multiplayer
This commit is contained in:
parent
c576c4e241
commit
7f94094de9
|
|
@ -1,30 +0,0 @@
|
|||
const urls = new Set();
|
||||
|
||||
function checkURL(request, init) {
|
||||
const url =
|
||||
request instanceof URL
|
||||
? request
|
||||
: new URL(
|
||||
(typeof request === "string"
|
||||
? new Request(request, init)
|
||||
: request
|
||||
).url
|
||||
);
|
||||
if (url.port && url.port !== "443" && url.protocol === "https:") {
|
||||
if (!urls.has(url.toString())) {
|
||||
urls.add(url.toString());
|
||||
console.warn(
|
||||
`WARNING: known issue with \`fetch()\` requests to custom HTTPS ports in published Workers:\n` +
|
||||
` - ${url.toString()} - the custom port will be ignored when the Worker is published using the \`wrangler deploy\` command.\n`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
globalThis.fetch = new Proxy(globalThis.fetch, {
|
||||
apply(target, thisArg, argArray) {
|
||||
const [request, init] = argArray;
|
||||
checkURL(request, init);
|
||||
return Reflect.apply(target, thisArg, argArray);
|
||||
},
|
||||
});
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import worker, * as OTHER_EXPORTS from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\worker\\worker.ts";
|
||||
import * as __MIDDLEWARE_0__ from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\node_modules\\wrangler\\templates\\middleware\\middleware-ensure-req-body-drained.ts";
|
||||
import * as __MIDDLEWARE_1__ from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\node_modules\\wrangler\\templates\\middleware\\middleware-miniflare3-json-error.ts";
|
||||
|
||||
export * from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\worker\\worker.ts";
|
||||
|
||||
export const __INTERNAL_WRANGLER_MIDDLEWARE__ = [
|
||||
|
||||
__MIDDLEWARE_0__.default,__MIDDLEWARE_1__.default
|
||||
]
|
||||
export default worker;
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
// This loads all middlewares exposed on the middleware object and then starts
|
||||
// the invocation chain. The big idea is that we can add these to the middleware
|
||||
// export dynamically through wrangler, or we can potentially let users directly
|
||||
// add them as a sort of "plugin" system.
|
||||
|
||||
import ENTRY, { __INTERNAL_WRANGLER_MIDDLEWARE__ } from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\.wrangler\\tmp\\bundle-fO5AAb\\middleware-insertion-facade.js";
|
||||
import { __facade_invoke__, __facade_register__, Dispatcher } from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\node_modules\\wrangler\\templates\\middleware\\common.ts";
|
||||
import type { WorkerEntrypointConstructor } from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\.wrangler\\tmp\\bundle-fO5AAb\\middleware-insertion-facade.js";
|
||||
|
||||
// Preserve all the exports from the worker
|
||||
export * from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\.wrangler\\tmp\\bundle-fO5AAb\\middleware-insertion-facade.js";
|
||||
|
||||
class __Facade_ScheduledController__ implements ScheduledController {
|
||||
readonly #noRetry: ScheduledController["noRetry"];
|
||||
|
||||
constructor(
|
||||
readonly scheduledTime: number,
|
||||
readonly cron: string,
|
||||
noRetry: ScheduledController["noRetry"]
|
||||
) {
|
||||
this.#noRetry = noRetry;
|
||||
}
|
||||
|
||||
noRetry() {
|
||||
if (!(this instanceof __Facade_ScheduledController__)) {
|
||||
throw new TypeError("Illegal invocation");
|
||||
}
|
||||
// Need to call native method immediately in case uncaught error thrown
|
||||
this.#noRetry();
|
||||
}
|
||||
}
|
||||
|
||||
function wrapExportedHandler(worker: ExportedHandler): ExportedHandler {
|
||||
// If we don't have any middleware defined, just return the handler as is
|
||||
if (
|
||||
__INTERNAL_WRANGLER_MIDDLEWARE__ === undefined ||
|
||||
__INTERNAL_WRANGLER_MIDDLEWARE__.length === 0
|
||||
) {
|
||||
return worker;
|
||||
}
|
||||
// Otherwise, register all middleware once
|
||||
for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) {
|
||||
__facade_register__(middleware);
|
||||
}
|
||||
|
||||
const fetchDispatcher: ExportedHandlerFetchHandler = function (
|
||||
request,
|
||||
env,
|
||||
ctx
|
||||
) {
|
||||
if (worker.fetch === undefined) {
|
||||
throw new Error("Handler does not export a fetch() function.");
|
||||
}
|
||||
return worker.fetch(request, env, ctx);
|
||||
};
|
||||
|
||||
return {
|
||||
...worker,
|
||||
fetch(request, env, ctx) {
|
||||
const dispatcher: Dispatcher = function (type, init) {
|
||||
if (type === "scheduled" && worker.scheduled !== undefined) {
|
||||
const controller = new __Facade_ScheduledController__(
|
||||
Date.now(),
|
||||
init.cron ?? "",
|
||||
() => {}
|
||||
);
|
||||
return worker.scheduled(controller, env, ctx);
|
||||
}
|
||||
};
|
||||
return __facade_invoke__(request, env, ctx, dispatcher, fetchDispatcher);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function wrapWorkerEntrypoint(
|
||||
klass: WorkerEntrypointConstructor
|
||||
): WorkerEntrypointConstructor {
|
||||
// If we don't have any middleware defined, just return the handler as is
|
||||
if (
|
||||
__INTERNAL_WRANGLER_MIDDLEWARE__ === undefined ||
|
||||
__INTERNAL_WRANGLER_MIDDLEWARE__.length === 0
|
||||
) {
|
||||
return klass;
|
||||
}
|
||||
// Otherwise, register all middleware once
|
||||
for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) {
|
||||
__facade_register__(middleware);
|
||||
}
|
||||
|
||||
// `extend`ing `klass` here so other RPC methods remain callable
|
||||
return class extends klass {
|
||||
#fetchDispatcher: ExportedHandlerFetchHandler<Record<string, unknown>> = (
|
||||
request,
|
||||
env,
|
||||
ctx
|
||||
) => {
|
||||
this.env = env;
|
||||
this.ctx = ctx;
|
||||
if (super.fetch === undefined) {
|
||||
throw new Error("Entrypoint class does not define a fetch() function.");
|
||||
}
|
||||
return super.fetch(request);
|
||||
};
|
||||
|
||||
#dispatcher: Dispatcher = (type, init) => {
|
||||
if (type === "scheduled" && super.scheduled !== undefined) {
|
||||
const controller = new __Facade_ScheduledController__(
|
||||
Date.now(),
|
||||
init.cron ?? "",
|
||||
() => {}
|
||||
);
|
||||
return super.scheduled(controller);
|
||||
}
|
||||
};
|
||||
|
||||
fetch(request: Request<unknown, IncomingRequestCfProperties>) {
|
||||
return __facade_invoke__(
|
||||
request,
|
||||
this.env,
|
||||
this.ctx,
|
||||
this.#dispatcher,
|
||||
this.#fetchDispatcher
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let WRAPPED_ENTRY: ExportedHandler | WorkerEntrypointConstructor | undefined;
|
||||
if (typeof ENTRY === "object") {
|
||||
WRAPPED_ENTRY = wrapExportedHandler(ENTRY);
|
||||
} else if (typeof ENTRY === "function") {
|
||||
WRAPPED_ENTRY = wrapWorkerEntrypoint(ENTRY);
|
||||
}
|
||||
export default WRAPPED_ENTRY;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
|
@ -4,8 +4,8 @@
|
|||
"path": "."
|
||||
},
|
||||
{
|
||||
"name": "orionreed.com",
|
||||
"path": "../orionreed.com"
|
||||
"name": "jeffemmett.com",
|
||||
"path": "../jeffemmett.com"
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
|
|
|
|||
33
package.json
33
package.json
|
|
@ -17,40 +17,41 @@
|
|||
"dependencies": {
|
||||
"@dimforge/rapier2d": "^0.11.2",
|
||||
"@tldraw/sync": "^2.4.6",
|
||||
"@tldraw/sync-core": "latest",
|
||||
"@tldraw/tlschema": "latest",
|
||||
"@types/markdown-it": "^14.1.1",
|
||||
"@vercel/analytics": "^1.2.2",
|
||||
"cloudflare-workers-unfurl": "^0.0.7",
|
||||
"gray-matter": "^4.0.3",
|
||||
"itty-router": "^5.0.17",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"markdown-it": "^14.1.0",
|
||||
"markdown-it-latex2img": "^0.0.6",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"tldraw": "^2.4.6",
|
||||
"@cloudflare/types": "^6.29.0",
|
||||
"@tldraw/sync-core": "latest",
|
||||
"@tldraw/tlschema": "latest",
|
||||
"cloudflare-workers-unfurl": "^0.0.7",
|
||||
"itty-router": "^5.0.17",
|
||||
"lodash.throttle": "^4.1.1"
|
||||
"tldraw": "^2.4.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.4.1",
|
||||
"@cloudflare/types": "^6.29.0",
|
||||
"@cloudflare/workers-types": "^4.20240821.1",
|
||||
"@types/lodash.throttle": "^4",
|
||||
"@types/react": "^18.2.15",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
||||
"@typescript-eslint/parser": "^5.59.0",
|
||||
"@vitejs/plugin-react": "^4.0.3",
|
||||
"@vitejs/plugin-react-swc": "^3.6.0",
|
||||
"concurrently": "^8.2.2",
|
||||
"eslint": "^8.38.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.3.4",
|
||||
"typescript": "^5.0.2",
|
||||
"vite": "^5.3.3",
|
||||
"vite-plugin-static-copy": "^1.0.6",
|
||||
"vite-plugin-top-level-await": "^1.3.1",
|
||||
"vite-plugin-wasm": "^3.2.2",
|
||||
"wrangler": "^3.72.3",
|
||||
"@types/lodash.throttle": "^4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
||||
"@typescript-eslint/parser": "^5.59.0",
|
||||
"@vitejs/plugin-react-swc": "^3.6.0",
|
||||
"concurrently": "^8.2.2",
|
||||
"eslint": "^8.38.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.3.4"
|
||||
"wrangler": "^3.72.3"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ async function unfurlBookmarkUrl({ url }: { url: string }): Promise<TLBookmarkAs
|
|||
|
||||
try {
|
||||
const response = await fetch(`${WORKER_URL}/unfurl?url=${encodeURIComponent(url)}`)
|
||||
const data = await response.json()
|
||||
const data = await response.json() as { description: string, image: string, favicon: string, title: string }
|
||||
|
||||
asset.props.description = data?.description ?? ''
|
||||
asset.props.image = data?.image ?? ''
|
||||
|
|
|
|||
|
|
@ -22,9 +22,8 @@ export function Canvas({ shapes }: { shapes: TLShape[]; }) {
|
|||
<Tldraw
|
||||
components={components}
|
||||
shapeUtils={[HTMLShapeUtil]}
|
||||
onMount={(editor: Editor) => {
|
||||
onMount={(_: Editor) => {
|
||||
window.dispatchEvent(new CustomEvent('editorDidMountEvent'));
|
||||
editor.user.updateUserPreferences({ isDarkMode: false })
|
||||
}}
|
||||
>
|
||||
<SimController shapes={shapes} />
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export function Inbox() {
|
|||
const response = await fetch('https://jeffemmett-canvas.web.val.run', {
|
||||
method: 'GET',
|
||||
});
|
||||
const messages = await response.json();
|
||||
const messages = await response.json() as { id: string, from: string, subject: string, text: string }[];
|
||||
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
const message = messages[i];
|
||||
|
|
|
|||
|
|
@ -2,15 +2,16 @@
|
|||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"lib": ["ES2020"],
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2022"],
|
||||
"module": "ES2022",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"types": ["@cloudflare/workers-types"],
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"target": "ES2022"
|
||||
},
|
||||
"include": ["worker"]
|
||||
"include": ["worker/*.ts"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ import { viteStaticCopy } from 'vite-plugin-static-copy';
|
|||
|
||||
export default defineConfig({
|
||||
define: {
|
||||
'process.env.TLDRAW_WORKER_URL':
|
||||
process.env.TLDRAW_WORKER_URL ?? '`http://${location.hostname}:5172`',
|
||||
'process.env.TLDRAW_WORKER_URL': JSON.stringify('https://jeffemmett-canvas.jeffemmett.workers.dev')
|
||||
},
|
||||
plugins: [
|
||||
react(),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
/// <reference types="@cloudflare/workers-types" />
|
||||
|
||||
import { RoomSnapshot, TLSocketRoom } from '@tldraw/sync-core'
|
||||
import {
|
||||
TLRecord,
|
||||
|
|
@ -69,6 +71,7 @@ export class TldrawDurableObject {
|
|||
|
||||
// Create the websocket pair for the client
|
||||
const { 0: clientWebSocket, 1: serverWebSocket } = new WebSocketPair()
|
||||
// @ts-ignore
|
||||
serverWebSocket.accept()
|
||||
|
||||
// load the room, or retrieve it if it's already loaded
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
/// <reference types="@cloudflare/workers-types" />
|
||||
|
||||
import { IRequest, error } from 'itty-router'
|
||||
import { Environment } from './types'
|
||||
|
||||
|
|
@ -36,6 +38,7 @@ export async function handleAssetDownload(
|
|||
|
||||
// if we have a cached response for this request (automatically handling ranges etc.), return it
|
||||
const cacheKey = new Request(request.url, { headers: request.headers })
|
||||
// @ts-ignore
|
||||
const cachedResponse = await caches.default.match(cacheKey)
|
||||
if (cachedResponse) {
|
||||
return cachedResponse
|
||||
|
|
@ -92,6 +95,7 @@ export async function handleAssetDownload(
|
|||
// we only cache complete (200) responses
|
||||
if (status === 200) {
|
||||
const [cacheBody, responseBody] = body!.tee()
|
||||
// @ts-ignore
|
||||
ctx.waitUntil(caches.default.put(cacheKey, new Response(cacheBody, { headers, status })))
|
||||
return new Response(responseBody, { headers, status })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// the contents of the environment should mostly be determined by wrangler.toml. These entries match
|
||||
// the bindings defined there.
|
||||
/// <reference types="@cloudflare/workers-types" />
|
||||
|
||||
export interface Environment {
|
||||
TLDRAW_BUCKET: R2Bucket
|
||||
TLDRAW_DURABLE_OBJECT: DurableObjectNamespace
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ export { TldrawDurableObject } from './TldrawDurableObject'
|
|||
// we use itty-router (https://itty.dev/) to handle routing. in this example we turn on CORS because
|
||||
// we're hosting the worker separately to the client. you should restrict this to your own domain.
|
||||
const { preflight, corsify } = cors({ origin: '*' })
|
||||
const router = AutoRouter<IRequest, [env: Environment, ctx: ExecutionContext]>({
|
||||
const router = AutoRouter<IRequest, [env: Environment]>({
|
||||
before: [preflight],
|
||||
finally: [corsify],
|
||||
catch: (e) => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue