@statewalker/cellb 0.1.0 → 0.2.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 +45 -21
- package/dist/adapters/wasm-sqlite.d.ts +11 -0
- package/dist/adapters/wasm-sqlite.js +26 -3
- package/dist/adapters/wasm-sqlite.js.map +1 -1
- package/dist/bindings/assets.js +2 -2
- package/dist/bindings/assets.js.map +1 -1
- package/dist/bindings/r2.js +2 -2
- package/dist/bindings/r2.js.map +1 -1
- package/dist/browser.d.ts +0 -1
- package/dist/browser.js +0 -1
- package/dist/browser.js.map +1 -1
- package/dist/bucket/celld-cells.js +1 -1
- package/dist/bucket/celld-cells.js.map +1 -1
- package/dist/bucket/s3-object-store.js +1 -1
- package/dist/bucket/s3-object-store.js.map +1 -1
- package/dist/core/handles.d.ts +5 -2
- package/dist/core/handles.js +12 -1
- package/dist/core/handles.js.map +1 -1
- package/dist/core/id.js +3 -3
- package/dist/core/id.js.map +1 -1
- package/dist/core/namespace.d.ts +1 -1
- package/dist/core/namespace.js +2 -1
- package/dist/core/namespace.js.map +1 -1
- package/dist/core/object-host.d.ts +23 -0
- package/dist/core/object-host.js +87 -6
- package/dist/core/object-host.js.map +1 -1
- package/dist/core/runtime.d.ts +10 -0
- package/dist/core/runtime.js +43 -2
- package/dist/core/runtime.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/isolate/browser.js +1 -1
- package/dist/isolate/browser.js.map +1 -1
- package/dist/isolate/host.d.ts +5 -1
- package/dist/isolate/host.js +19 -3
- package/dist/isolate/host.js.map +1 -1
- package/dist/isolate/isolate-worker.js +11 -1
- package/dist/isolate/isolate-worker.js.map +1 -1
- package/dist/isolate/isolate.js +12 -0
- package/dist/isolate/isolate.js.map +1 -1
- package/dist/isolate/node-entry.js +11 -0
- package/dist/isolate/node-entry.js.map +1 -1
- package/dist/isolate/protocol.d.ts +4 -0
- package/dist/isolate/protocol.js +118 -2
- package/dist/isolate/protocol.js.map +1 -1
- package/dist/node-compat/crypto.js +3 -3
- package/dist/node-compat/crypto.js.map +1 -1
- package/dist/project/browser-host.js +3 -2
- package/dist/project/browser-host.js.map +1 -1
- package/dist/project/node-project.js +13 -1
- package/dist/project/node-project.js.map +1 -1
- package/dist/project/site-loader.d.ts +45 -0
- package/dist/project/site-loader.js +97 -0
- package/dist/project/site-loader.js.map +1 -0
- package/dist/project/site.d.ts +0 -36
- package/dist/project/site.js +11 -99
- package/dist/project/site.js.map +1 -1
- package/dist/project/wrangler.js +10 -0
- package/dist/project/wrangler.js.map +1 -1
- package/dist/router/cell-router.js +1 -1
- package/dist/router/cell-router.js.map +1 -1
- package/dist/site.d.ts +1 -0
- package/dist/site.js +6 -0
- package/dist/site.js.map +1 -0
- package/dist/ws/frames.d.ts +14 -0
- package/dist/ws/frames.js +51 -0
- package/dist/ws/frames.js.map +1 -1
- package/dist/ws/server.d.ts +4 -0
- package/dist/ws/server.js +17 -2
- package/dist/ws/server.js.map +1 -1
- package/package.json +25 -5
package/dist/core/runtime.js
CHANGED
|
@@ -8,7 +8,7 @@ import { asyncRoot } from "./async-context.js";
|
|
|
8
8
|
import { ctxExports, storedExports } from "./handles.js";
|
|
9
9
|
import { DurableObjectId, namespaceKey } from "./id.js";
|
|
10
10
|
import { DurableObjectNamespace, localEndpoint } from "./namespace.js";
|
|
11
|
-
import { CellOwnedElsewhereError, ObjectHost } from "./object-host.js";
|
|
11
|
+
import { CellOwnedElsewhereError, closingWith, ObjectClosedError, ObjectHost, } from "./object-host.js";
|
|
12
12
|
import { installRequestBody } from "./request-body.js";
|
|
13
13
|
import { rejectionScope, reportToStderr } from "./worker-rejections.js";
|
|
14
14
|
export function createCellRuntime(opts) {
|
|
@@ -120,12 +120,16 @@ export function createCellRuntime(opts) {
|
|
|
120
120
|
throw new Error(`Durable Object class "${className}" is not exported by the worker`);
|
|
121
121
|
const hostFor = (id) => {
|
|
122
122
|
const cellKey = `${className}/${id.toString()}`;
|
|
123
|
+
// Once close() has closed the cells, none opens again: its storage is closed or handed to
|
|
124
|
+
// the next runtime. Until then (the grace period), work in flight still reaches objects.
|
|
125
|
+
if (cellsClosed)
|
|
126
|
+
throw new ObjectClosedError(cellKey);
|
|
123
127
|
let h = hosts.get(cellKey);
|
|
124
128
|
if (!h || h.broken) {
|
|
125
129
|
h?.close();
|
|
126
130
|
h = new ObjectHost({
|
|
127
131
|
cellKey,
|
|
128
|
-
id,
|
|
132
|
+
id: opts.ctxIdOf?.(cellKey) ?? id,
|
|
129
133
|
cls,
|
|
130
134
|
env,
|
|
131
135
|
openSql: opts.openSql,
|
|
@@ -257,6 +261,10 @@ export function createCellRuntime(opts) {
|
|
|
257
261
|
const backupAll = (reason) => Promise.all([...hosts.values()].map((h) => h.backupIfDirty(reason, clock.now()))).then(() => { });
|
|
258
262
|
let timer;
|
|
259
263
|
let closed = false;
|
|
264
|
+
/** Set by close() after its grace period: no cell opens or takes an event any more. */
|
|
265
|
+
let cellsClosed = false;
|
|
266
|
+
/** Aborts when close() starts: the signal of the Worker's requests in flight. */
|
|
267
|
+
const closing = new AbortController();
|
|
260
268
|
const schedule = () => {
|
|
261
269
|
if (!backup || closed)
|
|
262
270
|
return;
|
|
@@ -310,6 +318,34 @@ export function createCellRuntime(opts) {
|
|
|
310
318
|
alarms.stop();
|
|
311
319
|
clock.clearTimeout(timer);
|
|
312
320
|
timer = undefined;
|
|
321
|
+
// Events in flight (a conversation's last writes, say) and waitUntil work finish first,
|
|
322
|
+
// within the grace period: their writes are then in the final backups too.
|
|
323
|
+
const grace = opts.closeGraceMs ?? 2_000;
|
|
324
|
+
// Requests in flight, the Worker's and its objects', see their signal abort.
|
|
325
|
+
closing.abort(new Error("the runtime is closing"));
|
|
326
|
+
for (const h of hosts.values())
|
|
327
|
+
h.shutdown();
|
|
328
|
+
// Work in flight may start more (a queue's delivery calls the consumer, which writes to
|
|
329
|
+
// another object): wait until nothing runs, nor started while waiting, or the grace ends.
|
|
330
|
+
const end = Date.now() + grace;
|
|
331
|
+
for (let left = grace; left > 0; left = end - Date.now()) {
|
|
332
|
+
const cells = hosts.size;
|
|
333
|
+
let t;
|
|
334
|
+
const idle = await Promise.race([
|
|
335
|
+
Promise.all([...[...hosts.values()].map((h) => h.settled()), ...[...background]]).then(() => true),
|
|
336
|
+
new Promise((r) => (t = setTimeout(() => r(false), left))),
|
|
337
|
+
]);
|
|
338
|
+
clearTimeout(t);
|
|
339
|
+
if (!idle)
|
|
340
|
+
break;
|
|
341
|
+
// One more turn: what finished may have queued more work.
|
|
342
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
343
|
+
if (hosts.size === cells &&
|
|
344
|
+
background.size === 0 &&
|
|
345
|
+
[...hosts.values()].every((h) => h.idle))
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
cellsClosed = true;
|
|
313
349
|
await backupAll("close");
|
|
314
350
|
// The releases reach the store before it closes.
|
|
315
351
|
await Promise.all([...hosts.values()].map((h) => h.close()));
|
|
@@ -321,6 +357,11 @@ export function createCellRuntime(opts) {
|
|
|
321
357
|
const handler = opts.worker.default?.fetch;
|
|
322
358
|
if (!handler)
|
|
323
359
|
return new Response("Worker has no fetch handler", { status: 500 });
|
|
360
|
+
// A closed runtime serves nothing: its cells are closed, or another runtime's now.
|
|
361
|
+
if (closed)
|
|
362
|
+
return new Response("cellb: the runtime is closed", { status: 503 });
|
|
363
|
+
// Its signal aborts when the runtime closes: a long poll or an SSE stream ends then.
|
|
364
|
+
req = closingWith(req, closing.signal);
|
|
324
365
|
const ctx = {
|
|
325
366
|
waitUntil,
|
|
326
367
|
passThroughOnException() { },
|
package/dist/core/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/core/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type CellDurability,\n type CellStorage,\n type Clock,\n type OpenCellSql,\n systemClock,\n type ValueCodec,\n} from \"../ports.js\";\nimport { httpEndpoint, postVia, type Send } from \"../transport/cells-link.js\";\nimport { v8Codec, v8CodecWith } from \"../v8/codec.js\";\nimport { type CfWebSocket, takeClientPort } from \"../ws/server.js\";\nimport { withUpgrade } from \"../ws/upgrade.js\";\nimport { type AlarmEntry, AlarmScheduler } from \"./alarms.js\";\nimport { type AsyncRoot, asyncRoot } from \"./async-context.js\";\nimport type { ExecutionContext } from \"./durable-object.js\";\nimport { ctxExports, type DurableObjectClass, storedExports } from \"./handles.js\";\nimport { DurableObjectId, namespaceKey } from \"./id.js\";\nimport { DurableObjectNamespace, localEndpoint, type ObjectEndpoint } from \"./namespace.js\";\nimport { CellOwnedElsewhereError, ObjectHost } from \"./object-host.js\";\nimport { installRequestBody } from \"./request-body.js\";\nimport { type RejectionHandler, rejectionScope, reportToStderr } from \"./worker-rejections.js\";\n\nexport interface WorkerModule {\n default: { fetch?(req: Request, env: any, ctx: ExecutionContext): Response | Promise<Response> };\n [exportName: string]: unknown;\n}\n\nexport interface CellRuntimeOptions {\n /**\n * A promise the Worker's code leaves rejected (Node: the Worker shares the host's process).\n * It is the Worker's, as on workerd and celld: it reaches this handler, not the process's\n * `unhandledRejection` listeners. Default: one line on stderr, outside the Worker's console.\n */\n onUnhandledRejection?: RejectionHandler;\n /** The Worker's module namespace (what wrangler/celld bundle as main module). */\n worker: WorkerModule;\n /** Durable Object bindings: env name → exported class name (wrangler `durable_objects.bindings`). */\n durableObjects?: Record<string, { className: string }>;\n /** Plain vars / other bindings merged into env. */\n vars?: Record<string, unknown>;\n openSql: OpenCellSql;\n /** Durability, backup and ownership of the cells; closed by `close()`, after the runtime. */\n storage?: CellStorage;\n codec?: ValueCodec;\n /**\n * Placement: return a `send` when the cell lives elsewhere (another shard\n * worker, tab or peer); `undefined` means \"host it here\". Default: all local.\n */\n route?: (cellKey: string, id: DurableObjectId) => Send | undefined;\n /** How often to re-read a shared alarm wake index (durability.wakes), in ms. Default 30 s. */\n wakePollMs?: number;\n /** Every object of this runtime is a facet of an outer cell (an isolate's runtime). */\n facets?: boolean;\n /** The Worker script's name (wrangler `name`): object ids derive from it, as on celld. */\n scriptName?: string;\n /** Namespace keys overriding the script-scoped default, per class (celld's fleet-wide ones). */\n namespaceKeys?: Record<string, string>;\n /**\n * Routing between nodes (celld's peer routing): when this node cannot own a cell\n * (`CellOwnedElsewhereError`), the call goes to the owner's node over an internal link\n * (`cellsHttpHandler` on the far side). `ownerOf` reads the cell's lease holder.\n */\n peers?: {\n ownerOf(cellKey: string): Promise<string | undefined>;\n link(owner: string): Send;\n /**\n * Talks to an owner directly, for owners that do not speak cellsHttpHandler (a celld node,\n * reached through celld's peer tunnel). Takes precedence over `link` when it returns one.\n */\n endpoint?(\n owner: string,\n cellKey: string,\n name: string | undefined,\n ): Promise<ObjectEndpoint | undefined>;\n };\n /** Hibernate objects idle this long (ms); swept every max(1 s, half of it). Off by default. */\n hibernateAfterMs?: number;\n /**\n * Close the SQLite database of a hibernated object idle this long (ms); the next event reopens\n * it. Swept with `hibernateAfterMs`, so it needs that too. Off by default: the database must\n * come back, so use local SQLite that persists (a directory, an OPFS pool) or storage that\n * restores the cell (a log or a backup).\n */\n closeDatabaseAfterMs?: number;\n /** SQLite extensions loaded into every cell database (celld's `sqlite_vec` flag). */\n sqlExtensions?: string[];\n /** `delete_all_preserves_alarm`: storage.deleteAll() keeps the alarm (default: deletes it). */\n deleteAllPreservesAlarm?: boolean;\n /** Timers of the runtime (backups); injectable for tests. */\n clock?: Clock;\n}\n\nexport interface CellRuntime {\n /** Ingress: a (Request) ⇒ Response handler — exactly what webrun-http-browser / node:http mount. */\n fetch(req: Request): Promise<Response>;\n readonly env: Record<string, unknown>;\n /** The Worker's `ctx.exports` (also `exports` of `cloudflare:workers`). */\n readonly exports: Record<string, unknown>;\n /**\n * Runs Worker code the host dispatches itself (a cron trigger's `scheduled()`) as the Worker's\n * event: a promise it leaves rejected goes to `onUnhandledRejection`, not to the process.\n */\n runEvent<R>(fn: () => R): R;\n /** Drops live instances (simulates eviction / hibernation); storage survives if openSql persists it. */\n evictAll(): void;\n /** Settles all waitUntil() promises. */\n drain(): Promise<void>;\n /**\n * Keeps `p` running in the background until `drain()` (what `waitUntil` of\n * `cloudflare:workers` does: on Cloudflare it extends the current event).\n */\n waitUntil(p: Promise<unknown>): void;\n /** Durable Object binding → class name (the namespace key used by idFromName). */\n readonly durableObjectBindings: Readonly<Record<string, string>>;\n /**\n * WebSocket ingress: runs the Worker's fetch with an Upgrade request; on a 101\n * with `webSocket`, returns the client end's MessagePort (to be transferred to\n * the real client, e.g. a page's CellsWebSocket).\n */\n connectWebSocket(\n url: string,\n protocols?: string[],\n headers?: HeadersInit,\n ): Promise<{ port: MessagePort; protocol?: string }>;\n /** Backs up every live cell that changed since its last successful save. */\n backupNow(): Promise<void>;\n /**\n * Hibernates every object idle for at least `idleMs` (default: `hibernateAfterMs`):\n * instances are dropped, storage and hibernatable WebSockets stay. Returns how many slept.\n * Hibernated objects idle for `closeDatabaseAfterMs` also close their database.\n */\n hibernateIdle(idleMs?: number): number;\n /** Replaces one object's instance with a fresh one on the same storage (facet abort). */\n restartObject(cellKey: string): void;\n /** Final backup of changed cells, then stops timers, closes every database and the storage. */\n close(): Promise<void>;\n}\n\nexport function createCellRuntime(opts: CellRuntimeOptions): CellRuntime {\n installRequestBody(); // Firefox: `request.body` for the Worker code (and for the retry below)\n const storage = opts.storage ?? {};\n const { backup, ownership } = storage;\n const durability: CellDurability = storage.durability ?? { committed: () => Promise.resolve() };\n // V8 serialization: storage values in celld's (and workerd's) format.\n const codec = opts.codec ?? v8Codec;\n const hosts = new Map<string, ObjectHost>();\n const background = new Set<Promise<unknown>>();\n // Events start in the context the runtime was made in, not their caller's (Cloudflare).\n // …and in a scope that keeps the Worker's unhandled rejections its own (Node).\n const rejections = rejectionScope(\n opts.onUnhandledRejection ?? reportToStderr(opts.scriptName ?? \"worker\"),\n );\n const root = asyncRoot();\n const eventsRoot: AsyncRoot = (fn) => root(() => rejections(fn));\n const waitUntil = (p: Promise<unknown>) => {\n const t = p.catch(() => {}).finally(() => background.delete(t));\n background.add(t);\n };\n const env: Record<string, unknown> = { ...opts.vars };\n const bindingClasses: Record<string, string> = {};\n const exportsObj = ctxExports(opts.worker, env);\n // Storage values: V8 serialization; ctx.exports stubs are stored too (workerd).\n const storageCodec = opts.codec ?? v8CodecWith(storedExports(exportsObj));\n const clock = opts.clock ?? systemClock;\n // Hosts by class name: the alarm scheduler wakes objects that nobody is calling.\n const hostsByClass = new Map<string, (id: DurableObjectId) => ObjectHost>();\n const alarms = new AlarmScheduler({\n clock,\n openIndex: () => opts.openSql(\"__cellb/alarms\"),\n fire: (e) => fireAlarm(e),\n });\n // One alarm() at a time per object (as on Cloudflare): a re-armed alarm that comes due\n // while the previous handler still runs waits for it.\n const alarmRuns = new Map<string, Promise<void>>();\n const ownedRetries = new Map<string, number>();\n function fireAlarm(e: AlarmEntry): Promise<void> {\n const prev = alarmRuns.get(e.cellKey) ?? Promise.resolve();\n const next = prev.then(() => fireAlarmNow(e));\n alarmRuns.set(e.cellKey, next);\n void next.finally(() => {\n if (alarmRuns.get(e.cellKey) === next) alarmRuns.delete(e.cellKey);\n });\n return next;\n }\n /**\n * celld's alarm lifecycle, in the cell's own storage (so it survives restarts and moves\n * between nodes, celld included): the row stays while its handler runs (getAlarm() reads\n * null meanwhile); success deletes it, failure reschedules it with backoff and counts the\n * failure in the row (`retry`, `counted_retry`) — alarmInfo.retryCount is that count.\n */\n async function fireAlarmNow(e: AlarmEntry): Promise<void> {\n const hostFor = hostsByClass.get(e.className);\n if (!hostFor) return;\n const host = hostFor(new DurableObjectId(e.idHex));\n try {\n await host.deliver(async (obj, state) => {\n // A wake (local timer, or an entry of the shared wake index) is a hint: the stored\n // alarm decides. Gone → nothing to do; moved later → wait for that time.\n const row = state.storage.alarmRowSync();\n if (!row) return;\n if (row.at > clock.now()) {\n alarms.set(e, row.at);\n return;\n }\n state.storage.beginAlarm(row);\n let ok = true;\n try {\n if (typeof obj.alarm === \"function\")\n await obj.alarm({\n retryCount: row.retry,\n isRetry: row.retry > 0,\n scheduledTime: row.at, // alarmInfo.scheduledTime, as in workerd\n });\n } catch {\n ok = false;\n }\n state.storage.finishAlarm(row, ok, clock.now());\n });\n ownedRetries.delete(e.cellKey);\n } catch (err) {\n // Owned by another node (celld or cellb): its owner fires the alarm.\n if (isOwnedElsewhere(err)) {\n hosts.get(e.cellKey)?.close();\n hosts.delete(e.cellKey);\n // A live owner fires it. A stopped one's lease expires within its TTL: look again a\n // few times before leaving it to the next poll of the wake index.\n const n = (ownedRetries.get(e.cellKey) ?? 0) + 1;\n if (n <= 15) {\n ownedRetries.set(e.cellKey, n);\n alarms.set(e, clock.now() + 2_000);\n } else ownedRetries.delete(e.cellKey);\n }\n // Any other failure (broken object, storage error): the row is unchanged; it fires again\n // when the object is next opened or the index is polled.\n }\n }\n\n for (const [binding, { className }] of Object.entries(opts.durableObjects ?? {})) {\n const cls = opts.worker[className] as DurableObjectClass | undefined;\n if (typeof cls !== \"function\")\n throw new Error(`Durable Object class \"${className}\" is not exported by the worker`);\n const hostFor = (id: DurableObjectId): ObjectHost => {\n const cellKey = `${className}/${id.toString()}`;\n let h = hosts.get(cellKey);\n if (!h || h.broken) {\n h?.close();\n h = new ObjectHost({\n cellKey,\n id,\n cls,\n env,\n openSql: opts.openSql,\n durability,\n codec: storageCodec,\n waitUntil,\n backup,\n onAlarmChange: (at) => alarms.set({ cellKey, className, idHex: id.toString() }, at),\n exports: exportsObj,\n facet: opts.facets,\n asyncRoot: eventsRoot,\n acquire: ownership ? (key) => ownership.tryAcquire(key) : undefined,\n sqlExtensions: opts.sqlExtensions,\n deleteAllPreservesAlarm: opts.deleteAllPreservesAlarm,\n });\n hosts.set(cellKey, h);\n }\n return h;\n };\n hostsByClass.set(className, hostFor);\n const nsKey =\n opts.namespaceKeys?.[className] ?? namespaceKey(opts.scriptName ?? \"worker\", className);\n env[binding] = new DurableObjectNamespace(nsKey, (id) => {\n const remote = opts.route?.(`${className}/${id.toString()}`, id);\n if (remote) return () => httpEndpoint(postVia(remote), codec, binding, className, id);\n const cellKey = `${className}/${id.toString()}`;\n // A cell not open yet waits for room in its store before its first event (OPFS pool).\n const ready = () => (hosts.has(cellKey) ? undefined : opts.openSql.room?.(cellKey));\n const local = localEndpoint(() => hostFor(id), ready);\n const peers = opts.peers;\n if (!peers) return local;\n // Local first; a cell owned by another node is reached through that node.\n const viaOwner = async () => {\n const owner = await peers.ownerOf(cellKey);\n if (!owner) throw new CellOwnedElsewhereError(cellKey);\n const direct = await peers.endpoint?.(owner, cellKey, id.name);\n if (direct) return direct;\n return httpEndpoint(postVia(peers.link(owner)), codec, binding, className, id);\n };\n // The host reports a failed open as a broken object; the cause tells why.\n const elsewhere = (e: unknown): boolean => {\n for (\n let x = e as { name?: string; cause?: unknown } | undefined, i = 0;\n x && i < 5;\n x = x.cause as never, i++\n )\n if (x.name === \"CellOwnedElsewhereError\") return true;\n return false;\n };\n return () => {\n const l = local();\n return {\n get local() {\n return l.local; // not copied: reading it opens the cell\n },\n fetch: async (req: Request) => {\n const spare = req.body ? req.clone() : req;\n try {\n return await l.fetch(req);\n } catch (e) {\n if (!elsewhere(e)) throw e;\n hosts.get(cellKey)?.close();\n hosts.delete(cellKey);\n return (await viaOwner()).fetch(spare);\n }\n },\n call: async (method: string, args: unknown[]) => {\n try {\n return await l.call(method, args);\n } catch (e) {\n if (!elsewhere(e)) throw e;\n hosts.get(cellKey)?.close();\n hosts.delete(cellKey);\n return (await viaOwner()).call(method, args);\n }\n },\n };\n };\n });\n bindingClasses[binding] = className;\n // ctx.exports.<Class> of a class with a namespace is also that namespace, as in workerd\n // (`ctx.exports.MyActor.getByName(\"a\")`); it stays usable as a facet class handle.\n const ns = env[binding] as DurableObjectNamespace;\n const exported = exportsObj[className] as Record<string, unknown> | undefined;\n if (exported && !(\"getByName\" in exported))\n for (const [m, d] of Object.entries(\n Object.getOwnPropertyDescriptors(DurableObjectNamespace.prototype),\n ))\n if (m !== \"constructor\" && typeof d.value === \"function\") exported[m] = d.value.bind(ns);\n }\n\n alarms.restore();\n // Alarms published by any node in a shared wake index (celld's): this node fires them too.\n // An entry is only a hint: firing opens the cell and runs alarm() only if its stored alarm\n // is still due at that time.\n // The index is read at start and then every `wakePollMs` (default 30 s), so alarms of cells\n // whose owner went away are picked up — celld's waker does the same.\n const wakes = storage.durability?.wakes;\n let wakeTimer: unknown;\n let wakesStopped = false;\n if (wakes) {\n const known = new Set(Object.values(bindingClasses));\n const poll = async () => {\n try {\n for (const w of await wakes.call(storage.durability))\n if (known.has(w.className) && !alarmRuns.has(w.cellKey))\n alarms.set(\n { cellKey: w.cellKey, className: w.className, idHex: w.cellKey.split(\"/\")[1] },\n w.at,\n );\n } catch {\n // the index is unavailable for now: next poll\n }\n if (!wakesStopped) wakeTimer = clock.setTimeout(() => void poll(), opts.wakePollMs ?? 30_000);\n };\n void poll();\n }\n // Idle sweep for hibernation (opt-in).\n let hibernationTimer: unknown;\n if (opts.hibernateAfterMs !== undefined) {\n const every = Math.max(1_000, opts.hibernateAfterMs / 2);\n const sweep = () => {\n runtime.hibernateIdle();\n hibernationTimer = clock.setTimeout(sweep, every);\n };\n hibernationTimer = clock.setTimeout(sweep, every);\n }\n const backupAll = (reason: \"interval\" | \"manual\" | \"close\") =>\n Promise.all([...hosts.values()].map((h) => h.backupIfDirty(reason, clock.now()))).then(\n () => {},\n );\n let timer: unknown;\n let closed = false;\n const schedule = () => {\n if (!backup || closed) return;\n timer = clock.setTimeout(() => {\n void backupAll(\"interval\").finally(schedule);\n }, backup.intervalMs ?? 30_000);\n };\n schedule();\n\n const runtime: CellRuntime = {\n env,\n exports: exportsObj,\n durableObjectBindings: bindingClasses,\n backupNow: () => backupAll(\"manual\"),\n async connectWebSocket(url, protocols = [], headers) {\n const h = new Headers(headers);\n h.set(\"Upgrade\", \"websocket\");\n if (protocols.length) h.set(\"Sec-WebSocket-Protocol\", protocols.join(\", \"));\n const httpUrl = url.replace(/^ws(s?):/, \"http$1:\");\n const res = (await this.fetch(\n withUpgrade(\n new Request(httpUrl, { headers: h }),\n \"websocket\",\n protocols.length ? { \"Sec-WebSocket-Protocol\": protocols.join(\", \") } : undefined,\n ),\n )) as Response & {\n webSocket?: CfWebSocket | null;\n };\n if (res.status !== 101 || !res.webSocket)\n throw new Error(`WebSocket upgrade refused: HTTP ${res.status}`);\n return {\n port: takeClientPort(res.webSocket),\n protocol: res.headers.get(\"Sec-WebSocket-Protocol\") ?? undefined,\n };\n },\n restartObject(cellKey: string) {\n hosts.get(cellKey)?.restart();\n },\n hibernateIdle(idleMs = opts.hibernateAfterMs ?? 0) {\n const now = Date.now();\n let n = 0;\n const closeMs = opts.closeDatabaseAfterMs;\n for (const h of hosts.values()) {\n const idle = now - h.lastActive;\n if (idle >= idleMs && h.hibernate()) n++;\n if (closeMs !== undefined && idle >= closeMs) h.closeDatabase();\n }\n return n;\n },\n async close() {\n if (hibernationTimer !== undefined) clock.clearTimeout(hibernationTimer);\n closed = true;\n wakesStopped = true;\n if (wakeTimer !== undefined) clock.clearTimeout(wakeTimer);\n alarms.stop();\n clock.clearTimeout(timer);\n timer = undefined;\n await backupAll(\"close\");\n // The releases reach the store before it closes.\n await Promise.all([...hosts.values()].map((h) => h.close()));\n hosts.clear();\n alarms.close(); // every database of the runtime is closed now\n await storage.close?.();\n },\n async fetch(req) {\n const handler = opts.worker.default?.fetch;\n if (!handler) return new Response(\"Worker has no fetch handler\", { status: 500 });\n const ctx = {\n waitUntil,\n passThroughOnException() {},\n exports: exportsObj,\n } as ExecutionContext;\n // celld's ingress: an inbound request has a `cf` object (no edge fields).\n if ((req as { cf?: unknown }).cf === undefined)\n Object.defineProperty(req, \"cf\", { value: {}, enumerable: true });\n try {\n const r = await rejections(() => handler.call(opts.worker.default, req, env, ctx));\n // A non-Response is sent as text (celld), not a failure.\n return r instanceof Response ? r : new Response(String(r));\n } catch (e) {\n const err = e as Error;\n return new Response(\n `Worker failed: rejected: ${err?.name ?? \"Error\"}: ${err?.message ?? String(e)}`,\n {\n status: 500,\n headers: { \"content-type\": \"application/json\" },\n },\n );\n }\n },\n runEvent: (fn) => rejections(fn),\n evictAll() {\n for (const h of hosts.values()) h.close();\n hosts.clear();\n },\n async drain() {\n while (background.size) await Promise.all([...background]);\n },\n waitUntil,\n };\n return runtime;\n}\n\n/** The error (or its cause chain) says another node owns the cell. */\nexport function isOwnedElsewhere(e: unknown): boolean {\n for (\n let x = e as { name?: string; cause?: unknown } | undefined, i = 0;\n x && i < 5;\n x = x.cause as never, i++\n )\n if (x.name === \"CellOwnedElsewhereError\") return true;\n return false;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/core/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type CellDurability,\n type CellStorage,\n type Clock,\n type OpenCellSql,\n systemClock,\n type ValueCodec,\n} from \"../ports.js\";\nimport { httpEndpoint, postVia, type Send } from \"../transport/cells-link.js\";\nimport { v8Codec, v8CodecWith } from \"../v8/codec.js\";\nimport { type CfWebSocket, takeClientPort } from \"../ws/server.js\";\nimport { withUpgrade } from \"../ws/upgrade.js\";\nimport { type AlarmEntry, AlarmScheduler } from \"./alarms.js\";\nimport { type AsyncRoot, asyncRoot } from \"./async-context.js\";\nimport type { ExecutionContext } from \"./durable-object.js\";\nimport { ctxExports, type DurableObjectClass, storedExports } from \"./handles.js\";\nimport { DurableObjectId, namespaceKey } from \"./id.js\";\nimport { DurableObjectNamespace, localEndpoint, type ObjectEndpoint } from \"./namespace.js\";\nimport {\n CellOwnedElsewhereError,\n closingWith,\n ObjectClosedError,\n ObjectHost,\n} from \"./object-host.js\";\nimport { installRequestBody } from \"./request-body.js\";\nimport { type RejectionHandler, rejectionScope, reportToStderr } from \"./worker-rejections.js\";\n\nexport interface WorkerModule {\n default: { fetch?(req: Request, env: any, ctx: ExecutionContext): Response | Promise<Response> };\n [exportName: string]: unknown;\n}\n\nexport interface CellRuntimeOptions {\n /**\n * A promise the Worker's code leaves rejected (Node: the Worker shares the host's process).\n * It is the Worker's, as on workerd and celld: it reaches this handler, not the process's\n * `unhandledRejection` listeners. Default: one line on stderr, outside the Worker's console.\n */\n onUnhandledRejection?: RejectionHandler;\n /** The Worker's module namespace (what wrangler/celld bundle as main module). */\n worker: WorkerModule;\n /** Durable Object bindings: env name → exported class name (wrangler `durable_objects.bindings`). */\n durableObjects?: Record<string, { className: string }>;\n /** Plain vars / other bindings merged into env. */\n vars?: Record<string, unknown>;\n openSql: OpenCellSql;\n /** Durability, backup and ownership of the cells; closed by `close()`, after the runtime. */\n storage?: CellStorage;\n codec?: ValueCodec;\n /**\n * Placement: return a `send` when the cell lives elsewhere (another shard\n * worker, tab or peer); `undefined` means \"host it here\". Default: all local.\n */\n route?: (cellKey: string, id: DurableObjectId) => Send | undefined;\n /** How often to re-read a shared alarm wake index (durability.wakes), in ms. Default 30 s. */\n wakePollMs?: number;\n /** Every object of this runtime is a facet of an outer cell (an isolate's runtime). */\n facets?: boolean;\n /**\n * The `ctx.id` an object sees, when it is not the id that addresses it (a facet given an `id`\n * by `ctx.facets.get`): its storage, cell key and alarms stay the addressing id's.\n */\n ctxIdOf?: (cellKey: string) => DurableObjectId | undefined;\n /** The Worker script's name (wrangler `name`): object ids derive from it, as on celld. */\n scriptName?: string;\n /** Namespace keys overriding the script-scoped default, per class (celld's fleet-wide ones). */\n namespaceKeys?: Record<string, string>;\n /**\n * Routing between nodes (celld's peer routing): when this node cannot own a cell\n * (`CellOwnedElsewhereError`), the call goes to the owner's node over an internal link\n * (`cellsHttpHandler` on the far side). `ownerOf` reads the cell's lease holder.\n */\n peers?: {\n ownerOf(cellKey: string): Promise<string | undefined>;\n link(owner: string): Send;\n /**\n * Talks to an owner directly, for owners that do not speak cellsHttpHandler (a celld node,\n * reached through celld's peer tunnel). Takes precedence over `link` when it returns one.\n */\n endpoint?(\n owner: string,\n cellKey: string,\n name: string | undefined,\n ): Promise<ObjectEndpoint | undefined>;\n };\n /** Hibernate objects idle this long (ms); swept every max(1 s, half of it). Off by default. */\n hibernateAfterMs?: number;\n /**\n * Close the SQLite database of a hibernated object idle this long (ms); the next event reopens\n * it. Swept with `hibernateAfterMs`, so it needs that too. Off by default: the database must\n * come back, so use local SQLite that persists (a directory, an OPFS pool) or storage that\n * restores the cell (a log or a backup).\n */\n closeDatabaseAfterMs?: number;\n /**\n * On `close()`, how long (ms) events still running and `waitUntil` work may take to finish\n * before the databases close under them (they then fail with ObjectClosedError). Default 2000.\n */\n closeGraceMs?: number;\n /** SQLite extensions loaded into every cell database (celld's `sqlite_vec` flag). */\n sqlExtensions?: string[];\n /** `delete_all_preserves_alarm`: storage.deleteAll() keeps the alarm (default: deletes it). */\n deleteAllPreservesAlarm?: boolean;\n /** Timers of the runtime (backups); injectable for tests. */\n clock?: Clock;\n}\n\nexport interface CellRuntime {\n /** Ingress: a (Request) ⇒ Response handler — exactly what webrun-http-browser / node:http mount. */\n fetch(req: Request): Promise<Response>;\n readonly env: Record<string, unknown>;\n /** The Worker's `ctx.exports` (also `exports` of `cloudflare:workers`). */\n readonly exports: Record<string, unknown>;\n /**\n * Runs Worker code the host dispatches itself (a cron trigger's `scheduled()`) as the Worker's\n * event: a promise it leaves rejected goes to `onUnhandledRejection`, not to the process.\n */\n runEvent<R>(fn: () => R): R;\n /** Drops live instances (simulates eviction / hibernation); storage survives if openSql persists it. */\n evictAll(): void;\n /** Settles all waitUntil() promises. */\n drain(): Promise<void>;\n /**\n * Keeps `p` running in the background until `drain()` (what `waitUntil` of\n * `cloudflare:workers` does: on Cloudflare it extends the current event).\n */\n waitUntil(p: Promise<unknown>): void;\n /** Durable Object binding → class name (the namespace key used by idFromName). */\n readonly durableObjectBindings: Readonly<Record<string, string>>;\n /**\n * WebSocket ingress: runs the Worker's fetch with an Upgrade request; on a 101\n * with `webSocket`, returns the client end's MessagePort (to be transferred to\n * the real client, e.g. a page's CellsWebSocket).\n */\n connectWebSocket(\n url: string,\n protocols?: string[],\n headers?: HeadersInit,\n ): Promise<{ port: MessagePort; protocol?: string }>;\n /** Backs up every live cell that changed since its last successful save. */\n backupNow(): Promise<void>;\n /**\n * Hibernates every object idle for at least `idleMs` (default: `hibernateAfterMs`):\n * instances are dropped, storage and hibernatable WebSockets stay. Returns how many slept.\n * Hibernated objects idle for `closeDatabaseAfterMs` also close their database.\n */\n hibernateIdle(idleMs?: number): number;\n /** Replaces one object's instance with a fresh one on the same storage (facet abort). */\n restartObject(cellKey: string): void;\n /** Final backup of changed cells, then stops timers, closes every database and the storage. */\n close(): Promise<void>;\n}\n\nexport function createCellRuntime(opts: CellRuntimeOptions): CellRuntime {\n installRequestBody(); // Firefox: `request.body` for the Worker code (and for the retry below)\n const storage = opts.storage ?? {};\n const { backup, ownership } = storage;\n const durability: CellDurability = storage.durability ?? { committed: () => Promise.resolve() };\n // V8 serialization: storage values in celld's (and workerd's) format.\n const codec = opts.codec ?? v8Codec;\n const hosts = new Map<string, ObjectHost>();\n const background = new Set<Promise<unknown>>();\n // Events start in the context the runtime was made in, not their caller's (Cloudflare).\n // …and in a scope that keeps the Worker's unhandled rejections its own (Node).\n const rejections = rejectionScope(\n opts.onUnhandledRejection ?? reportToStderr(opts.scriptName ?? \"worker\"),\n );\n const root = asyncRoot();\n const eventsRoot: AsyncRoot = (fn) => root(() => rejections(fn));\n const waitUntil = (p: Promise<unknown>) => {\n const t = p.catch(() => {}).finally(() => background.delete(t));\n background.add(t);\n };\n const env: Record<string, unknown> = { ...opts.vars };\n const bindingClasses: Record<string, string> = {};\n const exportsObj = ctxExports(opts.worker, env);\n // Storage values: V8 serialization; ctx.exports stubs are stored too (workerd).\n const storageCodec = opts.codec ?? v8CodecWith(storedExports(exportsObj));\n const clock = opts.clock ?? systemClock;\n // Hosts by class name: the alarm scheduler wakes objects that nobody is calling.\n const hostsByClass = new Map<string, (id: DurableObjectId) => ObjectHost>();\n const alarms = new AlarmScheduler({\n clock,\n openIndex: () => opts.openSql(\"__cellb/alarms\"),\n fire: (e) => fireAlarm(e),\n });\n // One alarm() at a time per object (as on Cloudflare): a re-armed alarm that comes due\n // while the previous handler still runs waits for it.\n const alarmRuns = new Map<string, Promise<void>>();\n const ownedRetries = new Map<string, number>();\n function fireAlarm(e: AlarmEntry): Promise<void> {\n const prev = alarmRuns.get(e.cellKey) ?? Promise.resolve();\n const next = prev.then(() => fireAlarmNow(e));\n alarmRuns.set(e.cellKey, next);\n void next.finally(() => {\n if (alarmRuns.get(e.cellKey) === next) alarmRuns.delete(e.cellKey);\n });\n return next;\n }\n /**\n * celld's alarm lifecycle, in the cell's own storage (so it survives restarts and moves\n * between nodes, celld included): the row stays while its handler runs (getAlarm() reads\n * null meanwhile); success deletes it, failure reschedules it with backoff and counts the\n * failure in the row (`retry`, `counted_retry`) — alarmInfo.retryCount is that count.\n */\n async function fireAlarmNow(e: AlarmEntry): Promise<void> {\n const hostFor = hostsByClass.get(e.className);\n if (!hostFor) return;\n const host = hostFor(new DurableObjectId(e.idHex));\n try {\n await host.deliver(async (obj, state) => {\n // A wake (local timer, or an entry of the shared wake index) is a hint: the stored\n // alarm decides. Gone → nothing to do; moved later → wait for that time.\n const row = state.storage.alarmRowSync();\n if (!row) return;\n if (row.at > clock.now()) {\n alarms.set(e, row.at);\n return;\n }\n state.storage.beginAlarm(row);\n let ok = true;\n try {\n if (typeof obj.alarm === \"function\")\n await obj.alarm({\n retryCount: row.retry,\n isRetry: row.retry > 0,\n scheduledTime: row.at, // alarmInfo.scheduledTime, as in workerd\n });\n } catch {\n ok = false;\n }\n state.storage.finishAlarm(row, ok, clock.now());\n });\n ownedRetries.delete(e.cellKey);\n } catch (err) {\n // Owned by another node (celld or cellb): its owner fires the alarm.\n if (isOwnedElsewhere(err)) {\n hosts.get(e.cellKey)?.close();\n hosts.delete(e.cellKey);\n // A live owner fires it. A stopped one's lease expires within its TTL: look again a\n // few times before leaving it to the next poll of the wake index.\n const n = (ownedRetries.get(e.cellKey) ?? 0) + 1;\n if (n <= 15) {\n ownedRetries.set(e.cellKey, n);\n alarms.set(e, clock.now() + 2_000);\n } else ownedRetries.delete(e.cellKey);\n }\n // Any other failure (broken object, storage error): the row is unchanged; it fires again\n // when the object is next opened or the index is polled.\n }\n }\n\n for (const [binding, { className }] of Object.entries(opts.durableObjects ?? {})) {\n const cls = opts.worker[className] as DurableObjectClass | undefined;\n if (typeof cls !== \"function\")\n throw new Error(`Durable Object class \"${className}\" is not exported by the worker`);\n const hostFor = (id: DurableObjectId): ObjectHost => {\n const cellKey = `${className}/${id.toString()}`;\n // Once close() has closed the cells, none opens again: its storage is closed or handed to\n // the next runtime. Until then (the grace period), work in flight still reaches objects.\n if (cellsClosed) throw new ObjectClosedError(cellKey);\n let h = hosts.get(cellKey);\n if (!h || h.broken) {\n h?.close();\n h = new ObjectHost({\n cellKey,\n id: opts.ctxIdOf?.(cellKey) ?? id,\n cls,\n env,\n openSql: opts.openSql,\n durability,\n codec: storageCodec,\n waitUntil,\n backup,\n onAlarmChange: (at) => alarms.set({ cellKey, className, idHex: id.toString() }, at),\n exports: exportsObj,\n facet: opts.facets,\n asyncRoot: eventsRoot,\n acquire: ownership ? (key) => ownership.tryAcquire(key) : undefined,\n sqlExtensions: opts.sqlExtensions,\n deleteAllPreservesAlarm: opts.deleteAllPreservesAlarm,\n });\n hosts.set(cellKey, h);\n }\n return h;\n };\n hostsByClass.set(className, hostFor);\n const nsKey =\n opts.namespaceKeys?.[className] ?? namespaceKey(opts.scriptName ?? \"worker\", className);\n env[binding] = new DurableObjectNamespace(nsKey, (id) => {\n const remote = opts.route?.(`${className}/${id.toString()}`, id);\n if (remote) return () => httpEndpoint(postVia(remote), codec, binding, className, id);\n const cellKey = `${className}/${id.toString()}`;\n // A cell not open yet waits for room in its store before its first event (OPFS pool).\n const ready = () => (hosts.has(cellKey) ? undefined : opts.openSql.room?.(cellKey));\n const local = localEndpoint(() => hostFor(id), ready);\n const peers = opts.peers;\n if (!peers) return local;\n // Local first; a cell owned by another node is reached through that node.\n const viaOwner = async () => {\n const owner = await peers.ownerOf(cellKey);\n if (!owner) throw new CellOwnedElsewhereError(cellKey);\n const direct = await peers.endpoint?.(owner, cellKey, id.name);\n if (direct) return direct;\n return httpEndpoint(postVia(peers.link(owner)), codec, binding, className, id);\n };\n // The host reports a failed open as a broken object; the cause tells why.\n const elsewhere = (e: unknown): boolean => {\n for (\n let x = e as { name?: string; cause?: unknown } | undefined, i = 0;\n x && i < 5;\n x = x.cause as never, i++\n )\n if (x.name === \"CellOwnedElsewhereError\") return true;\n return false;\n };\n return () => {\n const l = local();\n return {\n get local() {\n return l.local; // not copied: reading it opens the cell\n },\n fetch: async (req: Request) => {\n const spare = req.body ? req.clone() : req;\n try {\n return await l.fetch(req);\n } catch (e) {\n if (!elsewhere(e)) throw e;\n hosts.get(cellKey)?.close();\n hosts.delete(cellKey);\n return (await viaOwner()).fetch(spare);\n }\n },\n call: async (method: string, args: unknown[]) => {\n try {\n return await l.call(method, args);\n } catch (e) {\n if (!elsewhere(e)) throw e;\n hosts.get(cellKey)?.close();\n hosts.delete(cellKey);\n return (await viaOwner()).call(method, args);\n }\n },\n };\n };\n });\n bindingClasses[binding] = className;\n // ctx.exports.<Class> of a class with a namespace is also that namespace, as in workerd\n // (`ctx.exports.MyActor.getByName(\"a\")`); it stays usable as a facet class handle.\n const ns = env[binding] as DurableObjectNamespace;\n const exported = exportsObj[className] as Record<string, unknown> | undefined;\n if (exported && !(\"getByName\" in exported))\n for (const [m, d] of Object.entries(\n Object.getOwnPropertyDescriptors(DurableObjectNamespace.prototype),\n ))\n if (m !== \"constructor\" && typeof d.value === \"function\") exported[m] = d.value.bind(ns);\n }\n\n alarms.restore();\n // Alarms published by any node in a shared wake index (celld's): this node fires them too.\n // An entry is only a hint: firing opens the cell and runs alarm() only if its stored alarm\n // is still due at that time.\n // The index is read at start and then every `wakePollMs` (default 30 s), so alarms of cells\n // whose owner went away are picked up — celld's waker does the same.\n const wakes = storage.durability?.wakes;\n let wakeTimer: unknown;\n let wakesStopped = false;\n if (wakes) {\n const known = new Set(Object.values(bindingClasses));\n const poll = async () => {\n try {\n for (const w of await wakes.call(storage.durability))\n if (known.has(w.className) && !alarmRuns.has(w.cellKey))\n alarms.set(\n { cellKey: w.cellKey, className: w.className, idHex: w.cellKey.split(\"/\")[1] },\n w.at,\n );\n } catch {\n // the index is unavailable for now: next poll\n }\n if (!wakesStopped) wakeTimer = clock.setTimeout(() => void poll(), opts.wakePollMs ?? 30_000);\n };\n void poll();\n }\n // Idle sweep for hibernation (opt-in).\n let hibernationTimer: unknown;\n if (opts.hibernateAfterMs !== undefined) {\n const every = Math.max(1_000, opts.hibernateAfterMs / 2);\n const sweep = () => {\n runtime.hibernateIdle();\n hibernationTimer = clock.setTimeout(sweep, every);\n };\n hibernationTimer = clock.setTimeout(sweep, every);\n }\n const backupAll = (reason: \"interval\" | \"manual\" | \"close\") =>\n Promise.all([...hosts.values()].map((h) => h.backupIfDirty(reason, clock.now()))).then(\n () => {},\n );\n let timer: unknown;\n let closed = false;\n /** Set by close() after its grace period: no cell opens or takes an event any more. */\n let cellsClosed = false;\n /** Aborts when close() starts: the signal of the Worker's requests in flight. */\n const closing = new AbortController();\n const schedule = () => {\n if (!backup || closed) return;\n timer = clock.setTimeout(() => {\n void backupAll(\"interval\").finally(schedule);\n }, backup.intervalMs ?? 30_000);\n };\n schedule();\n\n const runtime: CellRuntime = {\n env,\n exports: exportsObj,\n durableObjectBindings: bindingClasses,\n backupNow: () => backupAll(\"manual\"),\n async connectWebSocket(url, protocols = [], headers) {\n const h = new Headers(headers);\n h.set(\"Upgrade\", \"websocket\");\n if (protocols.length) h.set(\"Sec-WebSocket-Protocol\", protocols.join(\", \"));\n const httpUrl = url.replace(/^ws(s?):/, \"http$1:\");\n const res = (await this.fetch(\n withUpgrade(\n new Request(httpUrl, { headers: h }),\n \"websocket\",\n protocols.length ? { \"Sec-WebSocket-Protocol\": protocols.join(\", \") } : undefined,\n ),\n )) as Response & {\n webSocket?: CfWebSocket | null;\n };\n if (res.status !== 101 || !res.webSocket)\n throw new Error(`WebSocket upgrade refused: HTTP ${res.status}`);\n return {\n port: takeClientPort(res.webSocket),\n protocol: res.headers.get(\"Sec-WebSocket-Protocol\") ?? undefined,\n };\n },\n restartObject(cellKey: string) {\n hosts.get(cellKey)?.restart();\n },\n hibernateIdle(idleMs = opts.hibernateAfterMs ?? 0) {\n const now = Date.now();\n let n = 0;\n const closeMs = opts.closeDatabaseAfterMs;\n for (const h of hosts.values()) {\n const idle = now - h.lastActive;\n if (idle >= idleMs && h.hibernate()) n++;\n if (closeMs !== undefined && idle >= closeMs) h.closeDatabase();\n }\n return n;\n },\n async close() {\n if (hibernationTimer !== undefined) clock.clearTimeout(hibernationTimer);\n closed = true;\n wakesStopped = true;\n if (wakeTimer !== undefined) clock.clearTimeout(wakeTimer);\n alarms.stop();\n clock.clearTimeout(timer);\n timer = undefined;\n // Events in flight (a conversation's last writes, say) and waitUntil work finish first,\n // within the grace period: their writes are then in the final backups too.\n const grace = opts.closeGraceMs ?? 2_000;\n // Requests in flight, the Worker's and its objects', see their signal abort.\n closing.abort(new Error(\"the runtime is closing\"));\n for (const h of hosts.values()) h.shutdown();\n // Work in flight may start more (a queue's delivery calls the consumer, which writes to\n // another object): wait until nothing runs, nor started while waiting, or the grace ends.\n const end = Date.now() + grace;\n for (let left = grace; left > 0; left = end - Date.now()) {\n const cells = hosts.size;\n let t: ReturnType<typeof setTimeout> | undefined;\n const idle = await Promise.race([\n Promise.all([...[...hosts.values()].map((h) => h.settled()), ...[...background]]).then(\n () => true,\n ),\n new Promise<false>((r) => (t = setTimeout(() => r(false), left))),\n ]);\n clearTimeout(t);\n if (!idle) break;\n // One more turn: what finished may have queued more work.\n await new Promise((r) => setTimeout(r, 0));\n if (\n hosts.size === cells &&\n background.size === 0 &&\n [...hosts.values()].every((h) => h.idle)\n )\n break;\n }\n cellsClosed = true;\n await backupAll(\"close\");\n // The releases reach the store before it closes.\n await Promise.all([...hosts.values()].map((h) => h.close()));\n hosts.clear();\n alarms.close(); // every database of the runtime is closed now\n await storage.close?.();\n },\n async fetch(req) {\n const handler = opts.worker.default?.fetch;\n if (!handler) return new Response(\"Worker has no fetch handler\", { status: 500 });\n // A closed runtime serves nothing: its cells are closed, or another runtime's now.\n if (closed) return new Response(\"cellb: the runtime is closed\", { status: 503 });\n // Its signal aborts when the runtime closes: a long poll or an SSE stream ends then.\n req = closingWith(req, closing.signal);\n const ctx = {\n waitUntil,\n passThroughOnException() {},\n exports: exportsObj,\n } as ExecutionContext;\n // celld's ingress: an inbound request has a `cf` object (no edge fields).\n if ((req as { cf?: unknown }).cf === undefined)\n Object.defineProperty(req, \"cf\", { value: {}, enumerable: true });\n try {\n const r = await rejections(() => handler.call(opts.worker.default, req, env, ctx));\n // A non-Response is sent as text (celld), not a failure.\n return r instanceof Response ? r : new Response(String(r));\n } catch (e) {\n const err = e as Error;\n return new Response(\n `Worker failed: rejected: ${err?.name ?? \"Error\"}: ${err?.message ?? String(e)}`,\n {\n status: 500,\n headers: { \"content-type\": \"application/json\" },\n },\n );\n }\n },\n runEvent: (fn) => rejections(fn),\n evictAll() {\n for (const h of hosts.values()) h.close();\n hosts.clear();\n },\n async drain() {\n while (background.size) await Promise.all([...background]);\n },\n waitUntil,\n };\n return runtime;\n}\n\n/** The error (or its cause chain) says another node owns the cell. */\nexport function isOwnedElsewhere(e: unknown): boolean {\n for (\n let x = e as { name?: string; cause?: unknown } | undefined, i = 0;\n x && i < 5;\n x = x.cause as never, i++\n )\n if (x.name === \"CellOwnedElsewhereError\") return true;\n return false;\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,11 +8,12 @@ export { filesApiObjectStore, memoryObjectStore, type ObjectStore, PreconditionF
|
|
|
8
8
|
export { type S3Options, s3ObjectStore } from "./bucket/s3-object-store.js";
|
|
9
9
|
export { DurableObject, type ExecutionContext, WorkerEntrypoint } from "./core/durable-object.js";
|
|
10
10
|
export { DurableObjectNamespace, type DurableObjectStub, runInDurableObject, } from "./core/namespace.js";
|
|
11
|
-
export { BrokenObjectError, CellOwnedElsewhereError } from "./core/object-host.js";
|
|
11
|
+
export { BrokenObjectError, CellOwnedElsewhereError, ObjectClosedError, } from "./core/object-host.js";
|
|
12
12
|
export { type CellRuntime, type CellRuntimeOptions, createCellRuntime, type WorkerModule, } from "./core/runtime.js";
|
|
13
13
|
export { shardOf } from "./core/shard.js";
|
|
14
14
|
export { DurableObjectState } from "./core/state.js";
|
|
15
15
|
export * from "./ports.js";
|
|
16
|
+
export { parseJsonc } from "./project/jsonc.js";
|
|
16
17
|
export { createProjectRuntime, type ProjectHost, type ProjectRuntime, type WranglerConfig, } from "./project/wrangler.js";
|
|
17
18
|
export { CellRouter, type CellRouterOptions, ShardOwnerLostError } from "./router/cell-router.js";
|
|
18
19
|
export { createShardWorker, type ShardWorker, type ShardWorkerOptions, shardRouting, } from "./router/shard-worker.js";
|
package/dist/index.js
CHANGED
|
@@ -8,11 +8,12 @@ export { filesApiObjectStore, memoryObjectStore, PreconditionFailedError, } from
|
|
|
8
8
|
export { s3ObjectStore } from "./bucket/s3-object-store.js";
|
|
9
9
|
export { DurableObject, WorkerEntrypoint } from "./core/durable-object.js";
|
|
10
10
|
export { DurableObjectNamespace, runInDurableObject, } from "./core/namespace.js";
|
|
11
|
-
export { BrokenObjectError, CellOwnedElsewhereError } from "./core/object-host.js";
|
|
11
|
+
export { BrokenObjectError, CellOwnedElsewhereError, ObjectClosedError, } from "./core/object-host.js";
|
|
12
12
|
export { createCellRuntime, } from "./core/runtime.js";
|
|
13
13
|
export { shardOf } from "./core/shard.js";
|
|
14
14
|
export { DurableObjectState } from "./core/state.js";
|
|
15
15
|
export * from "./ports.js";
|
|
16
|
+
export { parseJsonc } from "./project/jsonc.js";
|
|
16
17
|
export { createProjectRuntime, } from "./project/wrangler.js";
|
|
17
18
|
export { CellRouter, ShardOwnerLostError } from "./router/cell-router.js";
|
|
18
19
|
export { createShardWorker, shardRouting, } from "./router/shard-worker.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACxF,OAAO,EAAyB,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACzF,OAAO,EAA8B,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACL,OAAO,EAGP,SAAS,GACV,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAA2B,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EAEjB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAkB,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAyB,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAClG,OAAO,EACL,sBAAsB,EAEtB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACxF,OAAO,EAAyB,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACzF,OAAO,EAA8B,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACL,OAAO,EAGP,SAAS,GACV,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAA2B,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EAEjB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAkB,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAyB,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAClG,OAAO,EACL,sBAAsB,EAEtB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAGL,iBAAiB,GAElB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,oBAAoB,GAIrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,UAAU,EAA0B,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAClG,OAAO,EACL,iBAAiB,EAGjB,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAEL,gBAAgB,EAEhB,aAAa,GACd,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAEL,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,YAAY,GACb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,oBAAoB,GAErB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC","sourcesContent":["export { type FilesApiBackupOptions, filesApiBackup } from \"./adapters/files-backup.js\";\nexport { type ChangeLogOptions, filesApiChangeLog } from \"./adapters/files-changelog.js\";\nexport { type FilesApiLtxLogOptions, filesApiLtxLog } from \"./adapters/files-ltx.js\";\nexport { wasmMemoryOpener } from \"./adapters/wasm-sqlite.js\";\nexport {\n AiError,\n type AiRunOptions,\n type WorkersAiOptions,\n workersAi,\n} from \"./bindings/workers-ai.js\";\nexport { type CelldBucketOptions, celldBucket } from \"./bucket/celld-cells.js\";\nexport {\n filesApiObjectStore,\n memoryObjectStore,\n type ObjectStore,\n PreconditionFailedError,\n} from \"./bucket/object-store.js\";\nexport { type S3Options, s3ObjectStore } from \"./bucket/s3-object-store.js\";\nexport { DurableObject, type ExecutionContext, WorkerEntrypoint } from \"./core/durable-object.js\";\nexport {\n DurableObjectNamespace,\n type DurableObjectStub,\n runInDurableObject,\n} from \"./core/namespace.js\";\nexport {\n BrokenObjectError,\n CellOwnedElsewhereError,\n ObjectClosedError,\n} from \"./core/object-host.js\";\nexport {\n type CellRuntime,\n type CellRuntimeOptions,\n createCellRuntime,\n type WorkerModule,\n} from \"./core/runtime.js\";\nexport { shardOf } from \"./core/shard.js\";\nexport { DurableObjectState } from \"./core/state.js\";\nexport * from \"./ports.js\";\nexport { parseJsonc } from \"./project/jsonc.js\";\nexport {\n createProjectRuntime,\n type ProjectHost,\n type ProjectRuntime,\n type WranglerConfig,\n} from \"./project/wrangler.js\";\nexport { CellRouter, type CellRouterOptions, ShardOwnerLostError } from \"./router/cell-router.js\";\nexport {\n createShardWorker,\n type ShardWorker,\n type ShardWorkerOptions,\n shardRouting,\n} from \"./router/shard-worker.js\";\nexport {\n type CellsHttpOptions,\n cellsHttpHandler,\n type RemoteRuntime,\n remoteRuntime,\n} from \"./transport/cells-http.js\";\nexport {\n type CellPort,\n connectRuntime,\n linkOverPort,\n serveHandlerOverPort,\n serveRuntime,\n} from \"./transport/port.js\";\nexport {\n type CellsWebSocketClass,\n createWebSocketClass,\n type WebSocketConnector,\n} from \"./ws/client.js\";\nexport { CellsResponse, takeClientPort, WebSocketPair } from \"./ws/server.js\";\n"]}
|
package/dist/isolate/browser.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/isolate/browser.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/isolate/browser.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAGjD;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAOrC;IACC,MAAM,WAAW,GAAG,CAAC,EAAU,EAAE,EAAE,CACjC,GAAG,IAAI,CAAC,aAAa,IAAI,SAAS,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACtE,OAAO,oBAAoB,CAAC;QAC1B,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,KAAK,EAAE,GAAG,EAAE;YACV,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC7D,OAAO,EAAE,IAAI,EAAE,CAAwB,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC;QAC5E,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,EAAU,EAAE,IAAgB,EAAE,EAAE;YAC9C,IAAI,CAAC,IAAI,CAAC,WAAW;gBACnB,OAAO;oBACL,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,UAAU,EAAE,IAAI,CAAC,UAAU;oBAC3B,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC;iBACpB,CAAC;YACb,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,GAAG,CAAC;YACxF,MAAM,GAAG,GAAG,kBAAkB,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAChD,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBACrD,MAAM,eAAe,CAAC,GAAG,IAAI,cAAc,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;YAC/D,CAAC;YACD,OAAO;gBACL,GAAG,EAAE,GAAG,IAAI,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE;gBAChD,SAAS,EAAE,WAAW,EAAE,EAAE;gBAC1B,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC;aACpB,CAAC;QACb,CAAC;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { ModuleLoader, WorkerCode } from \"../bindings/worker-loader.js\";\nimport type { CellStorage } from \"../ports.js\";\nimport { putLoadedModule } from \"../project/site-loader.js\";\nimport { isolatedModuleLoader } from \"./host.js\";\nimport type { PortLike } from \"./protocol.js\";\n\n/**\n * Isolated loading in browsers: each loaded Worker runs in its own Dedicated Worker\n * (`isolateScript`, e.g. src/isolate/isolate-worker.ts). With `siteBaseUrl` (the in-browser\n * HTTP server, docs/browser-host.md) its modules are uploaded and imported from URLs; otherwise they\n * travel to the isolate and become Blob-URL modules there.\n */\nexport function browserIsolatedLoader(opts: {\n isolateScript: URL;\n siteBaseUrl?: string;\n /** Prefix of the OPFS SQLite pool each isolate keeps its facets in (one pool per loaded id). */\n storagePrefix?: string;\n /** The host's storage: facets of loaded code are logged and restored through it. */\n storage?: () => CellStorage | undefined;\n}): ModuleLoader {\n const storageName = (id: string) =>\n `${opts.storagePrefix ?? \"isolate\"}-${id}`.replace(/[^\\w.-]/g, \"_\");\n return isolatedModuleLoader({\n storage: opts.storage,\n spawn: () => {\n const w = new Worker(opts.isolateScript, { type: \"module\" });\n return { port: w as unknown as PortLike, terminate: () => w.terminate() };\n },\n prepare: async (id: string, code: WorkerCode) => {\n if (!opts.siteBaseUrl)\n return {\n modules: code.modules,\n mainModule: code.mainModule,\n storageName: storageName(id),\n } as never;\n const base = opts.siteBaseUrl.endsWith(\"/\") ? opts.siteBaseUrl : `${opts.siteBaseUrl}/`;\n const dir = encodeURIComponent(`isolate-${id}`);\n for (const [name, m] of Object.entries(code.modules)) {\n await putLoadedModule(`${base}loaded-src/${dir}/${name}`, m);\n }\n return {\n url: `${base}loaded/${dir}/~/${code.mainModule}`,\n consoleId: `isolate-${id}`,\n storageName: storageName(id),\n } as never;\n },\n });\n}\n"]}
|
package/dist/isolate/host.d.ts
CHANGED
|
@@ -21,4 +21,8 @@ export declare function isolatedModuleLoader(opts: {
|
|
|
21
21
|
source?: string;
|
|
22
22
|
url?: string;
|
|
23
23
|
}>;
|
|
24
|
-
}):
|
|
24
|
+
}): IsolatedModuleLoader;
|
|
25
|
+
/** A Worker Loader's module loader whose isolates end with `close()`. */
|
|
26
|
+
export type IsolatedModuleLoader = ModuleLoader & {
|
|
27
|
+
close(): void;
|
|
28
|
+
};
|
package/dist/isolate/host.js
CHANGED
|
@@ -8,7 +8,9 @@ import { hostPort } from "./protocol.js";
|
|
|
8
8
|
* loader for `getDurableObjectClass` (see `workerLoader(load, { classes })`).
|
|
9
9
|
*/
|
|
10
10
|
export function isolatedModuleLoader(opts) {
|
|
11
|
-
|
|
11
|
+
// Every isolate this loader started: `close()` ends them (a project runtime's close does).
|
|
12
|
+
const isolates = new Set();
|
|
13
|
+
const load = async (id, code, logs) => {
|
|
12
14
|
// The env crosses as any call does: bindings and other stubs by reference.
|
|
13
15
|
const env = { ...code.env };
|
|
14
16
|
// The loaded code's global fetch(): blocked in the isolate, or sent back here to the Fetcher.
|
|
@@ -16,7 +18,11 @@ export function isolatedModuleLoader(opts) {
|
|
|
16
18
|
const outbound = code.globalOutbound === null ? "blocked" : fetcher ? "fetcher" : undefined;
|
|
17
19
|
const where = await opts.prepare(id, code);
|
|
18
20
|
const isolate = opts.spawn(id);
|
|
19
|
-
const
|
|
21
|
+
const running = {
|
|
22
|
+
terminate: () => isolate.terminate(),
|
|
23
|
+
};
|
|
24
|
+
isolates.add(running);
|
|
25
|
+
const { call, fetch, closeSockets } = await hostPort(isolate.port, async (m) => {
|
|
20
26
|
if (m.type === "durable") {
|
|
21
27
|
const st = opts.storage?.() ?? {};
|
|
22
28
|
if (m.op === "load")
|
|
@@ -38,6 +44,7 @@ export function isolatedModuleLoader(opts) {
|
|
|
38
44
|
console[m.level](...m.args);
|
|
39
45
|
}
|
|
40
46
|
}, fetcher);
|
|
47
|
+
running.closeSockets = closeSockets;
|
|
41
48
|
const exports = await call({
|
|
42
49
|
type: "load",
|
|
43
50
|
...where,
|
|
@@ -66,9 +73,18 @@ export function isolatedModuleLoader(opts) {
|
|
|
66
73
|
call: (cellKey, method, args) => call({ type: "object", op: "call", className, cellKey, method, args }),
|
|
67
74
|
restart: (cellKey) => call({ type: "object", op: "restart", className, cellKey }),
|
|
68
75
|
delete: (cellKey) => call({ type: "object", op: "delete", className, cellKey }),
|
|
69
|
-
attach: (cellKey, epoch) => call({ type: "object", op: "attach", className, cellKey, epoch }),
|
|
76
|
+
attach: (cellKey, epoch, idName) => call({ type: "object", op: "attach", className, cellKey, epoch, idName }),
|
|
70
77
|
});
|
|
71
78
|
return module;
|
|
72
79
|
};
|
|
80
|
+
return Object.assign(load, {
|
|
81
|
+
close() {
|
|
82
|
+
for (const isolate of isolates) {
|
|
83
|
+
isolate.closeSockets?.(); // its sockets' clients hear 1001 before the isolate ends
|
|
84
|
+
isolate.terminate();
|
|
85
|
+
}
|
|
86
|
+
isolates.clear();
|
|
87
|
+
},
|
|
88
|
+
});
|
|
73
89
|
}
|
|
74
90
|
//# sourceMappingURL=host.js.map
|
package/dist/isolate/host.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/isolate/host.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,aAAa,GAEd,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAsB,MAAM,oBAAoB,CAAC;AAElE,OAAO,EAAE,QAAQ,EAAiB,MAAM,eAAe,CAAC;AAExD;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAQpC;IACC,
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/isolate/host.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type LogSink,\n type ModuleLoader,\n outboundFetch,\n type WorkerCode,\n} from \"../bindings/worker-loader.js\";\nimport { ISOLATED, type IsolatedClass } from \"../core/handles.js\";\nimport type { CellStorage } from \"../ports.js\";\nimport { hostPort, type PortLike } from \"./protocol.js\";\n\n/**\n * Worker Loader whose code runs in a separate realm per loaded Worker (an isolate). Returns\n * a module facade: each export is an object whose `fetch()` and methods cross the port.\n * Durable Object classes cannot cross (their storage API is synchronous): use an in-realm\n * loader for `getDurableObjectClass` (see `workerLoader(load, { classes })`).\n */\nexport function isolatedModuleLoader(opts: {\n /**\n * The host's storage, so facets of loaded code are logged and restored like the root's\n * own (celld: one stream per facet under the root, the root's epoch).\n */\n storage?: () => CellStorage | undefined;\n spawn(id: string): { port: PortLike; terminate(): void };\n prepare(id: string, code: WorkerCode): Promise<{ source?: string; url?: string }>;\n}): IsolatedModuleLoader {\n // Every isolate this loader started: `close()` ends them (a project runtime's close does).\n const isolates = new Set<{ terminate(): void; closeSockets?(): void }>();\n const load = async (id: string, code: WorkerCode, logs?: LogSink) => {\n // The env crosses as any call does: bindings and other stubs by reference.\n const env: Record<string, unknown> = { ...code.env };\n // The loaded code's global fetch(): blocked in the isolate, or sent back here to the Fetcher.\n const fetcher = outboundFetch(code);\n const outbound = code.globalOutbound === null ? \"blocked\" : fetcher ? \"fetcher\" : undefined;\n const where = await opts.prepare(id, code);\n const isolate = opts.spawn(id);\n const running: { terminate(): void; closeSockets?(): void } = {\n terminate: () => isolate.terminate(),\n };\n isolates.add(running);\n const { call, fetch, closeSockets } = await hostPort(\n isolate.port,\n async (m) => {\n if (m.type === \"durable\") {\n const st = opts.storage?.() ?? {};\n if (m.op === \"load\") return st.backup?.load?.(m.cellKey);\n if (m.op === \"committed\" && st.durability) {\n const info = m.info;\n const token = info.image;\n await st.durability.committed(m.cellKey, {\n ...info,\n image:\n typeof token === \"number\"\n ? () => call<Uint8Array | undefined>({ type: \"image\", token })\n : token,\n });\n }\n return;\n }\n if (m.type === \"log\") {\n logs?.(m.level, m.args);\n (console as any)[m.level](...m.args);\n }\n },\n fetcher,\n );\n running.closeSockets = closeSockets;\n const exports = await call<Record<string, string>>({\n type: \"load\",\n ...where,\n env,\n outbound,\n });\n const facade = (name: string) =>\n new Proxy(\n {},\n {\n get(_t, prop) {\n if (prop === \"then\" || typeof prop === \"symbol\") return undefined;\n // Called as a plain-object entrypoint (entrypointStub): `ctx` comes last, after `env`\n // (the isolate has its own); its props cross with the call.\n if (prop === \"fetch\")\n return (req: Request, _env: unknown, ctx?: { props?: unknown }) =>\n fetch({ name, props: ctx?.props }, req);\n return (...args: unknown[]) => {\n const ctx = args.pop() as { props?: unknown };\n args.pop();\n return call({ type: \"call\", name, method: prop, args, props: ctx.props });\n };\n },\n },\n );\n const module: Record<string | symbol, unknown> = Object.fromEntries(\n Object.keys(exports).map((k) => [k, facade(k)]),\n );\n // Durable Object classes of the loaded code run in the isolate too (facets).\n module[ISOLATED] = (className: string): IsolatedClass => ({\n fetch: (cellKey, req) => fetch({ className, cellKey }, req),\n call: (cellKey, method, args) =>\n call({ type: \"object\", op: \"call\", className, cellKey, method, args }),\n restart: (cellKey) => call({ type: \"object\", op: \"restart\", className, cellKey }),\n delete: (cellKey) => call({ type: \"object\", op: \"delete\", className, cellKey }),\n attach: (cellKey, epoch, idName) =>\n call({ type: \"object\", op: \"attach\", className, cellKey, epoch, idName }),\n });\n return module as Record<string, unknown>;\n };\n return Object.assign(load, {\n close() {\n for (const isolate of isolates) {\n isolate.closeSockets?.(); // its sockets' clients hear 1001 before the isolate ends\n isolate.terminate();\n }\n isolates.clear();\n },\n });\n}\n\n/** A Worker Loader's module loader whose isolates end with `close()`. */\nexport type IsolatedModuleLoader = ModuleLoader & { close(): void };\n"]}
|
|
@@ -5,7 +5,7 @@ import { sahpoolOpener } from "../adapters/wasm-sqlite.js";
|
|
|
5
5
|
import { browserModuleLoader, PROJECT_WORKERS_MODULE_SHIM } from "../project/browser-modules.js";
|
|
6
6
|
import * as emailModule from "../project/cloudflare-email.js";
|
|
7
7
|
import * as workersModule from "../project/cloudflare-workers.js";
|
|
8
|
-
import { workersHostRegistry } from "../project/site.js";
|
|
8
|
+
import { workersHostRegistry } from "../project/site-loader.js";
|
|
9
9
|
import { realmWorkerScope } from "../project/worker-scope.js";
|
|
10
10
|
import * as workersGlobals from "../project/workers-globals-module.js";
|
|
11
11
|
import { serveIsolate } from "./isolate.js";
|
|
@@ -24,6 +24,16 @@ workersHostRegistry({
|
|
|
24
24
|
Request: workersGlobals.CellsRequest,
|
|
25
25
|
Response: workersGlobals.CellsResponse,
|
|
26
26
|
});
|
|
27
|
+
// This worker is the loaded Worker's realm: its globals are the Workers ones (as on Node,
|
|
28
|
+
// src/isolate/node-entry.ts). Loaded code reads them as free names (partyserver builds its
|
|
29
|
+
// `new WebSocketPair()` and its 101 `Response` that way).
|
|
30
|
+
Object.assign(globalThis, {
|
|
31
|
+
Request: workersGlobals.CellsRequest,
|
|
32
|
+
Response: workersGlobals.CellsResponse,
|
|
33
|
+
WebSocket: workersGlobals.WebSocket,
|
|
34
|
+
WebSocketPair: workersGlobals.WebSocketPair,
|
|
35
|
+
WebSocketRequestResponsePair: workersGlobals.WebSocketRequestResponsePair,
|
|
36
|
+
});
|
|
27
37
|
// The global console is left alone (the dev server's client logs here too): loaded modules
|
|
28
38
|
// get a console of their own that reports to the host.
|
|
29
39
|
serveIsolate(self, async (load, logs) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isolate-worker.js","sourceRoot":"","sources":["../../src/isolate/isolate-worker.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,iFAAiF;AAEjF,OAAO,iBAAiB,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AACjG,OAAO,KAAK,WAAW,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,aAAa,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"isolate-worker.js","sourceRoot":"","sources":["../../src/isolate/isolate-worker.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference lib=\"webworker\" />\n// One loaded Worker in its own realm (a Dedicated Worker), served over its port.\n\nimport sqlite3InitModule from \"@sqlite.org/sqlite-wasm\";\nimport { sahpoolOpener } from \"../adapters/wasm-sqlite.js\";\nimport { browserModuleLoader, PROJECT_WORKERS_MODULE_SHIM } from \"../project/browser-modules.js\";\nimport * as emailModule from \"../project/cloudflare-email.js\";\nimport * as workersModule from \"../project/cloudflare-workers.js\";\nimport { workersHostRegistry } from \"../project/site-loader.js\";\nimport { realmWorkerScope } from \"../project/worker-scope.js\";\nimport * as workersGlobals from \"../project/workers-globals-module.js\";\nimport { serveIsolate } from \"./isolate.js\";\nimport type { PortLike } from \"./protocol.js\";\n\n(globalThis as Record<string, unknown>).__cellsWorkersModule = workersModule;\n// The loaded Worker's own `env` and `exports` (serveIsolate binds the realm's scope to them).\nconst scope = realmWorkerScope();\nworkersHostRegistry({\n workersModule: {\n ...workersModule,\n env: scope.env,\n exports: scope.exports,\n waitUntil: scope.waitUntil,\n },\n emailModule,\n ...workersGlobals,\n Request: workersGlobals.CellsRequest,\n Response: workersGlobals.CellsResponse,\n});\n\n// This worker is the loaded Worker's realm: its globals are the Workers ones (as on Node,\n// src/isolate/node-entry.ts). Loaded code reads them as free names (partyserver builds its\n// `new WebSocketPair()` and its 101 `Response` that way).\nObject.assign(globalThis, {\n Request: workersGlobals.CellsRequest,\n Response: workersGlobals.CellsResponse,\n WebSocket: workersGlobals.WebSocket,\n WebSocketPair: workersGlobals.WebSocketPair,\n WebSocketRequestResponsePair: workersGlobals.WebSocketRequestResponsePair,\n});\n\n// The global console is left alone (the dev server's client logs here too): loaded modules\n// get a console of their own that reports to the host.\nserveIsolate(\n self as unknown as PortLike,\n async (load: any, logs) => {\n const own = Object.assign(Object.create(console), {\n log: (...a: unknown[]) => logs(\"log\", a),\n info: (...a: unknown[]) => logs(\"info\", a),\n warn: (...a: unknown[]) => logs(\"warn\", a),\n error: (...a: unknown[]) => logs(\"error\", a),\n debug: (...a: unknown[]) => logs(\"debug\", a),\n });\n if (load.url) {\n // The site's per-id module server binds `console` to __cellsLoadedConsoles[id].\n const g = globalThis as Record<string, any>;\n g.__cellsLoadedConsoles ??= {};\n g.__cellsLoadedConsoles[load.consoleId] = own;\n return (await import(/* @vite-ignore */ load.url)) as Record<string, unknown>;\n }\n return browserModuleLoader(PROJECT_WORKERS_MODULE_SHIM)(\n \"isolate\",\n { mainModule: load.mainModule, modules: load.modules },\n (level, args) => logs(level, args),\n );\n },\n {\n patchConsole: false,\n // Facets of the loaded code: SQLite on OPFS, one sahpool per loaded Worker.\n openSql: async (load: any) => {\n const sqlite3 = await (sqlite3InitModule as any)({ print() {}, printErr() {} });\n return sahpoolOpener(sqlite3, { name: load?.storageName ?? \"isolate\" });\n },\n },\n);\n"]}
|
package/dist/isolate/isolate.js
CHANGED
|
@@ -87,6 +87,12 @@ export function serveIsolate(port, importCode, opts = {}) {
|
|
|
87
87
|
vars: env, // the loaded Worker's env: plain values and host stubs
|
|
88
88
|
storage: { durability, backup, ownership },
|
|
89
89
|
facets: true, // rows move to this run's scope on open, as celld does for facets
|
|
90
|
+
ctxIdOf: (key) => {
|
|
91
|
+
const name = idNames.get(key);
|
|
92
|
+
return name === undefined
|
|
93
|
+
? undefined
|
|
94
|
+
: rt.env[className].idFromName(name);
|
|
95
|
+
},
|
|
90
96
|
});
|
|
91
97
|
runtimes.set(className, rt);
|
|
92
98
|
}
|
|
@@ -96,6 +102,10 @@ export function serveIsolate(port, importCode, opts = {}) {
|
|
|
96
102
|
let exports = {};
|
|
97
103
|
// The loaded Worker is this realm's own: its `cloudflare:workers` reads `env` and `exports` here.
|
|
98
104
|
const scope = realmWorkerScope();
|
|
105
|
+
// The name of the `id` a facet was given by `ctx.facets.get`, by its isolate-local cell key:
|
|
106
|
+
// the facet's `ctx.id` (partyserver's `this.name`). Two facets may be given the same id; each
|
|
107
|
+
// keeps its own object and storage, addressed by the parent's facet cell key.
|
|
108
|
+
const idNames = new Map();
|
|
99
109
|
// A facet of loaded code: the object lives here, named by the parent's facet cell key.
|
|
100
110
|
const facet = async (className, cellKey) => {
|
|
101
111
|
const rt = await objectRuntime(className);
|
|
@@ -140,6 +150,8 @@ export function serveIsolate(port, importCode, opts = {}) {
|
|
|
140
150
|
const { rt, stub, key } = await facet(m.className, m.cellKey);
|
|
141
151
|
if (m.op === "attach") {
|
|
142
152
|
facetKeys.set(key, { key: m.cellKey, epoch: m.epoch });
|
|
153
|
+
if (typeof m.idName === "string")
|
|
154
|
+
idNames.set(key, m.idName);
|
|
143
155
|
return;
|
|
144
156
|
}
|
|
145
157
|
if (m.op === "call")
|