@statewalker/cellb 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/bindings/html-rewriter.d.ts +7 -0
- package/dist/bindings/html-rewriter.js +4 -11
- package/dist/bindings/html-rewriter.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/project/browser-bundle.d.ts +3 -0
- package/dist/project/browser-bundle.js +2 -0
- package/dist/project/browser-bundle.js.map +1 -1
- package/dist/project/browser-host.js +2 -1
- package/dist/project/browser-host.js.map +1 -1
- package/dist/project/browser-shards.d.ts +2 -23
- package/dist/project/browser-shards.js +2 -8
- package/dist/project/browser-shards.js.map +1 -1
- package/dist/project/browser-tab-protocol.d.ts +30 -0
- package/dist/project/browser-tab-protocol.js +9 -0
- package/dist/project/browser-tab-protocol.js.map +1 -0
- package/dist/project/browser-tabs.js +1 -1
- package/dist/project/browser-tabs.js.map +1 -1
- package/dist/project/build.js +1 -0
- package/dist/project/build.js.map +1 -1
- package/dist/project/module-rules.d.ts +26 -0
- package/dist/project/module-rules.js +131 -0
- package/dist/project/module-rules.js.map +1 -0
- package/dist/project/node-load.js +2 -1
- package/dist/project/node-load.js.map +1 -1
- package/dist/project/node-project.d.ts +3 -0
- package/dist/project/node-project.js +5 -1
- package/dist/project/node-project.js.map +1 -1
- package/dist/project/wrangler.d.ts +27 -3
- package/dist/project/wrangler.js +45 -22
- package/dist/project/wrangler.js.map +1 -1
- package/dist/tabs.d.ts +1 -0
- package/dist/tabs.js +8 -0
- package/dist/tabs.js.map +1 -0
- package/package.json +5 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-tabs.js","sourceRoot":"","sources":["../../src/project/browser-tabs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * One project shared by every tab of an origin, its shards balanced over the tabs.\n *\n * ServiceWorker: installProjectRouter(self, { basePath: \"/app/\" })\n * each page: joinProjectShards({ name, shards, spawn, config, code, serviceWorker })\n * shard worker: serveProjectShard({ sqlite3 })\n *\n * Requests to `<basePath><name>/…` reach the project's Worker through the ServiceWorker, whichever\n * tab sent them (with their URL unchanged, unless `stripBase`); a Durable Object call runs in the\n * shard that owns the object, whichever tab holds that shard.\n *\n * Each tab holds a presence lock; every tab computes the same owner for each shard from the tabs\n * present (`shardOwner`: an even split, oldest tabs first), takes the shards it should own (one\n * Web Lock each) and gives up the others. A shard's OPFS pool belongs to the origin, so its cells\n * move with it from tab to tab. A shard given up is drained first (its requests in flight\n * finish, new ones wait for the next owner); a tab that closes runs no code, so the requests in\n * flight in its shards fail (ShardOwnerLostError) and the other tabs take the shards over.\n */\nimport {\n type DispatchFailure,\n type HandlerInfo,\n LinkLostError,\n SwHttpAdapter,\n SwHttpDispatcher,\n type WorkerLink,\n} from \"@statewalker/webrun-http-browser/sw\";\nimport { ShardOwnerLostError } from \"../router/cell-router.js\";\nimport { errorResponse } from \"../transport/cells-http.js\";\nimport { H } from \"../transport/cells-link.js\";\nimport { SW_SOCKET } from \"../ws/sw-connector.js\";\nimport { applyWorkerCookies, withPageCookies } from \"./browser-cookies.js\";\nimport type { BrowserBucket, BrowserProjectOptions } from \"./browser-host.js\";\nimport { INTERNAL_ORIGIN, TAB_INIT, type TabShardInit } from \"./browser-shards.js\";\n\n/** The ServiceWorker asks a project's tabs to attach their shards again (a host page's wait). */\nconst NEED_LINKS = \"cellb:need-links\";\n/** A page opens a socket (`serviceWorkerConnector`). */\nconst SOCKET = SW_SOCKET;\n\n/**\n * The tab that should run `shard`: the tabs sorted by id (ids start with the time the tab joined),\n * shard i to tab i mod n — every tab runs ⌊shards/n⌋ or ⌈shards/n⌉ shards. A tab joining or\n * leaving moves the shards whose owner index changes; the oldest tabs keep theirs first.\n */\nexport function shardOwner(shard: number, tabs: string[]): string | undefined {\n if (!tabs.length) return undefined;\n const sorted = [...tabs].sort();\n return sorted[shard % sorted.length];\n}\n\nexport interface ProjectTabsOptions {\n /** The project's name in this origin: its URL path, locks and OPFS pools derive from it. */\n name: string;\n shards: number;\n /** Starts the worker of one shard; its script calls `serveProjectShard`. */\n spawn: (shard: number) => Worker;\n config: BrowserProjectOptions[\"config\"];\n code: BrowserProjectOptions[\"code\"];\n assetFiles?: BrowserProjectOptions[\"assetFiles\"];\n /** The OpenAI-compatible endpoint behind the project's `ai` binding. */\n ai?: BrowserProjectOptions[\"ai\"];\n /** Each shard is its own fleet node, `<node>-s<shard>`. */\n bucket?: BrowserBucket;\n /**\n * The active ServiceWorker that runs `installProjectRouter`. This page must be inside its scope\n * and controlled by it (webrun-http-browser's adapter asks the worker to claim the page if it\n * is not, and rejects with a `ServiceWorkerControlError` after 30 s if that fails: after a hard\n * reload, say).\n */\n serviceWorker: () => Promise<ServiceWorker>;\n /** Called whenever the shards this tab runs change. */\n onChange?: (owned: number[]) => void;\n /** How often the tab checks who is present (tabs that crash release their locks silently). */\n checkMs?: number;\n /**\n * A shard handed to another tab first lets its requests in flight finish, for up to this long\n * (default 5 s); new ones wait for the next owner.\n */\n drainMs?: number;\n}\n\nexport interface ProjectTabs {\n /** The shards this tab runs now. */\n owned(): number[];\n /** Ids of the tabs present (this one included). */\n tabs(): Promise<string[]>;\n /** Gives up every shard (closing its runtime first) and leaves. */\n close(): Promise<void>;\n}\n\ninterface Held {\n /** Aborts the wait for the lock, or ends the hold once running. */\n stop: AbortController;\n worker?: Worker;\n running?: Promise<void>;\n}\n\n/** A shard's handler id under the project's key: the router's `route` picks shards by it. */\nconst shardId = (shard: number) => `shard:${shard}`;\n\n/** The page side: this tab takes part in running the project's shards. */\nexport async function joinProjectShards(opts: ProjectTabsOptions): Promise<ProjectTabs> {\n const prefix = `cellb:${opts.name}`;\n const tabId = `${Date.now().toString(36).padStart(9, \"0\")}-${crypto.randomUUID()}`;\n const presenceLock = `${prefix}:tab:${tabId}`;\n let leave!: () => void;\n await new Promise<void>((held) => {\n void navigator.locks.request(presenceLock, () => {\n held();\n return new Promise<void>((r) => (leave = r));\n });\n });\n const channel = new BroadcastChannel(`${prefix}:tabs`);\n const held = new Map<number, Held>();\n const running = new Set<number>();\n let closed = false;\n\n const tabs = async (): Promise<string[]> => {\n const { held: locks = [] } = await navigator.locks.query();\n const ids = locks\n .map((l) => l.name ?? \"\")\n .filter((n) => n.startsWith(`${prefix}:tab:`))\n .map((n) => n.slice(`${prefix}:tab:`.length));\n return ids.includes(tabId) ? ids : [...ids, tabId];\n };\n\n const ask = (w: Worker, data: unknown, ports: MessagePort[] = []) =>\n new Promise<{\n ok: boolean;\n error?: string;\n unsupported?: string[];\n }>((resolve) => {\n const { port1, port2 } = new MessageChannel();\n port1.onmessage = (e) => {\n port1.close();\n resolve(e.data);\n };\n w.postMessage(data, [port2, ...ports]);\n });\n\n // The tab's side of the ServiceWorker's router (webrun-http-browser): it attaches this tab's\n // shard workers under the project's key, and attaches them again whenever the ServiceWorker\n // asks (after a restart). The page itself attaches no handler the router would pick.\n const worker = await opts.serviceWorker();\n // The given worker's registration, not `navigator.serviceWorker.ready` (that is this page's\n // scope's registration, and never settles for a page outside every scope).\n const registration = (await navigator.serviceWorker.getRegistrations()).find((r) =>\n [r.active, r.waiting, r.installing].includes(worker),\n );\n if (!registration)\n throw new Error(`cellb: no registration holds the ServiceWorker ${worker.scriptURL}`);\n const adapter = new SwHttpAdapter({\n key: opts.name,\n registration,\n id: `tab:${tabId}`,\n });\n await adapter.start();\n const links = new Map<number, WorkerLink>();\n\n const changed = () => opts.onChange?.([...running].sort((a, b) => a - b));\n\n /** Waits for the shard's lock, then runs its worker until `stop` is aborted. */\n const take = (shard: number) => {\n const h: Held = { stop: new AbortController() };\n held.set(shard, h);\n h.running = navigator.locks\n .request(`${prefix}:shard:${shard}`, { signal: h.stop.signal }, async () => {\n const w = opts.spawn(shard);\n h.worker = w;\n try {\n const started = await ask(w, {\n type: TAB_INIT,\n name: opts.name,\n shard,\n shards: opts.shards,\n config: opts.config,\n code: opts.code,\n assetFiles: opts.assetFiles,\n ai: opts.ai,\n bucket: opts.bucket && { ...opts.bucket, node: `${opts.bucket.node}-s${shard}` },\n pool: `${opts.name}-shard-${shard}`,\n filesDir: `${opts.name}-files-${shard}`,\n } satisfies TabShardInit);\n if (!started.ok) throw new Error(started.error);\n // What the configuration asks for and this runtime does not provide (a cron trigger\n // without a scheduled() handler, say): said once, not silently ignored.\n if (started.unsupported?.length)\n console.warn(\n `cellb: project ${opts.name} shard ${shard}: unsupported: ${started.unsupported.join(\"; \")}`,\n );\n if (!h.stop.signal.aborted) {\n links.set(\n shard,\n await adapter.attachWorker(w, {\n key: opts.name,\n id: shardId(shard),\n meta: { shard },\n }),\n );\n running.add(shard);\n changed();\n await new Promise<void>((r) =>\n h.stop.signal.aborted ? r() : h.stop.signal.addEventListener(\"abort\", () => r()),\n );\n }\n } finally {\n // A planned hand-over drains the shard's requests in flight first; then the runtime\n // closes (and the pool with it) before the lock goes to the next tab.\n const link = links.get(shard);\n links.delete(shard);\n if (link && running.has(shard))\n await link.drain({ ms: opts.drainMs ?? 5_000 }).catch(() => {});\n running.delete(shard);\n await ask(w, { type: \"cellb:shard-close\" }).catch(() => {});\n w.terminate();\n changed();\n }\n })\n .catch((err) => {\n // Aborted while waiting is expected; a shard that failed to start is reported.\n if (!h.stop.signal.aborted)\n console.error(\n `cellb: ${opts.name} shard ${shard} failed: ${(err as Error)?.message ?? err}`,\n );\n })\n .finally(() => {\n if (held.get(shard) === h) held.delete(shard);\n });\n };\n\n let balancing: Promise<void> | undefined;\n let again = false;\n /** Takes the shards this tab should own and gives up the others. */\n const balance = async () => {\n if (balancing) {\n again = true;\n return balancing;\n }\n balancing = (async () => {\n do {\n again = false;\n if (closed) return;\n const present = await tabs();\n // close() may have run while `tabs()` was answering: take nothing after it.\n if (closed) return;\n for (let shard = 0; shard < opts.shards; shard++) {\n const mine = shardOwner(shard, present) === tabId;\n const h = held.get(shard);\n if (mine && !h) take(shard);\n else if (!mine && h) h.stop.abort();\n }\n } while (again);\n })().finally(() => (balancing = undefined));\n return balancing;\n };\n\n channel.onmessage = () => void balance();\n const timer = setInterval(() => void balance(), opts.checkMs ?? 1000);\n const onSw = (e: MessageEvent) => {\n if (e.data?.type !== NEED_LINKS || (e.data.name && e.data.name !== opts.name)) return;\n void adapter.relink().catch(() => {});\n };\n navigator.serviceWorker.addEventListener(\"message\", onSw);\n channel.postMessage({ joined: tabId });\n await balance();\n\n return {\n owned: () => [...running].sort((a, b) => a - b),\n tabs,\n async close() {\n closed = true;\n clearInterval(timer);\n navigator.serviceWorker.removeEventListener(\"message\", onSw);\n const stopping = [...held.values()];\n for (const h of stopping) h.stop.abort();\n await Promise.all(stopping.map((h) => h.running));\n await adapter.stop().catch(() => {});\n leave();\n channel.postMessage({ left: tabId });\n channel.close();\n },\n };\n}\n\n/**\n * A ServiceWorker's global scope (its `self`), as `installProjectRouter` takes it: typed without\n * TypeScript's WebWorker lib, so that code importing cellb compiles with the DOM lib alone.\n */\nexport interface ServiceWorkerScope {\n readonly location: { readonly origin: string };\n readonly clients: unknown;\n addEventListener(type: string, listener: (event: never) => unknown): void;\n}\n\n/**\n * The ServiceWorker side: webrun-http-browser's dispatcher, with the project as its key and the\n * tabs' shard workers as its handlers. What cellb adds: its urls (`<basePath><name>/`, a root\n * project, `http://cellb.internal/<name>/` for calls between shards), which shard a call goes to,\n * the page's cookies, no control headers from pages, and the host page.\n */\nexport function installProjectRouter(\n scope: ServiceWorkerScope,\n opts: {\n /** Requests to `<basePath><name>/…` go to project `name`. */\n basePath: string;\n /**\n * The Worker sees the request's URL as the page sent it (default), as a Worker on a\n * Cloudflare route does: mount its routes under `<basePath><name>/`. With `stripBase`, it\n * sees `/<rest>` instead — URLs it builds from the request then lack the prefix.\n */\n stripBase?: boolean;\n attachTimeoutMs?: number;\n /**\n * A project served at the origin's root, for apps that build absolute paths (EmDash's\n * `/_emdash/…`, say) and so cannot live under `<basePath><n>/`. Every same-origin request\n * outside `basePath` and outside the `passthrough` path prefixes (the host page's own files)\n * goes to project `name` with its URL unchanged, navigations included.\n *\n * With `hostPage`, a navigation that finds no tab running the project's shards (after\n * `hostWaitMs`, default 2 s, for one to link) is redirected there, with the URL it asked\n * for as `?next=`: the page that starts the project, which a person reopening the site\n * would otherwise never reach, as every path of the origin belongs to the project.\n */\n root?: { name: string; passthrough?: string[]; hostPage?: string; hostWaitMs?: number };\n },\n): { dispatcher: SwHttpDispatcher } {\n const sw = scope as unknown as ServiceWorkerGlobalScope;\n const base = opts.basePath.endsWith(\"/\") ? opts.basePath : `${opts.basePath}/`;\n const internal = new URL(INTERNAL_ORIGIN);\n\n /** Whether `url` goes to the root project (`opts.root`). */\n const atRoot = (url: URL) =>\n !!opts.root &&\n url.origin === sw.location.origin &&\n !url.pathname.startsWith(base) &&\n !(opts.root.passthrough ?? []).some((p) => url.pathname.startsWith(p));\n\n /**\n * `<base><name>/<rest>` → the project's name, the Worker's path `/<rest>`, and `<base><name>` as\n * the URL spells it (`prefix`: what `stripBase` cuts, so a name the URL leaves unescaped, `a@b`,\n * or escapes where it need not, `%61pp`, is cut as written).\n */\n const split = (url: URL): { name: string; path: string; prefix: string } | undefined => {\n if (opts.root && atRoot(url)) return { name: opts.root.name, path: url.pathname, prefix: \"\" };\n if (url.origin !== sw.location.origin || !url.pathname.startsWith(base)) return undefined;\n const rest = url.pathname.slice(base.length);\n const slash = rest.indexOf(\"/\");\n const raw = slash < 0 ? rest : rest.slice(0, slash);\n const name = decodeURIComponent(raw);\n return name\n ? { name, path: slash < 0 ? \"/\" : rest.slice(slash), prefix: `${base}${raw}` }\n : undefined;\n };\n\n const isShard = (h: HandlerInfo) => typeof (h.meta as { shard?: unknown })?.shard === \"number\";\n let rr = 0;\n const dispatcher = new SwHttpDispatcher({\n self: sw,\n handleFetch: false,\n attachTimeoutMs: opts.attachTimeoutMs ?? 15_000,\n key: (url) => {\n // Calls between shards: http://cellb.internal/<name>/.\n if (url.host === internal.host) {\n const name = url.pathname.split(\"/\")[1];\n return name ? decodeURIComponent(name) : undefined;\n }\n return split(url)?.name;\n },\n // A call between shards names its shard (it waits for that one); the rest go to the shard\n // with the fewest requests in flight, round robin among equals. The tabs' pages are handlers\n // of the key too (their adapters'), with nothing to serve: never picked.\n route: (request, _key, handlers) => {\n const shards = handlers.filter(isShard);\n const named = request.headers.get(H.shard);\n if (named !== null)\n return shards.find((h) => (h.meta as { shard: number }).shard === Number(named));\n if (!shards.length) return undefined;\n const start = rr++ % shards.length;\n let best = shards[start];\n for (let i = 1; i < shards.length; i++) {\n const h = shards[(start + i) % shards.length];\n if (h.inflight < best.inflight) best = h;\n }\n return best;\n },\n // A call between shards fails as an error its caller rethrows (postVia); a page's request\n // gets a response it can read.\n failure: (request, failure) => failed(request, failure),\n // Pages may not address objects or shards directly: no control headers on their sockets.\n socketHeaders: (headers, from) =>\n from === \"page\"\n ? headers?.filter(([name]) => !name.toLowerCase().startsWith(\"x-cellb\"))\n : headers,\n });\n dispatcher.start();\n\n const failed = (request: Request, failure: DispatchFailure): Response => {\n const named = request.headers.get(H.shard);\n const what = named !== null ? `cell shard ${named}` : \"the project\";\n const error =\n failure.kind === \"lost\" && failure.error instanceof LinkLostError && named !== null\n ? new ShardOwnerLostError(Number(named))\n : failure.kind === \"timeout\"\n ? new Error(`${what} was not attached in time`)\n : failure.kind === \"gone\"\n ? new Error(`${what} has no tab running it`)\n : (failure.error as Error);\n if (request.headers.get(H.kind) !== null) return errorResponse(error, 503);\n return new Response(`cellb: ${(error as Error)?.message ?? error}`, { status: 503 });\n };\n\n const askForLinks = async (name: string) => {\n const clients = await sw.clients.matchAll({ type: \"window\", includeUncontrolled: true });\n for (const c of clients) c.postMessage({ type: NEED_LINKS, name });\n };\n\n /** Whether a tab runs project `name`'s shards, waiting up to `ms` for one to link. */\n const runningShards = async (name: string, ms: number): Promise<boolean> => {\n await dispatcher.ready;\n const live = () => dispatcher.table.live(name).some(isShard);\n if (live()) return true;\n void askForLinks(name);\n for (const until = Date.now() + ms; Date.now() < until; ) {\n await new Promise((r) => setTimeout(r, 100));\n if (live()) return true;\n }\n return false;\n };\n\n /** Headers for a request the router sends on: no control headers from the page, its base. */\n const routed = (req: Request, prefix: string, root: boolean): Headers => {\n // Headers only: a Request built from `req` would take its body.\n const headers = new Headers(req.headers);\n for (const h of Object.values(H)) if (h !== H.cookie) headers.delete(h);\n if (opts.stripBase && !root) headers.set(H.base, prefix);\n return headers;\n };\n\n /** A request to project `name`, with the page's cookies in and the Worker's out. */\n const serve = async (\n { name, prefix }: { name: string; prefix: string },\n req: Request,\n root: boolean,\n ): Promise<Response> => {\n try {\n // A project no tab has ever served is not the router's: the page's own request goes to the\n // network, as if there were no router (not the copy below, with the page's cookies in a\n // header and a streamed body).\n await dispatcher.ready;\n if (!dispatcher.serves(name)) return await fetch(req);\n const headers = await withPageCookies(\n sw,\n new Request(req.url, { headers: routed(req, prefix, root) }),\n );\n const res = await dispatcher.dispatch(\n new Request(req.url, {\n method: req.method,\n headers,\n body: req.body,\n signal: req.signal,\n duplex: \"half\",\n } as RequestInit),\n );\n return await applyWorkerCookies(sw, res);\n } catch (err) {\n // A response the page can read, instead of a network error with no cause.\n console.error(`cellb: ${req.method} ${new URL(req.url).pathname} failed:`, err);\n return new Response(`cellb: ${(err as Error)?.stack ?? err}`, { status: 502 });\n }\n };\n\n sw.addEventListener(\"fetch\", (e: FetchEvent) => {\n const req = e.request;\n const url = new URL(req.url);\n const root = atRoot(url);\n if (!root && req.mode === \"navigate\") return; // the pages under basePath are the host's\n const project = split(url);\n if (!project) return;\n const hostPage = root && req.mode === \"navigate\" ? opts.root?.hostPage : undefined;\n if (hostPage)\n e.respondWith(\n runningShards(project.name, opts.root?.hostWaitMs ?? 2_000).then((running) =>\n running\n ? serve(project, req, root)\n : Response.redirect(\n `${new URL(hostPage, url.origin).href}?next=${encodeURIComponent(`${url.pathname}${url.search}`)}`,\n 302,\n ),\n ),\n );\n else e.respondWith(serve(project, req, root));\n });\n\n // A page's socket (`serviceWorkerConnector`): routed as a fetch would be, without the page's\n // headers.\n sw.addEventListener(\"message\", (e: ExtendableMessageEvent) => {\n const m = e.data;\n if (m?.type !== SOCKET) return;\n const reply = e.ports[0];\n e.waitUntil(\n (async () => {\n try {\n const url = new URL(m.url);\n const httpUrl = new URL(url);\n if (httpUrl.protocol === \"ws:\") httpUrl.protocol = \"http:\";\n else if (httpUrl.protocol === \"wss:\") httpUrl.protocol = \"https:\";\n const project = split(httpUrl);\n if (!project) throw new Error(`not a project URL: ${m.url}`);\n const headers: [string, string][] = [];\n if (opts.stripBase && !atRoot(httpUrl)) headers.push([H.base, project.prefix]);\n const { port, protocol } = await dispatcher.connectWebSocket(\n `${httpUrl}`,\n m.protocols ?? [],\n headers,\n );\n reply.postMessage({ ok: true, port, protocol }, [port]);\n } catch (err) {\n reply.postMessage({ ok: false, error: String((err as Error)?.message ?? err) });\n }\n })(),\n );\n });\n\n return { dispatcher };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"browser-tabs.js","sourceRoot":"","sources":["../../src/project/browser-tabs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * One project shared by every tab of an origin, its shards balanced over the tabs.\n *\n * ServiceWorker: installProjectRouter(self, { basePath: \"/app/\" })\n * each page: joinProjectShards({ name, shards, spawn, config, code, serviceWorker })\n * shard worker: serveProjectShard({ sqlite3 })\n *\n * Requests to `<basePath><name>/…` reach the project's Worker through the ServiceWorker, whichever\n * tab sent them (with their URL unchanged, unless `stripBase`); a Durable Object call runs in the\n * shard that owns the object, whichever tab holds that shard.\n *\n * Each tab holds a presence lock; every tab computes the same owner for each shard from the tabs\n * present (`shardOwner`: an even split, oldest tabs first), takes the shards it should own (one\n * Web Lock each) and gives up the others. A shard's OPFS pool belongs to the origin, so its cells\n * move with it from tab to tab. A shard given up is drained first (its requests in flight\n * finish, new ones wait for the next owner); a tab that closes runs no code, so the requests in\n * flight in its shards fail (ShardOwnerLostError) and the other tabs take the shards over.\n */\nimport {\n type DispatchFailure,\n type HandlerInfo,\n LinkLostError,\n SwHttpAdapter,\n SwHttpDispatcher,\n type WorkerLink,\n} from \"@statewalker/webrun-http-browser/sw\";\nimport { ShardOwnerLostError } from \"../router/cell-router.js\";\nimport { errorResponse } from \"../transport/cells-http.js\";\nimport { H } from \"../transport/cells-link.js\";\nimport { SW_SOCKET } from \"../ws/sw-connector.js\";\nimport { applyWorkerCookies, withPageCookies } from \"./browser-cookies.js\";\nimport type { BrowserBucket, BrowserProjectOptions } from \"./browser-host.js\";\nimport { INTERNAL_ORIGIN, TAB_INIT, type TabShardInit } from \"./browser-tab-protocol.js\";\n\n/** The ServiceWorker asks a project's tabs to attach their shards again (a host page's wait). */\nconst NEED_LINKS = \"cellb:need-links\";\n/** A page opens a socket (`serviceWorkerConnector`). */\nconst SOCKET = SW_SOCKET;\n\n/**\n * The tab that should run `shard`: the tabs sorted by id (ids start with the time the tab joined),\n * shard i to tab i mod n — every tab runs ⌊shards/n⌋ or ⌈shards/n⌉ shards. A tab joining or\n * leaving moves the shards whose owner index changes; the oldest tabs keep theirs first.\n */\nexport function shardOwner(shard: number, tabs: string[]): string | undefined {\n if (!tabs.length) return undefined;\n const sorted = [...tabs].sort();\n return sorted[shard % sorted.length];\n}\n\nexport interface ProjectTabsOptions {\n /** The project's name in this origin: its URL path, locks and OPFS pools derive from it. */\n name: string;\n shards: number;\n /** Starts the worker of one shard; its script calls `serveProjectShard`. */\n spawn: (shard: number) => Worker;\n config: BrowserProjectOptions[\"config\"];\n code: BrowserProjectOptions[\"code\"];\n assetFiles?: BrowserProjectOptions[\"assetFiles\"];\n /** The OpenAI-compatible endpoint behind the project's `ai` binding. */\n ai?: BrowserProjectOptions[\"ai\"];\n /** Each shard is its own fleet node, `<node>-s<shard>`. */\n bucket?: BrowserBucket;\n /**\n * The active ServiceWorker that runs `installProjectRouter`. This page must be inside its scope\n * and controlled by it (webrun-http-browser's adapter asks the worker to claim the page if it\n * is not, and rejects with a `ServiceWorkerControlError` after 30 s if that fails: after a hard\n * reload, say).\n */\n serviceWorker: () => Promise<ServiceWorker>;\n /** Called whenever the shards this tab runs change. */\n onChange?: (owned: number[]) => void;\n /** How often the tab checks who is present (tabs that crash release their locks silently). */\n checkMs?: number;\n /**\n * A shard handed to another tab first lets its requests in flight finish, for up to this long\n * (default 5 s); new ones wait for the next owner.\n */\n drainMs?: number;\n}\n\nexport interface ProjectTabs {\n /** The shards this tab runs now. */\n owned(): number[];\n /** Ids of the tabs present (this one included). */\n tabs(): Promise<string[]>;\n /** Gives up every shard (closing its runtime first) and leaves. */\n close(): Promise<void>;\n}\n\ninterface Held {\n /** Aborts the wait for the lock, or ends the hold once running. */\n stop: AbortController;\n worker?: Worker;\n running?: Promise<void>;\n}\n\n/** A shard's handler id under the project's key: the router's `route` picks shards by it. */\nconst shardId = (shard: number) => `shard:${shard}`;\n\n/** The page side: this tab takes part in running the project's shards. */\nexport async function joinProjectShards(opts: ProjectTabsOptions): Promise<ProjectTabs> {\n const prefix = `cellb:${opts.name}`;\n const tabId = `${Date.now().toString(36).padStart(9, \"0\")}-${crypto.randomUUID()}`;\n const presenceLock = `${prefix}:tab:${tabId}`;\n let leave!: () => void;\n await new Promise<void>((held) => {\n void navigator.locks.request(presenceLock, () => {\n held();\n return new Promise<void>((r) => (leave = r));\n });\n });\n const channel = new BroadcastChannel(`${prefix}:tabs`);\n const held = new Map<number, Held>();\n const running = new Set<number>();\n let closed = false;\n\n const tabs = async (): Promise<string[]> => {\n const { held: locks = [] } = await navigator.locks.query();\n const ids = locks\n .map((l) => l.name ?? \"\")\n .filter((n) => n.startsWith(`${prefix}:tab:`))\n .map((n) => n.slice(`${prefix}:tab:`.length));\n return ids.includes(tabId) ? ids : [...ids, tabId];\n };\n\n const ask = (w: Worker, data: unknown, ports: MessagePort[] = []) =>\n new Promise<{\n ok: boolean;\n error?: string;\n unsupported?: string[];\n }>((resolve) => {\n const { port1, port2 } = new MessageChannel();\n port1.onmessage = (e) => {\n port1.close();\n resolve(e.data);\n };\n w.postMessage(data, [port2, ...ports]);\n });\n\n // The tab's side of the ServiceWorker's router (webrun-http-browser): it attaches this tab's\n // shard workers under the project's key, and attaches them again whenever the ServiceWorker\n // asks (after a restart). The page itself attaches no handler the router would pick.\n const worker = await opts.serviceWorker();\n // The given worker's registration, not `navigator.serviceWorker.ready` (that is this page's\n // scope's registration, and never settles for a page outside every scope).\n const registration = (await navigator.serviceWorker.getRegistrations()).find((r) =>\n [r.active, r.waiting, r.installing].includes(worker),\n );\n if (!registration)\n throw new Error(`cellb: no registration holds the ServiceWorker ${worker.scriptURL}`);\n const adapter = new SwHttpAdapter({\n key: opts.name,\n registration,\n id: `tab:${tabId}`,\n });\n await adapter.start();\n const links = new Map<number, WorkerLink>();\n\n const changed = () => opts.onChange?.([...running].sort((a, b) => a - b));\n\n /** Waits for the shard's lock, then runs its worker until `stop` is aborted. */\n const take = (shard: number) => {\n const h: Held = { stop: new AbortController() };\n held.set(shard, h);\n h.running = navigator.locks\n .request(`${prefix}:shard:${shard}`, { signal: h.stop.signal }, async () => {\n const w = opts.spawn(shard);\n h.worker = w;\n try {\n const started = await ask(w, {\n type: TAB_INIT,\n name: opts.name,\n shard,\n shards: opts.shards,\n config: opts.config,\n code: opts.code,\n assetFiles: opts.assetFiles,\n ai: opts.ai,\n bucket: opts.bucket && { ...opts.bucket, node: `${opts.bucket.node}-s${shard}` },\n pool: `${opts.name}-shard-${shard}`,\n filesDir: `${opts.name}-files-${shard}`,\n } satisfies TabShardInit);\n if (!started.ok) throw new Error(started.error);\n // What the configuration asks for and this runtime does not provide (a cron trigger\n // without a scheduled() handler, say): said once, not silently ignored.\n if (started.unsupported?.length)\n console.warn(\n `cellb: project ${opts.name} shard ${shard}: unsupported: ${started.unsupported.join(\"; \")}`,\n );\n if (!h.stop.signal.aborted) {\n links.set(\n shard,\n await adapter.attachWorker(w, {\n key: opts.name,\n id: shardId(shard),\n meta: { shard },\n }),\n );\n running.add(shard);\n changed();\n await new Promise<void>((r) =>\n h.stop.signal.aborted ? r() : h.stop.signal.addEventListener(\"abort\", () => r()),\n );\n }\n } finally {\n // A planned hand-over drains the shard's requests in flight first; then the runtime\n // closes (and the pool with it) before the lock goes to the next tab.\n const link = links.get(shard);\n links.delete(shard);\n if (link && running.has(shard))\n await link.drain({ ms: opts.drainMs ?? 5_000 }).catch(() => {});\n running.delete(shard);\n await ask(w, { type: \"cellb:shard-close\" }).catch(() => {});\n w.terminate();\n changed();\n }\n })\n .catch((err) => {\n // Aborted while waiting is expected; a shard that failed to start is reported.\n if (!h.stop.signal.aborted)\n console.error(\n `cellb: ${opts.name} shard ${shard} failed: ${(err as Error)?.message ?? err}`,\n );\n })\n .finally(() => {\n if (held.get(shard) === h) held.delete(shard);\n });\n };\n\n let balancing: Promise<void> | undefined;\n let again = false;\n /** Takes the shards this tab should own and gives up the others. */\n const balance = async () => {\n if (balancing) {\n again = true;\n return balancing;\n }\n balancing = (async () => {\n do {\n again = false;\n if (closed) return;\n const present = await tabs();\n // close() may have run while `tabs()` was answering: take nothing after it.\n if (closed) return;\n for (let shard = 0; shard < opts.shards; shard++) {\n const mine = shardOwner(shard, present) === tabId;\n const h = held.get(shard);\n if (mine && !h) take(shard);\n else if (!mine && h) h.stop.abort();\n }\n } while (again);\n })().finally(() => (balancing = undefined));\n return balancing;\n };\n\n channel.onmessage = () => void balance();\n const timer = setInterval(() => void balance(), opts.checkMs ?? 1000);\n const onSw = (e: MessageEvent) => {\n if (e.data?.type !== NEED_LINKS || (e.data.name && e.data.name !== opts.name)) return;\n void adapter.relink().catch(() => {});\n };\n navigator.serviceWorker.addEventListener(\"message\", onSw);\n channel.postMessage({ joined: tabId });\n await balance();\n\n return {\n owned: () => [...running].sort((a, b) => a - b),\n tabs,\n async close() {\n closed = true;\n clearInterval(timer);\n navigator.serviceWorker.removeEventListener(\"message\", onSw);\n const stopping = [...held.values()];\n for (const h of stopping) h.stop.abort();\n await Promise.all(stopping.map((h) => h.running));\n await adapter.stop().catch(() => {});\n leave();\n channel.postMessage({ left: tabId });\n channel.close();\n },\n };\n}\n\n/**\n * A ServiceWorker's global scope (its `self`), as `installProjectRouter` takes it: typed without\n * TypeScript's WebWorker lib, so that code importing cellb compiles with the DOM lib alone.\n */\nexport interface ServiceWorkerScope {\n readonly location: { readonly origin: string };\n readonly clients: unknown;\n addEventListener(type: string, listener: (event: never) => unknown): void;\n}\n\n/**\n * The ServiceWorker side: webrun-http-browser's dispatcher, with the project as its key and the\n * tabs' shard workers as its handlers. What cellb adds: its urls (`<basePath><name>/`, a root\n * project, `http://cellb.internal/<name>/` for calls between shards), which shard a call goes to,\n * the page's cookies, no control headers from pages, and the host page.\n */\nexport function installProjectRouter(\n scope: ServiceWorkerScope,\n opts: {\n /** Requests to `<basePath><name>/…` go to project `name`. */\n basePath: string;\n /**\n * The Worker sees the request's URL as the page sent it (default), as a Worker on a\n * Cloudflare route does: mount its routes under `<basePath><name>/`. With `stripBase`, it\n * sees `/<rest>` instead — URLs it builds from the request then lack the prefix.\n */\n stripBase?: boolean;\n attachTimeoutMs?: number;\n /**\n * A project served at the origin's root, for apps that build absolute paths (EmDash's\n * `/_emdash/…`, say) and so cannot live under `<basePath><n>/`. Every same-origin request\n * outside `basePath` and outside the `passthrough` path prefixes (the host page's own files)\n * goes to project `name` with its URL unchanged, navigations included.\n *\n * With `hostPage`, a navigation that finds no tab running the project's shards (after\n * `hostWaitMs`, default 2 s, for one to link) is redirected there, with the URL it asked\n * for as `?next=`: the page that starts the project, which a person reopening the site\n * would otherwise never reach, as every path of the origin belongs to the project.\n */\n root?: { name: string; passthrough?: string[]; hostPage?: string; hostWaitMs?: number };\n },\n): { dispatcher: SwHttpDispatcher } {\n const sw = scope as unknown as ServiceWorkerGlobalScope;\n const base = opts.basePath.endsWith(\"/\") ? opts.basePath : `${opts.basePath}/`;\n const internal = new URL(INTERNAL_ORIGIN);\n\n /** Whether `url` goes to the root project (`opts.root`). */\n const atRoot = (url: URL) =>\n !!opts.root &&\n url.origin === sw.location.origin &&\n !url.pathname.startsWith(base) &&\n !(opts.root.passthrough ?? []).some((p) => url.pathname.startsWith(p));\n\n /**\n * `<base><name>/<rest>` → the project's name, the Worker's path `/<rest>`, and `<base><name>` as\n * the URL spells it (`prefix`: what `stripBase` cuts, so a name the URL leaves unescaped, `a@b`,\n * or escapes where it need not, `%61pp`, is cut as written).\n */\n const split = (url: URL): { name: string; path: string; prefix: string } | undefined => {\n if (opts.root && atRoot(url)) return { name: opts.root.name, path: url.pathname, prefix: \"\" };\n if (url.origin !== sw.location.origin || !url.pathname.startsWith(base)) return undefined;\n const rest = url.pathname.slice(base.length);\n const slash = rest.indexOf(\"/\");\n const raw = slash < 0 ? rest : rest.slice(0, slash);\n const name = decodeURIComponent(raw);\n return name\n ? { name, path: slash < 0 ? \"/\" : rest.slice(slash), prefix: `${base}${raw}` }\n : undefined;\n };\n\n const isShard = (h: HandlerInfo) => typeof (h.meta as { shard?: unknown })?.shard === \"number\";\n let rr = 0;\n const dispatcher = new SwHttpDispatcher({\n self: sw,\n handleFetch: false,\n attachTimeoutMs: opts.attachTimeoutMs ?? 15_000,\n key: (url) => {\n // Calls between shards: http://cellb.internal/<name>/.\n if (url.host === internal.host) {\n const name = url.pathname.split(\"/\")[1];\n return name ? decodeURIComponent(name) : undefined;\n }\n return split(url)?.name;\n },\n // A call between shards names its shard (it waits for that one); the rest go to the shard\n // with the fewest requests in flight, round robin among equals. The tabs' pages are handlers\n // of the key too (their adapters'), with nothing to serve: never picked.\n route: (request, _key, handlers) => {\n const shards = handlers.filter(isShard);\n const named = request.headers.get(H.shard);\n if (named !== null)\n return shards.find((h) => (h.meta as { shard: number }).shard === Number(named));\n if (!shards.length) return undefined;\n const start = rr++ % shards.length;\n let best = shards[start];\n for (let i = 1; i < shards.length; i++) {\n const h = shards[(start + i) % shards.length];\n if (h.inflight < best.inflight) best = h;\n }\n return best;\n },\n // A call between shards fails as an error its caller rethrows (postVia); a page's request\n // gets a response it can read.\n failure: (request, failure) => failed(request, failure),\n // Pages may not address objects or shards directly: no control headers on their sockets.\n socketHeaders: (headers, from) =>\n from === \"page\"\n ? headers?.filter(([name]) => !name.toLowerCase().startsWith(\"x-cellb\"))\n : headers,\n });\n dispatcher.start();\n\n const failed = (request: Request, failure: DispatchFailure): Response => {\n const named = request.headers.get(H.shard);\n const what = named !== null ? `cell shard ${named}` : \"the project\";\n const error =\n failure.kind === \"lost\" && failure.error instanceof LinkLostError && named !== null\n ? new ShardOwnerLostError(Number(named))\n : failure.kind === \"timeout\"\n ? new Error(`${what} was not attached in time`)\n : failure.kind === \"gone\"\n ? new Error(`${what} has no tab running it`)\n : (failure.error as Error);\n if (request.headers.get(H.kind) !== null) return errorResponse(error, 503);\n return new Response(`cellb: ${(error as Error)?.message ?? error}`, { status: 503 });\n };\n\n const askForLinks = async (name: string) => {\n const clients = await sw.clients.matchAll({ type: \"window\", includeUncontrolled: true });\n for (const c of clients) c.postMessage({ type: NEED_LINKS, name });\n };\n\n /** Whether a tab runs project `name`'s shards, waiting up to `ms` for one to link. */\n const runningShards = async (name: string, ms: number): Promise<boolean> => {\n await dispatcher.ready;\n const live = () => dispatcher.table.live(name).some(isShard);\n if (live()) return true;\n void askForLinks(name);\n for (const until = Date.now() + ms; Date.now() < until; ) {\n await new Promise((r) => setTimeout(r, 100));\n if (live()) return true;\n }\n return false;\n };\n\n /** Headers for a request the router sends on: no control headers from the page, its base. */\n const routed = (req: Request, prefix: string, root: boolean): Headers => {\n // Headers only: a Request built from `req` would take its body.\n const headers = new Headers(req.headers);\n for (const h of Object.values(H)) if (h !== H.cookie) headers.delete(h);\n if (opts.stripBase && !root) headers.set(H.base, prefix);\n return headers;\n };\n\n /** A request to project `name`, with the page's cookies in and the Worker's out. */\n const serve = async (\n { name, prefix }: { name: string; prefix: string },\n req: Request,\n root: boolean,\n ): Promise<Response> => {\n try {\n // A project no tab has ever served is not the router's: the page's own request goes to the\n // network, as if there were no router (not the copy below, with the page's cookies in a\n // header and a streamed body).\n await dispatcher.ready;\n if (!dispatcher.serves(name)) return await fetch(req);\n const headers = await withPageCookies(\n sw,\n new Request(req.url, { headers: routed(req, prefix, root) }),\n );\n const res = await dispatcher.dispatch(\n new Request(req.url, {\n method: req.method,\n headers,\n body: req.body,\n signal: req.signal,\n duplex: \"half\",\n } as RequestInit),\n );\n return await applyWorkerCookies(sw, res);\n } catch (err) {\n // A response the page can read, instead of a network error with no cause.\n console.error(`cellb: ${req.method} ${new URL(req.url).pathname} failed:`, err);\n return new Response(`cellb: ${(err as Error)?.stack ?? err}`, { status: 502 });\n }\n };\n\n sw.addEventListener(\"fetch\", (e: FetchEvent) => {\n const req = e.request;\n const url = new URL(req.url);\n const root = atRoot(url);\n if (!root && req.mode === \"navigate\") return; // the pages under basePath are the host's\n const project = split(url);\n if (!project) return;\n const hostPage = root && req.mode === \"navigate\" ? opts.root?.hostPage : undefined;\n if (hostPage)\n e.respondWith(\n runningShards(project.name, opts.root?.hostWaitMs ?? 2_000).then((running) =>\n running\n ? serve(project, req, root)\n : Response.redirect(\n `${new URL(hostPage, url.origin).href}?next=${encodeURIComponent(`${url.pathname}${url.search}`)}`,\n 302,\n ),\n ),\n );\n else e.respondWith(serve(project, req, root));\n });\n\n // A page's socket (`serviceWorkerConnector`): routed as a fetch would be, without the page's\n // headers.\n sw.addEventListener(\"message\", (e: ExtendableMessageEvent) => {\n const m = e.data;\n if (m?.type !== SOCKET) return;\n const reply = e.ports[0];\n e.waitUntil(\n (async () => {\n try {\n const url = new URL(m.url);\n const httpUrl = new URL(url);\n if (httpUrl.protocol === \"ws:\") httpUrl.protocol = \"http:\";\n else if (httpUrl.protocol === \"wss:\") httpUrl.protocol = \"https:\";\n const project = split(httpUrl);\n if (!project) throw new Error(`not a project URL: ${m.url}`);\n const headers: [string, string][] = [];\n if (opts.stripBase && !atRoot(httpUrl)) headers.push([H.base, project.prefix]);\n const { port, protocol } = await dispatcher.connectWebSocket(\n `${httpUrl}`,\n m.protocols ?? [],\n headers,\n );\n reply.postMessage({ ok: true, port, protocol }, [port]);\n } catch (err) {\n reply.postMessage({ ok: false, error: String((err as Error)?.message ?? err) });\n }\n })(),\n );\n });\n\n return { dispatcher };\n}\n"]}
|
package/dist/project/build.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/project/build.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EACL,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,YAAY,EAEZ,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAU9C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAW,EACX,MAAc,EACd,IAAI,GAAwB,EAAE;IAE9B,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACnB,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACzB,MAAM,MAAM,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM;QAChC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI;QACtB,CAAC,CAAC,MAAM,sBAAsB,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE;YACtD,UAAU;YACV,UAAU,EAAE,IAAI,CAAC,UAAU;
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/project/build.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `buildProject` (`cellb build`): the build step whose output folder `loadProject` loads, in a\n * browser or on Node. Imports no SQLite: the command stays quiet and light.\n */\nimport { mkdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { bundleWorkerForBrowser } from \"./browser-bundle.js\";\nimport {\n BUILD_FORMAT,\n BUILD_MANIFEST,\n BUILT_ASSETS,\n BUILT_WORKER,\n type BuildManifest,\n builtConfig,\n} from \"./built-project.js\";\nimport { readAssetDirectory, readWranglerConfig } from \"./node-project.js\";\nimport { hasNodeCompat } from \"./wrangler.js\";\n\nexport interface BuildProjectOptions {\n /**\n * Lower `await` to generators (default: with nodejs_compat), as `bundleWorkerForBrowser`;\n * `false` for browsers with TC39 AsyncContext only.\n */\n lowerAwait?: boolean;\n}\n\n/**\n * `cellb build`: writes the project in `dir` as a folder any static host serves and\n * `loadProject` (browser or Node) loads: `wrangler.json`, `worker.js` (`main` bundled for a\n * browser realm, with nodejs_compat when the flags ask for it), `assets/` and `cellb.json`.\n */\nexport async function buildProject(\n dir: string,\n outDir: string,\n opts: BuildProjectOptions = {},\n): Promise<BuildManifest> {\n dir = resolve(dir);\n outDir = resolve(outDir);\n const config = readWranglerConfig(dir);\n if (!config.main && !config.assets)\n throw new Error(\"wrangler config has neither `main` nor `assets`\");\n const nodeCompat = hasNodeCompat(config);\n const code = config.main\n ? await bundleWorkerForBrowser(resolve(dir, config.main), {\n nodeCompat,\n lowerAwait: opts.lowerAwait,\n rules: config.rules,\n })\n : null;\n const assets = config.assets?.directory\n ? readAssetDirectory(resolve(dir, config.assets.directory))\n : new Map<string, Uint8Array>();\n // A fresh folder: files of an earlier build must not linger as assets.\n for (const name of [BUILD_MANIFEST, \"wrangler.json\", BUILT_WORKER, BUILT_ASSETS])\n rmSync(join(outDir, name), { recursive: true, force: true });\n mkdirSync(outDir, { recursive: true });\n writeFileSync(join(outDir, \"wrangler.json\"), `${JSON.stringify(builtConfig(config), null, 2)}\\n`);\n if (code !== null) writeFileSync(join(outDir, BUILT_WORKER), code);\n for (const [path, bytes] of assets) {\n const out = join(outDir, BUILT_ASSETS, path);\n mkdirSync(dirname(out), { recursive: true });\n writeFileSync(out, bytes);\n }\n const manifest: BuildManifest = {\n format: BUILD_FORMAT,\n main: code !== null ? BUILT_WORKER : null,\n assets: [...assets.keys()].sort(),\n };\n // Written last: a folder with a manifest is a complete build.\n writeFileSync(join(outDir, BUILD_MANIFEST), `${JSON.stringify(manifest, null, 2)}\\n`);\n return manifest;\n}\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Plugin } from "esbuild";
|
|
2
|
+
/** A wrangler `rules` entry. */
|
|
3
|
+
export interface ModuleRule {
|
|
4
|
+
type: "ESModule" | "CommonJS" | "CompiledWasm" | "Data" | "Text" | (string & {});
|
|
5
|
+
globs: string[];
|
|
6
|
+
/** `true`: later rules of the same type (the defaults among them) apply too. */
|
|
7
|
+
fallthrough?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/** wrangler's (and workerd's) defaults, applied after a project's own rules. */
|
|
10
|
+
export declare const DEFAULT_MODULE_RULES: ModuleRule[];
|
|
11
|
+
/**
|
|
12
|
+
* A glob as an esbuild filter (Go regexp) on the import specifier, as wrangler matches it
|
|
13
|
+
* (glob-to-regexp with globstar): `**` spans any folders, `*` stays within one, the rest is literal.
|
|
14
|
+
*/
|
|
15
|
+
export declare function globFilter(glob: string): RegExp;
|
|
16
|
+
/**
|
|
17
|
+
* The rules in effect, as wrangler's `parseRules`: the project's, then the defaults. The first rule
|
|
18
|
+
* of a type without `fallthrough: true` closes the type: later rules of it are dropped (`ignored`
|
|
19
|
+
* names the project's own, unless the closing rule says `fallthrough: false`).
|
|
20
|
+
*/
|
|
21
|
+
export declare function effectiveRules(userRules?: ModuleRule[]): {
|
|
22
|
+
rules: ModuleRule[];
|
|
23
|
+
ignored: string[];
|
|
24
|
+
};
|
|
25
|
+
/** The esbuild plugin applying `rules` (with the defaults) to a bundle's imports. */
|
|
26
|
+
export declare function moduleRulesPlugin(userRules?: ModuleRule[]): Plugin;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wrangler's module `rules` for the esbuild bundles of a project's `main` (Node and `cellb build`):
|
|
3
|
+
* `CompiledWasm` (default export a `WebAssembly.Module`), `Data` (an `ArrayBuffer`) and `Text` (a
|
|
4
|
+
* string), matched on the import specifier by `globs`, as wrangler bundles. The bytes are inlined
|
|
5
|
+
* as base64 (about 1.33 times their size), so a bundle stays one self-contained module (a browser
|
|
6
|
+
* loads it by URL).
|
|
7
|
+
*/
|
|
8
|
+
import { readFileSync } from "node:fs";
|
|
9
|
+
/** wrangler's (and workerd's) defaults, applied after a project's own rules. */
|
|
10
|
+
export const DEFAULT_MODULE_RULES = [
|
|
11
|
+
{ type: "Text", globs: ["**/*.txt", "**/*.html", "**/*.sql"] },
|
|
12
|
+
{ type: "Data", globs: ["**/*.bin"] },
|
|
13
|
+
{ type: "CompiledWasm", globs: ["**/*.wasm", "**/*.wasm?module"] },
|
|
14
|
+
];
|
|
15
|
+
/** The rule types the bundles apply; ESModule and CommonJS are esbuild's own business. */
|
|
16
|
+
const TYPES = new Set(["CompiledWasm", "Data", "Text"]);
|
|
17
|
+
/**
|
|
18
|
+
* A glob as an esbuild filter (Go regexp) on the import specifier, as wrangler matches it
|
|
19
|
+
* (glob-to-regexp with globstar): `**` spans any folders, `*` stays within one, the rest is literal.
|
|
20
|
+
*/
|
|
21
|
+
export function globFilter(glob) {
|
|
22
|
+
let re = "";
|
|
23
|
+
for (let i = 0; i < glob.length; i++) {
|
|
24
|
+
const c = glob[i];
|
|
25
|
+
if (glob.startsWith("**/", i)) {
|
|
26
|
+
re += "(?:[^/]*/)*";
|
|
27
|
+
i += 2;
|
|
28
|
+
}
|
|
29
|
+
else if (glob.startsWith("**", i)) {
|
|
30
|
+
re += ".*";
|
|
31
|
+
i++;
|
|
32
|
+
}
|
|
33
|
+
else if (c === "*")
|
|
34
|
+
re += "[^/]*";
|
|
35
|
+
else
|
|
36
|
+
re += c.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
37
|
+
}
|
|
38
|
+
return new RegExp(`^${re}$`);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The rules in effect, as wrangler's `parseRules`: the project's, then the defaults. The first rule
|
|
42
|
+
* of a type without `fallthrough: true` closes the type: later rules of it are dropped (`ignored`
|
|
43
|
+
* names the project's own, unless the closing rule says `fallthrough: false`).
|
|
44
|
+
*/
|
|
45
|
+
export function effectiveRules(userRules = []) {
|
|
46
|
+
const all = [...userRules, ...DEFAULT_MODULE_RULES];
|
|
47
|
+
const closedAt = new Map();
|
|
48
|
+
const rules = [];
|
|
49
|
+
const ignored = [];
|
|
50
|
+
for (const [i, rule] of all.entries()) {
|
|
51
|
+
const at = closedAt.get(rule.type);
|
|
52
|
+
if (at !== undefined) {
|
|
53
|
+
if (i < userRules.length && all[at].fallthrough !== false)
|
|
54
|
+
ignored.push(`rules[${i}] (${rule.type}) is ignored: rules[${at}] has the same type and no \`fallthrough = true\``);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (rule.fallthrough !== true)
|
|
58
|
+
closedAt.set(rule.type, i);
|
|
59
|
+
rules.push(rule);
|
|
60
|
+
}
|
|
61
|
+
return { rules, ignored };
|
|
62
|
+
}
|
|
63
|
+
// Shared by every inlined file: base64 → bytes (Uint8Array.fromBase64 where the engine has it).
|
|
64
|
+
const DECODE = `export const bytes = (s) => {
|
|
65
|
+
if (typeof Uint8Array.fromBase64 === "function") return Uint8Array.fromBase64(s);
|
|
66
|
+
const t = atob(s);
|
|
67
|
+
const u = new Uint8Array(t.length);
|
|
68
|
+
for (let i = 0; i < t.length; i++) u[i] = t.charCodeAt(i);
|
|
69
|
+
return u;
|
|
70
|
+
};`;
|
|
71
|
+
/** The module a matched file becomes. */
|
|
72
|
+
function ruleModule(type, file) {
|
|
73
|
+
// A BOM stays part of the text, as wrangler uploads the file's bytes.
|
|
74
|
+
if (type === "Text")
|
|
75
|
+
return `export default ${JSON.stringify(new TextDecoder("utf-8", { ignoreBOM: true }).decode(file))};`;
|
|
76
|
+
const b64 = JSON.stringify(file.toString("base64"));
|
|
77
|
+
return [
|
|
78
|
+
'import { bytes } from "cellb-rule:decode";',
|
|
79
|
+
type === "CompiledWasm"
|
|
80
|
+
? // asynchronous: no engine limit on the size of a synchronous compile (Chromium's main thread)
|
|
81
|
+
`export default await WebAssembly.compile(bytes(${b64}));`
|
|
82
|
+
: `export default bytes(${b64}).buffer;`,
|
|
83
|
+
].join("\n");
|
|
84
|
+
}
|
|
85
|
+
/** The esbuild plugin applying `rules` (with the defaults) to a bundle's imports. */
|
|
86
|
+
export function moduleRulesPlugin(userRules) {
|
|
87
|
+
return {
|
|
88
|
+
name: "cellb-module-rules",
|
|
89
|
+
setup(b) {
|
|
90
|
+
const { rules, ignored } = effectiveRules(userRules);
|
|
91
|
+
for (const message of ignored)
|
|
92
|
+
console.warn(`[cellb] ${message}`);
|
|
93
|
+
for (const rule of rules) {
|
|
94
|
+
if (!TYPES.has(rule.type))
|
|
95
|
+
continue;
|
|
96
|
+
for (const glob of rule.globs)
|
|
97
|
+
b.onResolve({ filter: globFilter(glob) }, async (a) => {
|
|
98
|
+
// files on disk only: in-memory modules (Worker Loader code) bring `{ wasm }` entries
|
|
99
|
+
if (a.namespace !== "file" || a.pluginData?.cellbModuleRule)
|
|
100
|
+
return undefined;
|
|
101
|
+
// esbuild resolves the file (relative, or a package's through `exports`); the rule loads it
|
|
102
|
+
const r = await b.resolve(a.path.replace(/\?module$/, ""), {
|
|
103
|
+
kind: a.kind,
|
|
104
|
+
importer: a.importer,
|
|
105
|
+
resolveDir: a.resolveDir,
|
|
106
|
+
pluginData: { cellbModuleRule: true },
|
|
107
|
+
});
|
|
108
|
+
if (r.errors.length)
|
|
109
|
+
return { errors: r.errors };
|
|
110
|
+
// The type is part of the module's identity: one file reached by rules of two types
|
|
111
|
+
// is two modules.
|
|
112
|
+
return { path: r.path, namespace: `cellb-rule-${rule.type}` };
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
b.onResolve({ filter: /^cellb-rule:decode$/ }, () => ({
|
|
116
|
+
path: "decode",
|
|
117
|
+
namespace: "cellb-rule-decode",
|
|
118
|
+
}));
|
|
119
|
+
b.onLoad({ filter: /.*/, namespace: "cellb-rule-decode" }, () => ({
|
|
120
|
+
contents: DECODE,
|
|
121
|
+
loader: "js",
|
|
122
|
+
}));
|
|
123
|
+
for (const type of TYPES)
|
|
124
|
+
b.onLoad({ filter: /.*/, namespace: `cellb-rule-${type}` }, (a) => ({
|
|
125
|
+
contents: ruleModule(type, readFileSync(a.path)),
|
|
126
|
+
loader: "js",
|
|
127
|
+
}));
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=module-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-rules.js","sourceRoot":"","sources":["../../src/project/module-rules.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * wrangler's module `rules` for the esbuild bundles of a project's `main` (Node and `cellb build`):\n * `CompiledWasm` (default export a `WebAssembly.Module`), `Data` (an `ArrayBuffer`) and `Text` (a\n * string), matched on the import specifier by `globs`, as wrangler bundles. The bytes are inlined\n * as base64 (about 1.33 times their size), so a bundle stays one self-contained module (a browser\n * loads it by URL).\n */\nimport { readFileSync } from \"node:fs\";\nimport type { Plugin } from \"esbuild\";\n\n/** A wrangler `rules` entry. */\nexport interface ModuleRule {\n type: \"ESModule\" | \"CommonJS\" | \"CompiledWasm\" | \"Data\" | \"Text\" | (string & {});\n globs: string[];\n /** `true`: later rules of the same type (the defaults among them) apply too. */\n fallthrough?: boolean;\n}\n\n/** wrangler's (and workerd's) defaults, applied after a project's own rules. */\nexport const DEFAULT_MODULE_RULES: ModuleRule[] = [\n { type: \"Text\", globs: [\"**/*.txt\", \"**/*.html\", \"**/*.sql\"] },\n { type: \"Data\", globs: [\"**/*.bin\"] },\n { type: \"CompiledWasm\", globs: [\"**/*.wasm\", \"**/*.wasm?module\"] },\n];\n\n/** The rule types the bundles apply; ESModule and CommonJS are esbuild's own business. */\nconst TYPES = new Set([\"CompiledWasm\", \"Data\", \"Text\"]);\n\n/**\n * A glob as an esbuild filter (Go regexp) on the import specifier, as wrangler matches it\n * (glob-to-regexp with globstar): `**` spans any folders, `*` stays within one, the rest is literal.\n */\nexport function globFilter(glob: string): RegExp {\n let re = \"\";\n for (let i = 0; i < glob.length; i++) {\n const c = glob[i];\n if (glob.startsWith(\"**/\", i)) {\n re += \"(?:[^/]*/)*\";\n i += 2;\n } else if (glob.startsWith(\"**\", i)) {\n re += \".*\";\n i++;\n } else if (c === \"*\") re += \"[^/]*\";\n else re += c.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n }\n return new RegExp(`^${re}$`);\n}\n\n/**\n * The rules in effect, as wrangler's `parseRules`: the project's, then the defaults. The first rule\n * of a type without `fallthrough: true` closes the type: later rules of it are dropped (`ignored`\n * names the project's own, unless the closing rule says `fallthrough: false`).\n */\nexport function effectiveRules(userRules: ModuleRule[] = []): {\n rules: ModuleRule[];\n ignored: string[];\n} {\n const all = [...userRules, ...DEFAULT_MODULE_RULES];\n const closedAt = new Map<string, number>();\n const rules: ModuleRule[] = [];\n const ignored: string[] = [];\n for (const [i, rule] of all.entries()) {\n const at = closedAt.get(rule.type);\n if (at !== undefined) {\n if (i < userRules.length && all[at].fallthrough !== false)\n ignored.push(\n `rules[${i}] (${rule.type}) is ignored: rules[${at}] has the same type and no \\`fallthrough = true\\``,\n );\n continue;\n }\n if (rule.fallthrough !== true) closedAt.set(rule.type, i);\n rules.push(rule);\n }\n return { rules, ignored };\n}\n\n// Shared by every inlined file: base64 → bytes (Uint8Array.fromBase64 where the engine has it).\nconst DECODE = `export const bytes = (s) => {\n if (typeof Uint8Array.fromBase64 === \"function\") return Uint8Array.fromBase64(s);\n const t = atob(s);\n const u = new Uint8Array(t.length);\n for (let i = 0; i < t.length; i++) u[i] = t.charCodeAt(i);\n return u;\n};`;\n\n/** The module a matched file becomes. */\nfunction ruleModule(type: string, file: Buffer): string {\n // A BOM stays part of the text, as wrangler uploads the file's bytes.\n if (type === \"Text\")\n return `export default ${JSON.stringify(new TextDecoder(\"utf-8\", { ignoreBOM: true }).decode(file))};`;\n const b64 = JSON.stringify(file.toString(\"base64\"));\n return [\n 'import { bytes } from \"cellb-rule:decode\";',\n type === \"CompiledWasm\"\n ? // asynchronous: no engine limit on the size of a synchronous compile (Chromium's main thread)\n `export default await WebAssembly.compile(bytes(${b64}));`\n : `export default bytes(${b64}).buffer;`,\n ].join(\"\\n\");\n}\n\n/** The esbuild plugin applying `rules` (with the defaults) to a bundle's imports. */\nexport function moduleRulesPlugin(userRules?: ModuleRule[]): Plugin {\n return {\n name: \"cellb-module-rules\",\n setup(b) {\n const { rules, ignored } = effectiveRules(userRules);\n for (const message of ignored) console.warn(`[cellb] ${message}`);\n for (const rule of rules) {\n if (!TYPES.has(rule.type)) continue;\n for (const glob of rule.globs)\n b.onResolve({ filter: globFilter(glob) }, async (a) => {\n // files on disk only: in-memory modules (Worker Loader code) bring `{ wasm }` entries\n if (a.namespace !== \"file\" || a.pluginData?.cellbModuleRule) return undefined;\n // esbuild resolves the file (relative, or a package's through `exports`); the rule loads it\n const r = await b.resolve(a.path.replace(/\\?module$/, \"\"), {\n kind: a.kind,\n importer: a.importer,\n resolveDir: a.resolveDir,\n pluginData: { cellbModuleRule: true },\n });\n if (r.errors.length) return { errors: r.errors };\n // The type is part of the module's identity: one file reached by rules of two types\n // is two modules.\n return { path: r.path, namespace: `cellb-rule-${rule.type}` };\n });\n }\n b.onResolve({ filter: /^cellb-rule:decode$/ }, () => ({\n path: \"decode\",\n namespace: \"cellb-rule-decode\",\n }));\n b.onLoad({ filter: /.*/, namespace: \"cellb-rule-decode\" }, () => ({\n contents: DECODE,\n loader: \"js\",\n }));\n for (const type of TYPES)\n b.onLoad({ filter: /.*/, namespace: `cellb-rule-${type}` }, (a) => ({\n contents: ruleModule(type, readFileSync(a.path)),\n loader: \"js\",\n }));\n },\n };\n}\n"]}
|
|
@@ -14,7 +14,7 @@ import * as workersClasses from "./cloudflare-workers.js";
|
|
|
14
14
|
import { loadNodeProject, nodeIsolatedLoader, nodeModuleLoader } from "./node-project.js";
|
|
15
15
|
import { workerScope } from "./worker-scope.js";
|
|
16
16
|
import * as workersGlobals from "./workers-globals-module.js";
|
|
17
|
-
import { createProjectRuntime, loadTimeEnv, populatesProcessEnv, processEnvOf, } from "./wrangler.js";
|
|
17
|
+
import { createProjectRuntime, loadProjectBindings, loadTimeEnv, populatesProcessEnv, processEnvOf, } from "./wrangler.js";
|
|
18
18
|
/**
|
|
19
19
|
* Loads a project and runs it in this process.
|
|
20
20
|
*
|
|
@@ -133,6 +133,7 @@ async function runBuilt(built, host) {
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
const project = createProjectRuntime(config, module, {
|
|
136
|
+
bindings: await loadProjectBindings(config),
|
|
136
137
|
loadModules: nodeModuleLoader,
|
|
137
138
|
isolatedModules: nodeIsolatedLoader(() => host.storage),
|
|
138
139
|
assetFiles: built.assets,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-load.js","sourceRoot":"","sources":["../../src/project/node-load.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClG,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAExD,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAG9D,OAAO,EACL,cAAc,EACd,YAAY,EAEZ,cAAc,EACd,UAAU,EAKV,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,GACV,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,cAAc,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1F,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,cAAc,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EACL,oBAAoB,EACpB,WAAW,EAEX,mBAAmB,EACnB,YAAY,GACb,MAAM,eAAe,CAAC;AAIvB;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAqB,EACrB,OAAO,GAA2B,EAAE;IAEpC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,KAAK,EAAE,OAAmC,EAAE,OAAoB,EAAE,EAAE;QAChF,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACtB,OAAO,EAAE,EAAE,CAAC;IACd,CAAC,CAAC;IACF,wCAAwC;IACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC,MAAM,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;QAC9E,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC1E,OAAO;YACL,MAAM;YACN,OAAO;YACP,WAAW;YACX,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC;YAClC,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC;SAC5B,CAAC;IACJ,CAAC;IACD,yFAAyF;IACzF,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC,MAAM,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;QAC9E,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAC1E,OAAO;gBACL,MAAM;gBACN,OAAO;gBACP,WAAW;gBACX,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC;gBAClC,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;aACjF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9C,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IACD,2BAA2B;IAC3B,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACjD,IAAI,CAAC,QAAQ;QACX,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,WAAW,cAAc,4CAA4C,CAAC,CAAC;IAC/F,OAAO,QAAQ,CAAC,MAAM,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;AAClE,CAAC;AAED,0FAA0F;AAC1F,SAAS,QAAQ,CAAC,OAA+B;IAC/C,IAAI,KAAe,CAAC;IACpB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACnC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,KAAK,GAAG,IAAI,YAAY,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IAC7D,CAAC;;QAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC;IACjC,OAAO;QACL,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3E,KAAK;QACL,OAAO,EAAE,OAAO,CAAC,MAAM;QACvB,EAAE,EAAE,OAAO,CAAC,EAAE;KACf,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,QAAQ,CACrB,KAAmB,EACnB,IAAsC;IAEtC,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IACzB,MAAM,KAAK,GAAG,MAAM,CAAC,mBAAmB,IAAI,EAAE,CAAC;IAC/C,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACxD,MAAM,CAAC,GAAG,UAAqC,CAAC;IAChD,CAAC,CAAC,oBAAoB,GAAG,cAAc,CAAC;IACxC,CAAC,CAAC,mBAAmB,GAAG,KAAK,CAAC;IAC9B,CAAC,CAAC,cAAc,GAAG;QACjB,GAAG,cAAc;QACjB,OAAO,EAAE,cAAc,CAAC,YAAY;QACpC,QAAQ,EAAE,cAAc,CAAC,aAAa;QACtC,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAC,gCAAgC,CAAC;YAC7D,CAAC,CAAC,cAAc,CAAC,qBAAqB;YACtC,CAAC,CAAC,cAAc,CAAC,aAAa;KACjC,CAAC;IACF,IAAI,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC,CAAC,iBAAiB,GAAG,GAAG,CAAC;QAC1B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,MAAM,GAAiB,EAAE,OAAO,EAAE,EAAE,EAAkB,CAAC;IAC3D,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;QACxD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QAC9D,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,kBAAkB,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAiB,CAAC;QACvF,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAG,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE;QACnD,WAAW,EAAE,gBAAgB;QAC7B,eAAe,EAAE,kBAAkB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;QACvD,UAAU,EAAE,KAAK,CAAC,MAAM;QACxB,GAAG,IAAI;KACR,CAAC,CAAC;IACH,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5B,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IACzC,OAAO;QACL,MAAM;QACN,OAAO;QACP,WAAW;QACX,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC;QAClC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE;KAC7B,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,SAAS,QAAQ,CAAC,MAAqB;IACrC,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,IAAI,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,OAAO,SAAS,CAAC;QACnD,OAAO,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,MAAM,YAAY,GAAG,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;IACvF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,SAAS,CAAC,MAAqB;IACtC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACpC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC;IACrD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW;IAC3B,OAAO;QACL,KAAK,CAAC,KAAK,CAAC,IAAI;YACd,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAC7B,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3E,CAAC;KACF,CAAC;AACJ,CAAC;AAED,qFAAqF;AACrF,KAAK,UAAU,OAAO,CAAC,KAAe;IACpC,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC5B,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,aAAa,CAAC,GAAG,EAAE,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAe,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["/**\n * `loadProject` on Node (`@statewalker/cellb/node`): one call that reads a project, built or\n * not, and runs it.\n */\nimport { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport type { FilesApi } from \"@statewalker/webrun-files\";\nimport { MemFilesApi } from \"@statewalker/webrun-files-mem\";\nimport { NodeFilesApi } from \"@statewalker/webrun-files-node\";\nimport { nodeSqliteOpener } from \"../adapters/node-sqlite.js\";\nimport type { WorkerModule } from \"../core/runtime.js\";\nimport type { CellStorage } from \"../ports.js\";\nimport {\n BUILD_MANIFEST,\n BUILT_WORKER,\n type BuiltProject,\n filesApiReader,\n isFilesApi,\n type LoadedProject,\n type LoadProjectOptions,\n type ProjectReader,\n type ProjectSource,\n readBuildManifest,\n readBuiltProject,\n urlReader,\n} from \"./built-project.js\";\nimport * as workersClasses from \"./cloudflare-workers.js\";\nimport { loadNodeProject, nodeIsolatedLoader, nodeModuleLoader } from \"./node-project.js\";\nimport { workerScope } from \"./worker-scope.js\";\nimport * as workersGlobals from \"./workers-globals-module.js\";\nimport {\n createProjectRuntime,\n loadTimeEnv,\n type ProjectHost,\n populatesProcessEnv,\n processEnvOf,\n} from \"./wrangler.js\";\n\nexport type NodeLoadProjectOptions = LoadProjectOptions<CellStorage>;\n\n/**\n * Loads a project and runs it in this process.\n *\n * `source`: a folder with `wrangler.json(c)` (its `main` bundled with esbuild, as\n * `loadNodeProject` does), a folder written by `cellb build` (its `worker.js` imported as built),\n * an `http(s):` URL of a built folder, or a FilesApi holding either kind of folder.\n *\n * `options.data`: a directory for the cells' SQLite files and the project's files\n * (`<data>/files`); without it, both are in memory.\n */\nexport async function loadProject(\n source: ProjectSource,\n options: NodeLoadProjectOptions = {},\n): Promise<LoadedProject> {\n const host = nodeHost(options);\n const close = async (runtime: { close(): Promise<void> }, cleanup?: () => void) => {\n await runtime.close();\n cleanup?.();\n };\n // A folder on disk: read where it lies.\n const dir = localDir(source);\n if (dir !== undefined) {\n const reader = fsReader(dir);\n const manifest = await readBuildManifest(reader);\n if (manifest) return runBuilt(await readBuiltProject(reader, manifest), host);\n const { runtime, unsupported, config } = await loadNodeProject(dir, host);\n return {\n config,\n runtime,\n unsupported,\n fetch: (req) => runtime.fetch(req),\n close: () => close(runtime),\n };\n }\n // A FilesApi: a built folder is read from it; a source folder is copied out for esbuild.\n if (isFilesApi(source)) {\n const reader = filesApiReader(source);\n const manifest = await readBuildManifest(reader);\n if (manifest) return runBuilt(await readBuiltProject(reader, manifest), host);\n const tmp = await copyOut(source);\n try {\n const { runtime, unsupported, config } = await loadNodeProject(tmp, host);\n return {\n config,\n runtime,\n unsupported,\n fetch: (req) => runtime.fetch(req),\n close: () => close(runtime, () => rmSync(tmp, { recursive: true, force: true })),\n };\n } catch (err) {\n rmSync(tmp, { recursive: true, force: true });\n throw err;\n }\n }\n // A URL of a built folder.\n const url = folderUrl(source);\n const reader = urlReader(url);\n const manifest = await readBuildManifest(reader);\n if (!manifest)\n throw new Error(`${url} has no ${BUILD_MANIFEST}: load a folder written by \\`cellb build\\``);\n return runBuilt(await readBuiltProject(reader, manifest), host);\n}\n\n/** What `options` become on Node: SQLite files and a FilesApi under `data`, or memory. */\nfunction nodeHost(options: NodeLoadProjectOptions): Omit<ProjectHost, \"loadModules\"> {\n let files: FilesApi;\n if (options.data) {\n const data = resolve(options.data);\n mkdirSync(join(data, \"files\"), { recursive: true });\n files = new NodeFilesApi({ rootDir: join(data, \"files\") });\n } else files = new MemFilesApi();\n return {\n openSql: nodeSqliteOpener(options.data ? resolve(options.data) : undefined),\n files,\n storage: options.bucket,\n ai: options.ai,\n };\n}\n\n/**\n * Runs a built project on Node: `worker.js` was bundled for a browser realm, so it reads the\n * Workers globals and `cloudflare:workers` from the globals this sets, as in a browser worker.\n * (One such project per process: the globals are the process's.)\n */\nasync function runBuilt(\n built: BuiltProject,\n host: Omit<ProjectHost, \"loadModules\">,\n): Promise<LoadedProject> {\n const { config } = built;\n const flags = config.compatibility_flags ?? [];\n const scope = workerScope(loadTimeEnv(config, host.ai));\n const g = globalThis as Record<string, unknown>;\n g.__cellsWorkersModule = workersClasses;\n g.__cellsProjectScope = scope;\n g.__cellsGlobals = {\n ...workersGlobals,\n Request: workersGlobals.CellsRequest,\n Response: workersGlobals.CellsResponse,\n WebSocketPair: flags.includes(\"websocket_standard_binary_type\")\n ? workersGlobals.StandardWebSocketPair\n : workersGlobals.WebSocketPair,\n };\n if (populatesProcessEnv(config)) {\n const env = processEnvOf(config);\n g.__cellsProcessEnv = env;\n for (const [k, v] of Object.entries(env)) process.env[k] ??= v;\n }\n let module: WorkerModule = { default: {} } as WorkerModule;\n if (built.code !== null) {\n const tmp = mkdtempSync(join(tmpdir(), \"cellb-built-\"));\n const file = join(tmp, BUILT_WORKER.replace(/\\.js$/, \".mjs\"));\n writeFileSync(file, built.code);\n try {\n module = (await import(/* @vite-ignore */ pathToFileURL(file).href)) as WorkerModule;\n } finally {\n rmSync(tmp, { recursive: true, force: true });\n }\n }\n const project = createProjectRuntime(config, module, {\n loadModules: nodeModuleLoader,\n isolatedModules: nodeIsolatedLoader(() => host.storage),\n assetFiles: built.assets,\n ...host,\n });\n scope.bind(project.runtime);\n const { runtime, unsupported } = project;\n return {\n config,\n runtime,\n unsupported,\n fetch: (req) => runtime.fetch(req),\n close: () => runtime.close(),\n };\n}\n\n/** The folder a source names on this machine: a path or a `file:` URL. */\nfunction localDir(source: ProjectSource): string | undefined {\n if (typeof source === \"string\") {\n if (/^https?:\\/\\//i.test(source)) return undefined;\n return resolve(source.startsWith(\"file:\") ? fileURLToPath(source) : source);\n }\n if (source instanceof URL && source.protocol === \"file:\") return fileURLToPath(source);\n return undefined;\n}\n\nfunction folderUrl(source: ProjectSource): URL {\n const url = new URL(String(source));\n if (!url.pathname.endsWith(\"/\")) url.pathname += \"/\";\n return url;\n}\n\nfunction fsReader(dir: string): ProjectReader {\n return {\n async bytes(path) {\n const full = join(dir, path);\n return existsSync(full) ? new Uint8Array(readFileSync(full)) : undefined;\n },\n };\n}\n\n/** Copies a FilesApi's files into a temporary folder (esbuild bundles from disk). */\nasync function copyOut(files: FilesApi): Promise<string> {\n const tmp = mkdtempSync(join(tmpdir(), \"cellb-project-\"));\n const reader = filesApiReader(files);\n for (const path of (await reader.list?.(\"/\")) ?? []) {\n const out = join(tmp, path);\n mkdirSync(dirname(out), { recursive: true });\n writeFileSync(out, (await reader.bytes(path)) as Uint8Array);\n }\n return tmp;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"node-load.js","sourceRoot":"","sources":["../../src/project/node-load.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `loadProject` on Node (`@statewalker/cellb/node`): one call that reads a project, built or\n * not, and runs it.\n */\nimport { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport type { FilesApi } from \"@statewalker/webrun-files\";\nimport { MemFilesApi } from \"@statewalker/webrun-files-mem\";\nimport { NodeFilesApi } from \"@statewalker/webrun-files-node\";\nimport { nodeSqliteOpener } from \"../adapters/node-sqlite.js\";\nimport type { WorkerModule } from \"../core/runtime.js\";\nimport type { CellStorage } from \"../ports.js\";\nimport {\n BUILD_MANIFEST,\n BUILT_WORKER,\n type BuiltProject,\n filesApiReader,\n isFilesApi,\n type LoadedProject,\n type LoadProjectOptions,\n type ProjectReader,\n type ProjectSource,\n readBuildManifest,\n readBuiltProject,\n urlReader,\n} from \"./built-project.js\";\nimport * as workersClasses from \"./cloudflare-workers.js\";\nimport { loadNodeProject, nodeIsolatedLoader, nodeModuleLoader } from \"./node-project.js\";\nimport { workerScope } from \"./worker-scope.js\";\nimport * as workersGlobals from \"./workers-globals-module.js\";\nimport {\n createProjectRuntime,\n loadProjectBindings,\n loadTimeEnv,\n type ProjectHost,\n populatesProcessEnv,\n processEnvOf,\n} from \"./wrangler.js\";\n\nexport type NodeLoadProjectOptions = LoadProjectOptions<CellStorage>;\n\n/**\n * Loads a project and runs it in this process.\n *\n * `source`: a folder with `wrangler.json(c)` (its `main` bundled with esbuild, as\n * `loadNodeProject` does), a folder written by `cellb build` (its `worker.js` imported as built),\n * an `http(s):` URL of a built folder, or a FilesApi holding either kind of folder.\n *\n * `options.data`: a directory for the cells' SQLite files and the project's files\n * (`<data>/files`); without it, both are in memory.\n */\nexport async function loadProject(\n source: ProjectSource,\n options: NodeLoadProjectOptions = {},\n): Promise<LoadedProject> {\n const host = nodeHost(options);\n const close = async (runtime: { close(): Promise<void> }, cleanup?: () => void) => {\n await runtime.close();\n cleanup?.();\n };\n // A folder on disk: read where it lies.\n const dir = localDir(source);\n if (dir !== undefined) {\n const reader = fsReader(dir);\n const manifest = await readBuildManifest(reader);\n if (manifest) return runBuilt(await readBuiltProject(reader, manifest), host);\n const { runtime, unsupported, config } = await loadNodeProject(dir, host);\n return {\n config,\n runtime,\n unsupported,\n fetch: (req) => runtime.fetch(req),\n close: () => close(runtime),\n };\n }\n // A FilesApi: a built folder is read from it; a source folder is copied out for esbuild.\n if (isFilesApi(source)) {\n const reader = filesApiReader(source);\n const manifest = await readBuildManifest(reader);\n if (manifest) return runBuilt(await readBuiltProject(reader, manifest), host);\n const tmp = await copyOut(source);\n try {\n const { runtime, unsupported, config } = await loadNodeProject(tmp, host);\n return {\n config,\n runtime,\n unsupported,\n fetch: (req) => runtime.fetch(req),\n close: () => close(runtime, () => rmSync(tmp, { recursive: true, force: true })),\n };\n } catch (err) {\n rmSync(tmp, { recursive: true, force: true });\n throw err;\n }\n }\n // A URL of a built folder.\n const url = folderUrl(source);\n const reader = urlReader(url);\n const manifest = await readBuildManifest(reader);\n if (!manifest)\n throw new Error(`${url} has no ${BUILD_MANIFEST}: load a folder written by \\`cellb build\\``);\n return runBuilt(await readBuiltProject(reader, manifest), host);\n}\n\n/** What `options` become on Node: SQLite files and a FilesApi under `data`, or memory. */\nfunction nodeHost(options: NodeLoadProjectOptions): Omit<ProjectHost, \"loadModules\"> {\n let files: FilesApi;\n if (options.data) {\n const data = resolve(options.data);\n mkdirSync(join(data, \"files\"), { recursive: true });\n files = new NodeFilesApi({ rootDir: join(data, \"files\") });\n } else files = new MemFilesApi();\n return {\n openSql: nodeSqliteOpener(options.data ? resolve(options.data) : undefined),\n files,\n storage: options.bucket,\n ai: options.ai,\n };\n}\n\n/**\n * Runs a built project on Node: `worker.js` was bundled for a browser realm, so it reads the\n * Workers globals and `cloudflare:workers` from the globals this sets, as in a browser worker.\n * (One such project per process: the globals are the process's.)\n */\nasync function runBuilt(\n built: BuiltProject,\n host: Omit<ProjectHost, \"loadModules\">,\n): Promise<LoadedProject> {\n const { config } = built;\n const flags = config.compatibility_flags ?? [];\n const scope = workerScope(loadTimeEnv(config, host.ai));\n const g = globalThis as Record<string, unknown>;\n g.__cellsWorkersModule = workersClasses;\n g.__cellsProjectScope = scope;\n g.__cellsGlobals = {\n ...workersGlobals,\n Request: workersGlobals.CellsRequest,\n Response: workersGlobals.CellsResponse,\n WebSocketPair: flags.includes(\"websocket_standard_binary_type\")\n ? workersGlobals.StandardWebSocketPair\n : workersGlobals.WebSocketPair,\n };\n if (populatesProcessEnv(config)) {\n const env = processEnvOf(config);\n g.__cellsProcessEnv = env;\n for (const [k, v] of Object.entries(env)) process.env[k] ??= v;\n }\n let module: WorkerModule = { default: {} } as WorkerModule;\n if (built.code !== null) {\n const tmp = mkdtempSync(join(tmpdir(), \"cellb-built-\"));\n const file = join(tmp, BUILT_WORKER.replace(/\\.js$/, \".mjs\"));\n writeFileSync(file, built.code);\n try {\n module = (await import(/* @vite-ignore */ pathToFileURL(file).href)) as WorkerModule;\n } finally {\n rmSync(tmp, { recursive: true, force: true });\n }\n }\n const project = createProjectRuntime(config, module, {\n bindings: await loadProjectBindings(config),\n loadModules: nodeModuleLoader,\n isolatedModules: nodeIsolatedLoader(() => host.storage),\n assetFiles: built.assets,\n ...host,\n });\n scope.bind(project.runtime);\n const { runtime, unsupported } = project;\n return {\n config,\n runtime,\n unsupported,\n fetch: (req) => runtime.fetch(req),\n close: () => runtime.close(),\n };\n}\n\n/** The folder a source names on this machine: a path or a `file:` URL. */\nfunction localDir(source: ProjectSource): string | undefined {\n if (typeof source === \"string\") {\n if (/^https?:\\/\\//i.test(source)) return undefined;\n return resolve(source.startsWith(\"file:\") ? fileURLToPath(source) : source);\n }\n if (source instanceof URL && source.protocol === \"file:\") return fileURLToPath(source);\n return undefined;\n}\n\nfunction folderUrl(source: ProjectSource): URL {\n const url = new URL(String(source));\n if (!url.pathname.endsWith(\"/\")) url.pathname += \"/\";\n return url;\n}\n\nfunction fsReader(dir: string): ProjectReader {\n return {\n async bytes(path) {\n const full = join(dir, path);\n return existsSync(full) ? new Uint8Array(readFileSync(full)) : undefined;\n },\n };\n}\n\n/** Copies a FilesApi's files into a temporary folder (esbuild bundles from disk). */\nasync function copyOut(files: FilesApi): Promise<string> {\n const tmp = mkdtempSync(join(tmpdir(), \"cellb-project-\"));\n const reader = filesApiReader(files);\n for (const path of (await reader.list?.(\"/\")) ?? []) {\n const out = join(tmp, path);\n mkdirSync(dirname(out), { recursive: true });\n writeFileSync(out, (await reader.bytes(path)) as Uint8Array);\n }\n return tmp;\n}\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type LogSink, type ModuleLoader } from "../bindings/worker-loader.js";
|
|
2
2
|
import type { WorkerModule } from "../core/runtime.js";
|
|
3
3
|
import type { CellStorage } from "../ports.js";
|
|
4
|
+
import { type ModuleRule } from "./module-rules.js";
|
|
4
5
|
import { type WorkerScope } from "./worker-scope.js";
|
|
5
6
|
import { type ProjectHost, type ProjectRuntime, type WranglerConfig } from "./wrangler.js";
|
|
6
7
|
/** Reads `wrangler.jsonc` / `wrangler.json` of a project directory (celld reads the same files). */
|
|
@@ -20,6 +21,8 @@ export declare function bundleWorker(entry: {
|
|
|
20
21
|
nodeCompat?: boolean;
|
|
21
22
|
standardBinaryType?: boolean;
|
|
22
23
|
scope?: WorkerScope;
|
|
24
|
+
/** wrangler `rules` for non-JS imports (the defaults: `.wasm`, `.bin`, `.txt`…, as wrangler). */
|
|
25
|
+
rules?: ModuleRule[];
|
|
23
26
|
}): Promise<WorkerModule>;
|
|
24
27
|
/** Worker Loader on Node: compiles `WorkerCode.modules` with esbuild (as celld compiles loaded code). */
|
|
25
28
|
export declare const nodeModuleLoader: ModuleLoader;
|
|
@@ -10,9 +10,10 @@ import { ctxExports } from "../core/handles.js";
|
|
|
10
10
|
import { isolatedModuleLoader } from "../isolate/host.js";
|
|
11
11
|
import * as workersClasses from "./cloudflare-workers.js";
|
|
12
12
|
import { parseJsonc } from "./jsonc.js";
|
|
13
|
+
import { moduleRulesPlugin } from "./module-rules.js";
|
|
13
14
|
import { ownModule } from "./own-module.js";
|
|
14
15
|
import { workerScope } from "./worker-scope.js";
|
|
15
|
-
import { createProjectRuntime, hasNodeCompat, loadTimeEnv, WRANGLER_FILES, } from "./wrangler.js";
|
|
16
|
+
import { createProjectRuntime, hasNodeCompat, loadProjectBindings, loadTimeEnv, WRANGLER_FILES, } from "./wrangler.js";
|
|
16
17
|
/** Reads `wrangler.jsonc` / `wrangler.json` of a project directory (celld reads the same files). */
|
|
17
18
|
export function readWranglerConfig(dir) {
|
|
18
19
|
for (const name of WRANGLER_FILES) {
|
|
@@ -179,6 +180,7 @@ export async function bundleWorker(entry, logs, outbound, opts = {}) {
|
|
|
179
180
|
}));
|
|
180
181
|
},
|
|
181
182
|
},
|
|
183
|
+
moduleRulesPlugin(opts.rules),
|
|
182
184
|
],
|
|
183
185
|
});
|
|
184
186
|
return (await import(/* @vite-ignore */ out));
|
|
@@ -226,12 +228,14 @@ export async function loadNodeProject(dir, host) {
|
|
|
226
228
|
nodeCompat,
|
|
227
229
|
standardBinaryType,
|
|
228
230
|
scope,
|
|
231
|
+
rules: config.rules,
|
|
229
232
|
})
|
|
230
233
|
: { default: {} };
|
|
231
234
|
const assetFiles = config.assets?.directory
|
|
232
235
|
? readAssetDirectory(resolve(dir, config.assets.directory))
|
|
233
236
|
: undefined;
|
|
234
237
|
const project = createProjectRuntime(config, module, {
|
|
238
|
+
bindings: await loadProjectBindings(config),
|
|
235
239
|
loadModules: nodeModuleLoader,
|
|
236
240
|
// own realm, as celld; facets logged like the root's
|
|
237
241
|
isolatedModules: nodeIsolatedLoader(() => host.storage),
|