@statewalker/cellb 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +323 -2
- package/dist/adapters/files-backup.d.ts +16 -0
- package/dist/adapters/files-backup.js +32 -0
- package/dist/adapters/files-backup.js.map +1 -0
- package/dist/adapters/files-changelog.d.ts +33 -0
- package/dist/adapters/files-changelog.js +96 -0
- package/dist/adapters/files-changelog.js.map +1 -0
- package/dist/adapters/files-ltx.d.ts +35 -0
- package/dist/adapters/files-ltx.js +9 -0
- package/dist/adapters/files-ltx.js.map +1 -0
- package/dist/adapters/ltx-vfs.d.ts +21 -0
- package/dist/adapters/ltx-vfs.js +286 -0
- package/dist/adapters/ltx-vfs.js.map +1 -0
- package/dist/adapters/node-sqlite.d.ts +45 -0
- package/dist/adapters/node-sqlite.js +254 -0
- package/dist/adapters/node-sqlite.js.map +1 -0
- package/dist/adapters/wasm-page-hook.d.ts +26 -0
- package/dist/adapters/wasm-page-hook.js +55 -0
- package/dist/adapters/wasm-page-hook.js.map +1 -0
- package/dist/adapters/wasm-session.d.ts +11 -0
- package/dist/adapters/wasm-session.js +76 -0
- package/dist/adapters/wasm-session.js.map +1 -0
- package/dist/adapters/wasm-sqlite.d.ts +89 -0
- package/dist/adapters/wasm-sqlite.js +258 -0
- package/dist/adapters/wasm-sqlite.js.map +1 -0
- package/dist/bindings/assets.d.ts +26 -0
- package/dist/bindings/assets.js +260 -0
- package/dist/bindings/assets.js.map +1 -0
- package/dist/bindings/cache.d.ts +16 -0
- package/dist/bindings/cache.js +34 -0
- package/dist/bindings/cache.js.map +1 -0
- package/dist/bindings/celld-kv.d.ts +26 -0
- package/dist/bindings/celld-kv.js +81 -0
- package/dist/bindings/celld-kv.js.map +1 -0
- package/dist/bindings/celld-queues.d.ts +56 -0
- package/dist/bindings/celld-queues.js +223 -0
- package/dist/bindings/celld-queues.js.map +1 -0
- package/dist/bindings/celld-workflows.d.ts +22 -0
- package/dist/bindings/celld-workflows.js +54 -0
- package/dist/bindings/celld-workflows.js.map +1 -0
- package/dist/bindings/cron.d.ts +27 -0
- package/dist/bindings/cron.js +232 -0
- package/dist/bindings/cron.js.map +1 -0
- package/dist/bindings/d1-migrations.d.ts +22 -0
- package/dist/bindings/d1-migrations.js +32 -0
- package/dist/bindings/d1-migrations.js.map +1 -0
- package/dist/bindings/html-rewriter.d.ts +8 -0
- package/dist/bindings/html-rewriter.js +75 -0
- package/dist/bindings/html-rewriter.js.map +1 -0
- package/dist/bindings/r2-celld.d.ts +3 -0
- package/dist/bindings/r2-celld.js +113 -0
- package/dist/bindings/r2-celld.js.map +1 -0
- package/dist/bindings/r2.d.ts +236 -0
- package/dist/bindings/r2.js +419 -0
- package/dist/bindings/r2.js.map +1 -0
- package/dist/bindings/worker-loader.d.ts +83 -0
- package/dist/bindings/worker-loader.js +183 -0
- package/dist/bindings/worker-loader.js.map +1 -0
- package/dist/bindings/workers-ai.d.ts +39 -0
- package/dist/bindings/workers-ai.js +175 -0
- package/dist/bindings/workers-ai.js.map +1 -0
- package/dist/browser.d.ts +7 -0
- package/dist/browser.js +8 -0
- package/dist/browser.js.map +1 -0
- package/dist/bucket/celld-cells.d.ts +86 -0
- package/dist/bucket/celld-cells.js +273 -0
- package/dist/bucket/celld-cells.js.map +1 -0
- package/dist/bucket/celld-format.d.ts +10 -0
- package/dist/bucket/celld-format.js +27 -0
- package/dist/bucket/celld-format.js.map +1 -0
- package/dist/bucket/idb-object-store.d.ts +9 -0
- package/dist/bucket/idb-object-store.js +73 -0
- package/dist/bucket/idb-object-store.js.map +1 -0
- package/dist/bucket/ltx-log.d.ts +34 -0
- package/dist/bucket/ltx-log.js +289 -0
- package/dist/bucket/ltx-log.js.map +1 -0
- package/dist/bucket/object-store.d.ts +51 -0
- package/dist/bucket/object-store.js +114 -0
- package/dist/bucket/object-store.js.map +1 -0
- package/dist/bucket/s3-object-store.d.ts +25 -0
- package/dist/bucket/s3-object-store.js +151 -0
- package/dist/bucket/s3-object-store.js.map +1 -0
- package/dist/bucket/sqlite-object-store.d.ts +10 -0
- package/dist/bucket/sqlite-object-store.js +107 -0
- package/dist/bucket/sqlite-object-store.js.map +1 -0
- package/dist/core/alarms.d.ts +27 -0
- package/dist/core/alarms.js +88 -0
- package/dist/core/alarms.js.map +1 -0
- package/dist/core/async-context.d.ts +34 -0
- package/dist/core/async-context.js +50 -0
- package/dist/core/async-context.js.map +1 -0
- package/dist/core/celld-schema.d.ts +14 -0
- package/dist/core/celld-schema.js +34 -0
- package/dist/core/celld-schema.js.map +1 -0
- package/dist/core/durable-object.d.ts +28 -0
- package/dist/core/durable-object.js +31 -0
- package/dist/core/durable-object.js.map +1 -0
- package/dist/core/gates.d.ts +33 -0
- package/dist/core/gates.js +89 -0
- package/dist/core/gates.js.map +1 -0
- package/dist/core/handles.d.ts +90 -0
- package/dist/core/handles.js +224 -0
- package/dist/core/handles.js.map +1 -0
- package/dist/core/id.d.ts +19 -0
- package/dist/core/id.js +64 -0
- package/dist/core/id.js.map +1 -0
- package/dist/core/namespace.d.ts +38 -0
- package/dist/core/namespace.js +141 -0
- package/dist/core/namespace.js.map +1 -0
- package/dist/core/object-host.d.ts +91 -0
- package/dist/core/object-host.js +616 -0
- package/dist/core/object-host.js.map +1 -0
- package/dist/core/request-body.d.ts +9 -0
- package/dist/core/request-body.js +55 -0
- package/dist/core/request-body.js.map +1 -0
- package/dist/core/runtime.d.ts +121 -0
- package/dist/core/runtime.js +366 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/core/shard.d.ts +7 -0
- package/dist/core/shard.js +10 -0
- package/dist/core/shard.js.map +1 -0
- package/dist/core/sql-split.d.ts +15 -0
- package/dist/core/sql-split.js +101 -0
- package/dist/core/sql-split.js.map +1 -0
- package/dist/core/sql-storage.d.ts +53 -0
- package/dist/core/sql-storage.js +407 -0
- package/dist/core/sql-storage.js.map +1 -0
- package/dist/core/state.d.ts +44 -0
- package/dist/core/state.js +93 -0
- package/dist/core/state.js.map +1 -0
- package/dist/core/storage.d.ts +103 -0
- package/dist/core/storage.js +351 -0
- package/dist/core/storage.js.map +1 -0
- package/dist/core/worker-rejections.d.ts +21 -0
- package/dist/core/worker-rejections.js +55 -0
- package/dist/core/worker-rejections.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/isolate/browser.d.ts +16 -0
- package/dist/isolate/browser.js +37 -0
- package/dist/isolate/browser.js.map +1 -0
- package/dist/isolate/host.d.ts +24 -0
- package/dist/isolate/host.js +74 -0
- package/dist/isolate/host.js.map +1 -0
- package/dist/isolate/isolate-worker.d.ts +1 -0
- package/dist/isolate/isolate-worker.js +53 -0
- package/dist/isolate/isolate-worker.js.map +1 -0
- package/dist/isolate/isolate.d.ts +10 -0
- package/dist/isolate/isolate.js +169 -0
- package/dist/isolate/isolate.js.map +1 -0
- package/dist/isolate/node-entry.d.ts +1 -0
- package/dist/isolate/node-entry.js +12 -0
- package/dist/isolate/node-entry.js.map +1 -0
- package/dist/isolate/protocol.d.ts +66 -0
- package/dist/isolate/protocol.js +205 -0
- package/dist/isolate/protocol.js.map +1 -0
- package/dist/ltx/crc64.d.ts +6 -0
- package/dist/ltx/crc64.js +46 -0
- package/dist/ltx/crc64.js.map +1 -0
- package/dist/ltx/ltx-page-server.d.ts +65 -0
- package/dist/ltx/ltx-page-server.js +309 -0
- package/dist/ltx/ltx-page-server.js.map +1 -0
- package/dist/ltx/ltx-pages.d.ts +81 -0
- package/dist/ltx/ltx-pages.js +315 -0
- package/dist/ltx/ltx-pages.js.map +1 -0
- package/dist/ltx/ltx-store-worker.d.ts +1 -0
- package/dist/ltx/ltx-store-worker.js +38 -0
- package/dist/ltx/ltx-store-worker.js.map +1 -0
- package/dist/ltx/ltx.d.ts +45 -0
- package/dist/ltx/ltx.js +203 -0
- package/dist/ltx/ltx.js.map +1 -0
- package/dist/ltx/lz4.d.ts +9 -0
- package/dist/ltx/lz4.js +156 -0
- package/dist/ltx/lz4.js.map +1 -0
- package/dist/ltx/opfs-sync-files.d.ts +23 -0
- package/dist/ltx/opfs-sync-files.js +191 -0
- package/dist/ltx/opfs-sync-files.js.map +1 -0
- package/dist/ltx/xxh32.d.ts +1 -0
- package/dist/ltx/xxh32.js +43 -0
- package/dist/ltx/xxh32.js.map +1 -0
- package/dist/miniflare-compat/blob-service.d.ts +13 -0
- package/dist/miniflare-compat/blob-service.js +66 -0
- package/dist/miniflare-compat/blob-service.js.map +1 -0
- package/dist/miniflare-compat/kv-binding.d.ts +44 -0
- package/dist/miniflare-compat/kv-binding.js +99 -0
- package/dist/miniflare-compat/kv-binding.js.map +1 -0
- package/dist/miniflare-compat/shims/assert.d.ts +15 -0
- package/dist/miniflare-compat/shims/assert.js +24 -0
- package/dist/miniflare-compat/shims/assert.js.map +1 -0
- package/dist/miniflare-compat/shims/workerd-cloudflare.d.ts +7 -0
- package/dist/miniflare-compat/shims/workerd-cloudflare.js +6 -0
- package/dist/miniflare-compat/shims/workerd-cloudflare.js.map +1 -0
- package/dist/miniflare-compat/shims/workerd-globals.d.ts +1 -0
- package/dist/miniflare-compat/shims/workerd-globals.js +30 -0
- package/dist/miniflare-compat/shims/workerd-globals.js.map +1 -0
- package/dist/miniflare-compat/shims/workerd-internal.d.ts +20 -0
- package/dist/miniflare-compat/shims/workerd-internal.js +23 -0
- package/dist/miniflare-compat/shims/workerd-internal.js.map +1 -0
- package/dist/miniflare-compat/shims/workerd-performance.d.ts +4 -0
- package/dist/miniflare-compat/shims/workerd-performance.js +17 -0
- package/dist/miniflare-compat/shims/workerd-performance.js.map +1 -0
- package/dist/miniflare-compat/simulator-fetcher.d.ts +9 -0
- package/dist/miniflare-compat/simulator-fetcher.js +14 -0
- package/dist/miniflare-compat/simulator-fetcher.js.map +1 -0
- package/dist/miniflare-compat/vendored.d.ts +15 -0
- package/dist/miniflare-compat/vendored.js +27 -0
- package/dist/miniflare-compat/vendored.js.map +1 -0
- package/dist/node-compat/async_hooks.d.ts +22 -0
- package/dist/node-compat/async_hooks.js +176 -0
- package/dist/node-compat/async_hooks.js.map +1 -0
- package/dist/node-compat/browser-registry.d.ts +3 -0
- package/dist/node-compat/browser-registry.js +39 -0
- package/dist/node-compat/browser-registry.js.map +1 -0
- package/dist/node-compat/crypto.d.ts +60 -0
- package/dist/node-compat/crypto.js +143 -0
- package/dist/node-compat/crypto.js.map +1 -0
- package/dist/node-compat/diagnostics_channel.d.ts +27 -0
- package/dist/node-compat/diagnostics_channel.js +46 -0
- package/dist/node-compat/diagnostics_channel.js.map +1 -0
- package/dist/node-compat/fs.d.ts +35 -0
- package/dist/node-compat/fs.js +40 -0
- package/dist/node-compat/fs.js.map +1 -0
- package/dist/node-compat/globals.d.ts +3 -0
- package/dist/node-compat/globals.js +4 -0
- package/dist/node-compat/globals.js.map +1 -0
- package/dist/node-compat/install.d.ts +5 -0
- package/dist/node-compat/install.js +12 -0
- package/dist/node-compat/install.js.map +1 -0
- package/dist/node-compat/module.d.ts +12 -0
- package/dist/node-compat/module.js +36 -0
- package/dist/node-compat/module.js.map +1 -0
- package/dist/node-compat/modules.d.ts +8 -0
- package/dist/node-compat/modules.js +23 -0
- package/dist/node-compat/modules.js.map +1 -0
- package/dist/node-compat/os.d.ts +36 -0
- package/dist/node-compat/os.js +36 -0
- package/dist/node-compat/os.js.map +1 -0
- package/dist/node-compat/process.d.ts +14 -0
- package/dist/node-compat/process.js +16 -0
- package/dist/node-compat/process.js.map +1 -0
- package/dist/node-compat/shims.d.ts +4 -0
- package/dist/node.d.ts +5 -0
- package/dist/node.js +6 -0
- package/dist/node.js.map +1 -0
- package/dist/peer/celld-peer.d.ts +53 -0
- package/dist/peer/celld-peer.js +555 -0
- package/dist/peer/celld-peer.js.map +1 -0
- package/dist/ports.d.ts +183 -0
- package/dist/ports.js +10 -0
- package/dist/ports.js.map +1 -0
- package/dist/project/browser-bundle.d.ts +17 -0
- package/dist/project/browser-bundle.js +125 -0
- package/dist/project/browser-bundle.js.map +1 -0
- package/dist/project/browser-cookies.d.ts +12 -0
- package/dist/project/browser-cookies.js +90 -0
- package/dist/project/browser-cookies.js.map +1 -0
- package/dist/project/browser-host.d.ts +173 -0
- package/dist/project/browser-host.js +200 -0
- package/dist/project/browser-host.js.map +1 -0
- package/dist/project/browser-modules.d.ts +17 -0
- package/dist/project/browser-modules.js +89 -0
- package/dist/project/browser-modules.js.map +1 -0
- package/dist/project/browser-shards.d.ts +62 -0
- package/dist/project/browser-shards.js +210 -0
- package/dist/project/browser-shards.js.map +1 -0
- package/dist/project/browser-tabs.d.ts +103 -0
- package/dist/project/browser-tabs.js +418 -0
- package/dist/project/browser-tabs.js.map +1 -0
- package/dist/project/cloudflare-email.d.ts +8 -0
- package/dist/project/cloudflare-email.js +11 -0
- package/dist/project/cloudflare-email.js.map +1 -0
- package/dist/project/cloudflare-workers.d.ts +12 -0
- package/dist/project/cloudflare-workers.js +16 -0
- package/dist/project/cloudflare-workers.js.map +1 -0
- package/dist/project/host-modules.d.ts +4 -0
- package/dist/project/host-modules.js +40 -0
- package/dist/project/host-modules.js.map +1 -0
- package/dist/project/jsonc.d.ts +2 -0
- package/dist/project/jsonc.js +27 -0
- package/dist/project/jsonc.js.map +1 -0
- package/dist/project/lower-await.d.ts +2 -0
- package/dist/project/lower-await.js +151 -0
- package/dist/project/lower-await.js.map +1 -0
- package/dist/project/node-project.d.ts +38 -0
- package/dist/project/node-project.js +362 -0
- package/dist/project/node-project.js.map +1 -0
- package/dist/project/own-module.d.ts +6 -0
- package/dist/project/own-module.js +13 -0
- package/dist/project/own-module.js.map +1 -0
- package/dist/project/scheduler.d.ts +2 -0
- package/dist/project/scheduler.js +3 -0
- package/dist/project/scheduler.js.map +1 -0
- package/dist/project/site.d.ts +74 -0
- package/dist/project/site.js +206 -0
- package/dist/project/site.js.map +1 -0
- package/dist/project/virtual-modules.d.ts +3 -0
- package/dist/project/worker-scope.d.ts +27 -0
- package/dist/project/worker-scope.js +46 -0
- package/dist/project/worker-scope.js.map +1 -0
- package/dist/project/workerd-message-channel.d.ts +13 -0
- package/dist/project/workerd-message-channel.js +137 -0
- package/dist/project/workerd-message-channel.js.map +1 -0
- package/dist/project/workers-global-names.d.ts +6 -0
- package/dist/project/workers-global-names.js +15 -0
- package/dist/project/workers-global-names.js.map +1 -0
- package/dist/project/workers-globals-module.d.ts +8 -0
- package/dist/project/workers-globals-module.js +9 -0
- package/dist/project/workers-globals-module.js.map +1 -0
- package/dist/project/workers-globals.d.ts +9 -0
- package/dist/project/workers-globals.js +19 -0
- package/dist/project/workers-globals.js.map +1 -0
- package/dist/project/wrangler.d.ts +116 -0
- package/dist/project/wrangler.js +342 -0
- package/dist/project/wrangler.js.map +1 -0
- package/dist/router/cell-router.d.ts +72 -0
- package/dist/router/cell-router.js +247 -0
- package/dist/router/cell-router.js.map +1 -0
- package/dist/router/shard-worker.d.ts +44 -0
- package/dist/router/shard-worker.js +163 -0
- package/dist/router/shard-worker.js.map +1 -0
- package/dist/transport/cells-http.d.ts +25 -0
- package/dist/transport/cells-http.js +141 -0
- package/dist/transport/cells-http.js.map +1 -0
- package/dist/transport/cells-link.d.ts +27 -0
- package/dist/transport/cells-link.js +71 -0
- package/dist/transport/cells-link.js.map +1 -0
- package/dist/transport/port.d.ts +26 -0
- package/dist/transport/port.js +100 -0
- package/dist/transport/port.js.map +1 -0
- package/dist/v8/codec.d.ts +6 -0
- package/dist/v8/codec.js +9 -0
- package/dist/v8/codec.js.map +1 -0
- package/dist/v8/serialize.d.ts +10 -0
- package/dist/v8/serialize.js +601 -0
- package/dist/v8/serialize.js.map +1 -0
- package/dist/ws/client.d.ts +25 -0
- package/dist/ws/client.js +203 -0
- package/dist/ws/client.js.map +1 -0
- package/dist/ws/control.d.ts +48 -0
- package/dist/ws/control.js +44 -0
- package/dist/ws/control.js.map +1 -0
- package/dist/ws/frames.d.ts +38 -0
- package/dist/ws/frames.js +39 -0
- package/dist/ws/frames.js.map +1 -0
- package/dist/ws/server.d.ts +99 -0
- package/dist/ws/server.js +295 -0
- package/dist/ws/server.js.map +1 -0
- package/dist/ws/sw-connector.d.ts +10 -0
- package/dist/ws/sw-connector.js +25 -0
- package/dist/ws/sw-connector.js.map +1 -0
- package/dist/ws/upgrade.d.ts +28 -0
- package/dist/ws/upgrade.js +75 -0
- package/dist/ws/upgrade.js.map +1 -0
- package/package.json +111 -3
- package/vendor/celld/LICENSE +202 -0
- package/vendor/celld/kv.js +1131 -0
- package/vendor/celld/queues.js +1656 -0
- package/vendor/celld/workflows.js +1610 -0
- package/vendor/html-rewriter-wasm/html_rewriter.js +925 -0
- package/vendor/html-rewriter-wasm/html_rewriter_bg.wasm +0 -0
- package/vendor/miniflare/d1-api.js +738 -0
- package/vendor/miniflare/d1-database.js +6978 -0
- package/vendor/miniflare/kv-namespace.js +3061 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/core/state.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InputGate } from \"./gates.js\";\nimport type { DurableObjectId } from \"./id.js\";\nimport type { DurableObjectStorage } from \"./storage.js\";\n\n/** `ctx` passed to a Durable Object constructor. */\nexport class DurableObjectState {\n /** Not readonly: an object woken by id alone gets its recorded name back (celld). */\n id: DurableObjectId;\n readonly storage: DurableObjectStorage;\n readonly #gate: InputGate;\n readonly #waitUntil: (p: Promise<unknown>) => void;\n\n readonly #onBlockFailure: (e: unknown) => void;\n constructor(\n id: DurableObjectId,\n storage: DurableObjectStorage,\n gate: InputGate,\n waitUntil: (p: Promise<unknown>) => void,\n onBlockFailure: (e: unknown) => void = () => {},\n ) {\n this.#onBlockFailure = onBlockFailure;\n this.id = id;\n this.storage = storage;\n this.#gate = gate;\n this.#waitUntil = waitUntil;\n }\n /** Open blockConcurrencyWhile() sections (nested ones are open together). */\n #blockDepth = 0;\n /** No event is delivered to the object until `fn` settles. */\n blockConcurrencyWhile<T>(fn: () => Promise<T>): Promise<T> {\n // As workerd (io-context.h) and celld: at most 64 nested sections; the next throws at once.\n if (this.#blockDepth >= 64)\n throw new Error(\"blockConcurrencyWhile() calls are nested too deeply.\");\n this.#blockDepth++;\n const p = this.#gate.runClosed(fn).finally(() => this.#blockDepth--);\n // A failure resets the object even when the caller (typically the\n // constructor) does not await the promise; the rejection is then observed.\n p.catch((e) => this.#onBlockFailure(e));\n return p;\n }\n waitUntil(p: Promise<unknown>): void {\n this.#waitUntil(p);\n }\n\n /** `ctx.exports`: loopback handles of the Worker's exports (set by the host). */\n exports: Record<string, unknown> = {};\n /** `ctx.props`: what a facet's class handle was given as `{ props }` (set by the host). */\n props: unknown;\n /** `ctx.facets`: child objects with their own SQLite (set by the host). */\n facets!: {\n get(name: string, start: () => unknown): Record<string, any>;\n abort(name: string, reason?: unknown): void;\n delete(name: string): Promise<void>;\n };\n\n // ---- WebSocket hibernation API ------------------------------------------------\n // Sockets accepted here belong to the RUNTIME, not to the object instance: their\n // events are delivered as object events (through the input gate) to\n // webSocketMessage / webSocketClose / webSocketError on whatever instance is live.\n\n #dispatch?: (fn: (instance: any) => unknown) => Promise<unknown>;\n readonly #sockets = new Map<WebSocketLike, string[]>();\n #autoResponse?: { request: string; response: string };\n\n /** Set by the ObjectHost: delivers an event to the live instance. */\n attachDispatcher(dispatch: (fn: (instance: any) => unknown) => Promise<unknown>): void {\n this.#dispatch = dispatch;\n }\n\n acceptWebSocket(ws: WebSocketLike, tags: string[] = []): void {\n if (this.#sockets.has(ws)) throw new Error(\"WebSocket already accepted\");\n if (tags.length > 10) throw new Error(\"A WebSocket can have at most 10 tags\");\n this.#sockets.set(ws, [...tags]);\n (ws as { hibernatable?: boolean }).hibernatable = true;\n // webSocketMessage() gets string | ArrayBuffer, whatever the pair's default binaryType.\n (ws as { binaryType?: string }).binaryType = \"arraybuffer\";\n ws.accept();\n const deliver = (fn: (o: any) => unknown) => this.#dispatch?.(fn).catch(() => {});\n ws.addEventListener(\"message\", (e: MessageEvent) => {\n const auto = this.#autoResponse;\n if (auto && e.data === auto.request) {\n ws.send(auto.response);\n return;\n }\n void deliver((o) => o.webSocketMessage?.(ws, e.data));\n });\n ws.addEventListener(\"close\", (e: CloseEvent) => {\n this.#sockets.delete(ws);\n void deliver((o) => o.webSocketClose?.(ws, e.code, e.reason, e.wasClean));\n });\n ws.addEventListener(\n \"error\",\n (e: Event) => void deliver((o) => o.webSocketError?.(ws, (e as ErrorEvent).error ?? e)),\n );\n }\n\n getWebSockets(tag?: string): WebSocketLike[] {\n return [...this.#sockets]\n .filter(([, tags]) => tag === undefined || tags.includes(tag))\n .map(([ws]) => ws);\n }\n\n getTags(ws: WebSocketLike): string[] {\n const tags = this.#sockets.get(ws);\n if (!tags) throw new Error(\"WebSocket was not accepted with acceptWebSocket()\");\n return [...tags];\n }\n\n setWebSocketAutoResponse(pair?: { request: string; response: string }): void {\n this.#autoResponse = pair;\n }\n getWebSocketAutoResponse(): { request: string; response: string } | null {\n return this.#autoResponse ?? null;\n }\n}\n\n/** The server end of a WebSocketPair, as seen by the hibernation API. */\nexport interface WebSocketLike {\n accept(): void;\n send(data: string | ArrayBuffer | ArrayBufferView): void;\n close(code?: number, reason?: string): void;\n addEventListener(type: string, fn: (e: any) => void): void;\n}\n"]}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { ValueCodec } from "../ports.js";
|
|
2
|
+
import type { InputGate } from "./gates.js";
|
|
3
|
+
import type { SqlStorage } from "./sql-storage.js";
|
|
4
|
+
export interface ListOptions {
|
|
5
|
+
start?: string;
|
|
6
|
+
startAfter?: string;
|
|
7
|
+
end?: string;
|
|
8
|
+
prefix?: string;
|
|
9
|
+
reverse?: boolean;
|
|
10
|
+
limit?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Synchronous KV API of SQLite-backed objects (`ctx.storage.kv`), stored as celld stores it:
|
|
14
|
+
* `_cf_KV(scope, k, v)` with the cell's scope and V8-serialized values (celld-schema.ts).
|
|
15
|
+
*/
|
|
16
|
+
export declare class SyncKvStorage {
|
|
17
|
+
#private;
|
|
18
|
+
readonly scope: string;
|
|
19
|
+
/** The name the object was addressed by: recorded as celld's _cf_METADATA.actor_name. */
|
|
20
|
+
actorName: string | undefined;
|
|
21
|
+
constructor(sql: SqlStorage, codec: ValueCodec, scope?: string);
|
|
22
|
+
get<T = unknown>(key: string): T | undefined;
|
|
23
|
+
put(key: string, value: unknown): void;
|
|
24
|
+
delete(key: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Only one list() iterator is live at a time, as in workerd: a new call invalidates the
|
|
27
|
+
* previous one, which throws on its next step.
|
|
28
|
+
*/
|
|
29
|
+
list<T = unknown>(opts?: ListOptions): IterableIterator<[string, T]>;
|
|
30
|
+
deleteAll(): void;
|
|
31
|
+
}
|
|
32
|
+
/** Methods shared by `ctx.storage` and the `txn` object of `transaction()`. */
|
|
33
|
+
export declare class AsyncKvApi {
|
|
34
|
+
protected kv: SyncKvStorage;
|
|
35
|
+
protected gate: InputGate;
|
|
36
|
+
constructor(kv: SyncKvStorage, gate: InputGate);
|
|
37
|
+
/** Every async storage op closes the input gate until it (and its continuation) completes. */
|
|
38
|
+
protected op<T>(fn: () => T): Promise<T>;
|
|
39
|
+
get<T = unknown>(key: string): Promise<T | undefined>;
|
|
40
|
+
get<T = unknown>(keys: string[]): Promise<Map<string, T>>;
|
|
41
|
+
put(key: string, value: unknown): Promise<void>;
|
|
42
|
+
put(entries: Record<string, unknown>): Promise<void>;
|
|
43
|
+
delete(key: string): Promise<boolean>;
|
|
44
|
+
delete(keys: string[]): Promise<number>;
|
|
45
|
+
list<T = unknown>(opts?: ListOptions): Promise<Map<string, T>>;
|
|
46
|
+
}
|
|
47
|
+
export declare class DurableObjectTransaction extends AsyncKvApi {
|
|
48
|
+
rolledBack: boolean;
|
|
49
|
+
rollback(): void;
|
|
50
|
+
}
|
|
51
|
+
/** `ctx.storage` of a SQLite-backed Durable Object. */
|
|
52
|
+
export declare class DurableObjectStorage extends AsyncKvApi {
|
|
53
|
+
#private;
|
|
54
|
+
readonly sql: SqlStorage;
|
|
55
|
+
readonly kv: SyncKvStorage;
|
|
56
|
+
constructor(sql: SqlStorage, kv: SyncKvStorage, gate: InputGate, sync: () => Promise<void>);
|
|
57
|
+
deleteAll(): Promise<void>;
|
|
58
|
+
transactionSync<T>(fn: () => T): T;
|
|
59
|
+
/**
|
|
60
|
+
* Async transaction spanning awaits: the input gate stays closed (no other
|
|
61
|
+
* event can interleave writes into the savepoint) and auto-commit is held.
|
|
62
|
+
*/
|
|
63
|
+
transaction<T>(closure: (txn: DurableObjectTransaction) => Promise<T>): Promise<T>;
|
|
64
|
+
/** Resolves once all writes so far are durable (the output gate barrier). */
|
|
65
|
+
sync(): Promise<void>;
|
|
66
|
+
/** `delete_all_preserves_alarm`: deleteAll() leaves the alarm in place. */
|
|
67
|
+
deleteAllPreservesAlarm: boolean;
|
|
68
|
+
/** celld's harness hands its storage "scope" to engine ops; here it is the storage itself. */
|
|
69
|
+
get _scope(): this;
|
|
70
|
+
/** Called whenever the stored alarm changes (the runtime schedules it). */
|
|
71
|
+
onAlarmChange: (at: number | null) => void;
|
|
72
|
+
/**
|
|
73
|
+
* The alarm row as celld keeps it (storage.rs): due time, failure counters, and a random
|
|
74
|
+
* generation that changes with every setAlarm() — so a handler's own change is detected.
|
|
75
|
+
*/
|
|
76
|
+
alarmRowSync(): {
|
|
77
|
+
at: number;
|
|
78
|
+
retry: number;
|
|
79
|
+
counted: number;
|
|
80
|
+
generation: string;
|
|
81
|
+
} | null;
|
|
82
|
+
beginAlarm(row: {
|
|
83
|
+
generation: string;
|
|
84
|
+
}): void;
|
|
85
|
+
/**
|
|
86
|
+
* After the handler (celld's finish_alarm_handler): unless the handler changed the alarm,
|
|
87
|
+
* success deletes it and failure reschedules it with backoff (2 s << min(retry, 6)) —
|
|
88
|
+
* abandoned after 6 counted failures. Returns the alarm now stored.
|
|
89
|
+
*/
|
|
90
|
+
finishAlarm(fired: {
|
|
91
|
+
at: number;
|
|
92
|
+
generation: string;
|
|
93
|
+
}, succeeded: boolean, now: number): number | null;
|
|
94
|
+
/** Synchronous read of the stored alarm (ms since epoch) or null (null while it is handled). */
|
|
95
|
+
alarmSync(): number | null;
|
|
96
|
+
/** One alarm per object, in celld's `_cf_ALARM` (same transaction as the event's writes). */
|
|
97
|
+
getAlarm(_opts?: unknown): Promise<number | null>;
|
|
98
|
+
setAlarm(scheduledTime: number | Date, _opts?: unknown): Promise<void>;
|
|
99
|
+
/** setAlarm() inside a synchronous transaction (celld's harness ops). */
|
|
100
|
+
setAlarmSync(at: number): void;
|
|
101
|
+
deleteAlarm(_opts?: unknown): Promise<void>;
|
|
102
|
+
clearAlarmSync(): void;
|
|
103
|
+
}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { serialize } from "../v8/serialize.js";
|
|
2
|
+
import { CELLD_SCHEMA } from "./celld-schema.js";
|
|
3
|
+
/** `EXPORT` of core/handles.ts, by its registered name: importing handles.ts here is a cycle. */
|
|
4
|
+
const EXPORT = Symbol.for("cellb.export");
|
|
5
|
+
const withoutStoredStubs = (v) => v && typeof v === "object" && v[EXPORT]
|
|
6
|
+
? null
|
|
7
|
+
: Array.isArray(v)
|
|
8
|
+
? v.map(withoutStoredStubs)
|
|
9
|
+
: v && Object.getPrototypeOf(v) === Object.prototype
|
|
10
|
+
? Object.fromEntries(Object.entries(v).map(([k, x]) => [k, withoutStoredStubs(x)]))
|
|
11
|
+
: v;
|
|
12
|
+
/**
|
|
13
|
+
* Synchronous KV API of SQLite-backed objects (`ctx.storage.kv`), stored as celld stores it:
|
|
14
|
+
* `_cf_KV(scope, k, v)` with the cell's scope and V8-serialized values (celld-schema.ts).
|
|
15
|
+
*/
|
|
16
|
+
export class SyncKvStorage {
|
|
17
|
+
#sql;
|
|
18
|
+
#codec;
|
|
19
|
+
#ready = false;
|
|
20
|
+
scope;
|
|
21
|
+
/** The name the object was addressed by: recorded as celld's _cf_METADATA.actor_name. */
|
|
22
|
+
actorName;
|
|
23
|
+
constructor(sql, codec, scope = "") {
|
|
24
|
+
this.#sql = sql;
|
|
25
|
+
this.#codec = codec;
|
|
26
|
+
this.scope = scope;
|
|
27
|
+
sql.rolledBack.add(() => {
|
|
28
|
+
this.#ready = false; // the table may have been created inside the rolled-back transaction
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
#init() {
|
|
32
|
+
if (this.#ready)
|
|
33
|
+
return;
|
|
34
|
+
for (const ddl of CELLD_SCHEMA)
|
|
35
|
+
this.#sql.internalExec(ddl);
|
|
36
|
+
if (this.actorName !== undefined)
|
|
37
|
+
this.#sql.internalExec("INSERT OR IGNORE INTO _cf_METADATA (scope, actor_name) VALUES (?, ?)", [this.scope, this.actorName]);
|
|
38
|
+
this.#ready = true;
|
|
39
|
+
}
|
|
40
|
+
get(key) {
|
|
41
|
+
this.#init();
|
|
42
|
+
const r = this.#sql.internalExec("SELECT v FROM _cf_KV WHERE scope = ? AND k = ?", [
|
|
43
|
+
this.scope,
|
|
44
|
+
key,
|
|
45
|
+
]);
|
|
46
|
+
if (!r.rows.length)
|
|
47
|
+
return undefined;
|
|
48
|
+
return this.#codec.decode(new Uint8Array(r.rows[0][0]));
|
|
49
|
+
}
|
|
50
|
+
put(key, value) {
|
|
51
|
+
this.#init();
|
|
52
|
+
// As celld: `undefined` is a storable value; what structured clone refuses is a TypeError.
|
|
53
|
+
// ctx.exports.X({ props }) stubs are left to the codec, which stores them (workerd).
|
|
54
|
+
try {
|
|
55
|
+
structuredClone(withoutStoredStubs(value));
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
// Worded as V8 (workerd, celld) words it, by cellb's V8 serializer: SpiderMonkey says
|
|
59
|
+
// "Function object could not be cloned." for V8's "() => 1 could not be cloned.".
|
|
60
|
+
try {
|
|
61
|
+
serialize(withoutStoredStubs(value));
|
|
62
|
+
}
|
|
63
|
+
catch (v8) {
|
|
64
|
+
throw new TypeError(v8.message);
|
|
65
|
+
}
|
|
66
|
+
// Browsers prefix the engine message ("Failed to execute 'structuredClone' on …: ").
|
|
67
|
+
throw new TypeError(e.message.replace(/^Failed to execute '[^']+' on '[^']+': /, ""));
|
|
68
|
+
}
|
|
69
|
+
this.#sql.internalExec("INSERT OR REPLACE INTO _cf_KV (scope, k, v) VALUES (?, ?, ?)", [
|
|
70
|
+
this.scope,
|
|
71
|
+
key,
|
|
72
|
+
this.#codec.encode(value),
|
|
73
|
+
]);
|
|
74
|
+
}
|
|
75
|
+
delete(key) {
|
|
76
|
+
this.#init();
|
|
77
|
+
return (this.#sql.internalExec("DELETE FROM _cf_KV WHERE scope = ? AND k = ?", [this.scope, key])
|
|
78
|
+
.rowsWritten > 0);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Only one list() iterator is live at a time, as in workerd: a new call invalidates the
|
|
82
|
+
* previous one, which throws on its next step.
|
|
83
|
+
*/
|
|
84
|
+
list(opts = {}) {
|
|
85
|
+
const generation = ++this.#listGeneration;
|
|
86
|
+
const live = () => {
|
|
87
|
+
if (generation !== this.#listGeneration)
|
|
88
|
+
throw new Error("kv.list() iterator was invalidated because a new call to kv.list() was started. " +
|
|
89
|
+
"Only one kv.list() iterator can exist at a time.");
|
|
90
|
+
};
|
|
91
|
+
const rows = this.#rows(opts);
|
|
92
|
+
return (function* () {
|
|
93
|
+
live();
|
|
94
|
+
for (const row of rows) {
|
|
95
|
+
yield row;
|
|
96
|
+
live();
|
|
97
|
+
}
|
|
98
|
+
})();
|
|
99
|
+
}
|
|
100
|
+
#listGeneration = 0;
|
|
101
|
+
*#rows(opts) {
|
|
102
|
+
this.#init();
|
|
103
|
+
const where = ["scope = ?"];
|
|
104
|
+
const params = [this.scope];
|
|
105
|
+
if (opts.start !== undefined)
|
|
106
|
+
where.push("k >= ?"), params.push(opts.start);
|
|
107
|
+
if (opts.startAfter !== undefined)
|
|
108
|
+
where.push("k > ?"), params.push(opts.startAfter);
|
|
109
|
+
if (opts.end !== undefined)
|
|
110
|
+
where.push("k < ?"), params.push(opts.end);
|
|
111
|
+
if (opts.prefix !== undefined)
|
|
112
|
+
where.push("substr(k, 1, ?) = ?"), params.push(opts.prefix.length, opts.prefix);
|
|
113
|
+
let q = "SELECT k, v FROM _cf_KV";
|
|
114
|
+
q += ` WHERE ${where.join(" AND ")}`;
|
|
115
|
+
q += ` ORDER BY k ${opts.reverse ? "DESC" : "ASC"}`;
|
|
116
|
+
if (opts.limit !== undefined)
|
|
117
|
+
(q += " LIMIT ?"), params.push(opts.limit);
|
|
118
|
+
for (const [k, v] of this.#sql.internalExec(q, params).rows)
|
|
119
|
+
yield [k, this.#codec.decode(new Uint8Array(v))];
|
|
120
|
+
}
|
|
121
|
+
deleteAll() {
|
|
122
|
+
this.#init();
|
|
123
|
+
this.#sql.internalExec("DELETE FROM _cf_KV WHERE scope = ?", [this.scope]);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/** Methods shared by `ctx.storage` and the `txn` object of `transaction()`. */
|
|
127
|
+
export class AsyncKvApi {
|
|
128
|
+
kv;
|
|
129
|
+
gate;
|
|
130
|
+
constructor(kv, gate) {
|
|
131
|
+
this.kv = kv;
|
|
132
|
+
this.gate = gate;
|
|
133
|
+
}
|
|
134
|
+
/** Every async storage op closes the input gate until it (and its continuation) completes. */
|
|
135
|
+
op(fn) {
|
|
136
|
+
return this.gate.runClosed(async () => {
|
|
137
|
+
await Promise.resolve();
|
|
138
|
+
return fn();
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
get(keyOrKeys) {
|
|
142
|
+
return this.op(() => {
|
|
143
|
+
if (!Array.isArray(keyOrKeys))
|
|
144
|
+
return this.kv.get(keyOrKeys);
|
|
145
|
+
checkKeys(keyOrKeys);
|
|
146
|
+
const m = new Map();
|
|
147
|
+
for (const k of [...keyOrKeys].sort()) {
|
|
148
|
+
const v = this.kv.get(k);
|
|
149
|
+
if (v !== undefined)
|
|
150
|
+
m.set(k, v);
|
|
151
|
+
}
|
|
152
|
+
return m;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
put(keyOrEntries, value) {
|
|
156
|
+
return this.op(() => {
|
|
157
|
+
if (typeof keyOrEntries === "string")
|
|
158
|
+
return this.kv.put(keyOrEntries, value);
|
|
159
|
+
const entries = Object.entries(keyOrEntries);
|
|
160
|
+
checkKeys(entries.map(([k]) => k));
|
|
161
|
+
for (const [k, v] of entries)
|
|
162
|
+
this.kv.put(k, v);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
delete(keyOrKeys) {
|
|
166
|
+
return this.op(() => {
|
|
167
|
+
if (!Array.isArray(keyOrKeys))
|
|
168
|
+
return this.kv.delete(keyOrKeys);
|
|
169
|
+
checkKeys(keyOrKeys);
|
|
170
|
+
return keyOrKeys.filter((k) => this.kv.delete(k)).length;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
list(opts) {
|
|
174
|
+
return this.op(() => new Map(this.kv.list(opts)));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// celld sets no limit on the number of keys of one get/put/delete (storage-details).
|
|
178
|
+
function checkKeys(_keys) { }
|
|
179
|
+
export class DurableObjectTransaction extends AsyncKvApi {
|
|
180
|
+
rolledBack = false;
|
|
181
|
+
rollback() {
|
|
182
|
+
this.rolledBack = true;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** `ctx.storage` of a SQLite-backed Durable Object. */
|
|
186
|
+
export class DurableObjectStorage extends AsyncKvApi {
|
|
187
|
+
sql;
|
|
188
|
+
kv;
|
|
189
|
+
#sync;
|
|
190
|
+
constructor(sql, kv, gate, sync) {
|
|
191
|
+
super(kv, gate);
|
|
192
|
+
this.sql = sql;
|
|
193
|
+
sql.rolledBack.add(() => {
|
|
194
|
+
this.#metaReady = false;
|
|
195
|
+
});
|
|
196
|
+
this.kv = kv;
|
|
197
|
+
this.#sync = sync;
|
|
198
|
+
}
|
|
199
|
+
deleteAll() {
|
|
200
|
+
return this.op(() => {
|
|
201
|
+
this.kv.deleteAll();
|
|
202
|
+
// deleteAll() also deletes the alarm, as on Cloudflare, unless `delete_all_preserves_alarm`.
|
|
203
|
+
if (!this.deleteAllPreservesAlarm)
|
|
204
|
+
this.clearAlarmSync();
|
|
205
|
+
const tables = this.sql.internalExec("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE '\\_cf\\_%' ESCAPE '\\' AND name NOT LIKE 'sqlite\\_%' ESCAPE '\\'").rows;
|
|
206
|
+
for (const [name] of tables)
|
|
207
|
+
this.sql.internalExec(`DROP TABLE IF EXISTS "${String(name).replace(/"/g, '""')}"`);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
transactionSync(fn) {
|
|
211
|
+
return this.sql.transactionSync(fn);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Async transaction spanning awaits: the input gate stays closed (no other
|
|
215
|
+
* event can interleave writes into the savepoint) and auto-commit is held.
|
|
216
|
+
*/
|
|
217
|
+
transaction(closure) {
|
|
218
|
+
return this.gate.runClosed(async () => {
|
|
219
|
+
const release = this.sql.hold();
|
|
220
|
+
const sp = "_cf_atx";
|
|
221
|
+
this.sql.internalExec(`SAVEPOINT ${sp}`);
|
|
222
|
+
const txn = new DurableObjectTransaction(this.kv, this.gate);
|
|
223
|
+
try {
|
|
224
|
+
const r = await closure(txn);
|
|
225
|
+
if (txn.rolledBack)
|
|
226
|
+
this.#rollbackTo(sp);
|
|
227
|
+
else
|
|
228
|
+
this.sql.internalExec(`RELEASE ${sp}`);
|
|
229
|
+
return r;
|
|
230
|
+
}
|
|
231
|
+
catch (e) {
|
|
232
|
+
this.#rollbackTo(sp);
|
|
233
|
+
throw e;
|
|
234
|
+
}
|
|
235
|
+
finally {
|
|
236
|
+
release();
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
#rollbackTo(sp) {
|
|
241
|
+
this.sql.internalExec(`ROLLBACK TO ${sp}`);
|
|
242
|
+
this.sql.internalExec(`RELEASE ${sp}`);
|
|
243
|
+
for (const f of this.sql.rolledBack)
|
|
244
|
+
f(); // tables created inside may be gone
|
|
245
|
+
}
|
|
246
|
+
/** Resolves once all writes so far are durable (the output gate barrier). */
|
|
247
|
+
sync() {
|
|
248
|
+
return this.#sync();
|
|
249
|
+
}
|
|
250
|
+
/** `delete_all_preserves_alarm`: deleteAll() leaves the alarm in place. */
|
|
251
|
+
deleteAllPreservesAlarm = false;
|
|
252
|
+
/** celld's harness hands its storage "scope" to engine ops; here it is the storage itself. */
|
|
253
|
+
get _scope() {
|
|
254
|
+
return this;
|
|
255
|
+
}
|
|
256
|
+
/** Called whenever the stored alarm changes (the runtime schedules it). */
|
|
257
|
+
onAlarmChange = () => { };
|
|
258
|
+
#metaReady = false;
|
|
259
|
+
#meta() {
|
|
260
|
+
if (this.#metaReady)
|
|
261
|
+
return;
|
|
262
|
+
for (const ddl of CELLD_SCHEMA)
|
|
263
|
+
this.sql.internalExec(ddl);
|
|
264
|
+
if (this.kv.actorName !== undefined)
|
|
265
|
+
this.sql.internalExec("INSERT OR IGNORE INTO _cf_METADATA (scope, actor_name) VALUES (?, ?)", [this.kv.scope, this.kv.actorName]);
|
|
266
|
+
this.#metaReady = true;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* The alarm row as celld keeps it (storage.rs): due time, failure counters, and a random
|
|
270
|
+
* generation that changes with every setAlarm() — so a handler's own change is detected.
|
|
271
|
+
*/
|
|
272
|
+
alarmRowSync() {
|
|
273
|
+
this.#meta();
|
|
274
|
+
const r = this.sql.internalExec(
|
|
275
|
+
// generation is a 64-bit random(): read as text (beyond JS's safe integers)
|
|
276
|
+
"SELECT at_ms, retry, counted_retry, CAST(generation AS TEXT) FROM _cf_ALARM WHERE scope = ?", [this.kv.scope]).rows[0];
|
|
277
|
+
return r
|
|
278
|
+
? { at: Number(r[0]), retry: Number(r[1]), counted: Number(r[2]), generation: String(r[3]) }
|
|
279
|
+
: null;
|
|
280
|
+
}
|
|
281
|
+
/** The alarm being handled: getAlarm() reads null until the handler changes the alarm. */
|
|
282
|
+
#active;
|
|
283
|
+
beginAlarm(row) {
|
|
284
|
+
this.#active = { generation: row.generation };
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* After the handler (celld's finish_alarm_handler): unless the handler changed the alarm,
|
|
288
|
+
* success deletes it and failure reschedules it with backoff (2 s << min(retry, 6)) —
|
|
289
|
+
* abandoned after 6 counted failures. Returns the alarm now stored.
|
|
290
|
+
*/
|
|
291
|
+
finishAlarm(fired, succeeded, now) {
|
|
292
|
+
this.#active = undefined;
|
|
293
|
+
const cur = this.alarmRowSync();
|
|
294
|
+
if (!cur || cur.generation !== fired.generation)
|
|
295
|
+
return cur?.at ?? null;
|
|
296
|
+
if (succeeded) {
|
|
297
|
+
this.sql.internalExec("DELETE FROM _cf_ALARM WHERE scope = ? AND at_ms = ?", [
|
|
298
|
+
this.kv.scope,
|
|
299
|
+
fired.at,
|
|
300
|
+
]);
|
|
301
|
+
}
|
|
302
|
+
else if (cur.counted >= 6) {
|
|
303
|
+
this.sql.internalExec("DELETE FROM _cf_ALARM WHERE scope = ?", [this.kv.scope]);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
const at = now + 2_000 * 2 ** Math.min(Math.max(cur.retry, 0), 6);
|
|
307
|
+
this.sql.internalExec("UPDATE _cf_ALARM SET at_ms = ?, retry = retry + 1, counted_retry = counted_retry + 1 WHERE scope = ?", [at, this.kv.scope]);
|
|
308
|
+
}
|
|
309
|
+
const after = this.alarmRowSync()?.at ?? null;
|
|
310
|
+
this.onAlarmChange(after);
|
|
311
|
+
return after;
|
|
312
|
+
}
|
|
313
|
+
/** Synchronous read of the stored alarm (ms since epoch) or null (null while it is handled). */
|
|
314
|
+
alarmSync() {
|
|
315
|
+
const row = this.alarmRowSync();
|
|
316
|
+
if (row && this.#active && this.#active.generation === row.generation)
|
|
317
|
+
return null;
|
|
318
|
+
return row ? row.at : null;
|
|
319
|
+
}
|
|
320
|
+
/** One alarm per object, in celld's `_cf_ALARM` (same transaction as the event's writes). */
|
|
321
|
+
getAlarm(_opts) {
|
|
322
|
+
return this.op(() => this.alarmSync());
|
|
323
|
+
}
|
|
324
|
+
setAlarm(scheduledTime, _opts) {
|
|
325
|
+
// As celld: the time is coerced to a number and a non-number becomes 0 (due at once).
|
|
326
|
+
const n = scheduledTime instanceof Date ? scheduledTime.getTime() : Number(scheduledTime);
|
|
327
|
+
const at = Number.isNaN(n) ? 0 : n;
|
|
328
|
+
return this.op(() => {
|
|
329
|
+
this.#meta();
|
|
330
|
+
this.sql.internalExec(
|
|
331
|
+
// celld's statement: counters reset, a new random generation
|
|
332
|
+
"INSERT INTO _cf_ALARM(scope,at_ms,retry,counted_retry,generation) VALUES(?,?,0,0,random()) ON CONFLICT(scope) DO UPDATE SET at_ms=excluded.at_ms, retry=0, counted_retry=0, generation=random()", [this.kv.scope, at]);
|
|
333
|
+
this.onAlarmChange(at);
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
/** setAlarm() inside a synchronous transaction (celld's harness ops). */
|
|
337
|
+
setAlarmSync(at) {
|
|
338
|
+
this.#meta();
|
|
339
|
+
this.sql.internalExec("INSERT INTO _cf_ALARM(scope,at_ms,retry,counted_retry,generation) VALUES(?,?,0,0,random()) ON CONFLICT(scope) DO UPDATE SET at_ms=excluded.at_ms, retry=0, counted_retry=0, generation=random()", [this.kv.scope, at]);
|
|
340
|
+
this.onAlarmChange(at);
|
|
341
|
+
}
|
|
342
|
+
deleteAlarm(_opts) {
|
|
343
|
+
return this.op(() => this.clearAlarmSync());
|
|
344
|
+
}
|
|
345
|
+
clearAlarmSync() {
|
|
346
|
+
this.#meta();
|
|
347
|
+
this.sql.internalExec("DELETE FROM _cf_ALARM WHERE scope = ?", [this.kv.scope]);
|
|
348
|
+
this.onAlarmChange(null);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/core/storage.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ValueCodec } from \"../ports.js\";\nimport { serialize } from \"../v8/serialize.js\";\nimport { CELLD_SCHEMA } from \"./celld-schema.js\";\nimport type { InputGate } from \"./gates.js\";\nimport type { SqlStorage } from \"./sql-storage.js\";\n\nexport interface ListOptions {\n start?: string;\n startAfter?: string;\n end?: string;\n prefix?: string;\n reverse?: boolean;\n limit?: number;\n}\n\n/** `EXPORT` of core/handles.ts, by its registered name: importing handles.ts here is a cycle. */\nconst EXPORT = Symbol.for(\"cellb.export\");\nconst withoutStoredStubs = (v: unknown): unknown =>\n v && typeof v === \"object\" && (v as Record<symbol, unknown>)[EXPORT]\n ? null\n : Array.isArray(v)\n ? v.map(withoutStoredStubs)\n : v && Object.getPrototypeOf(v) === Object.prototype\n ? Object.fromEntries(Object.entries(v).map(([k, x]) => [k, withoutStoredStubs(x)]))\n : v;\n\n/**\n * Synchronous KV API of SQLite-backed objects (`ctx.storage.kv`), stored as celld stores it:\n * `_cf_KV(scope, k, v)` with the cell's scope and V8-serialized values (celld-schema.ts).\n */\nexport class SyncKvStorage {\n #sql: SqlStorage;\n #codec: ValueCodec;\n #ready = false;\n readonly scope: string;\n /** The name the object was addressed by: recorded as celld's _cf_METADATA.actor_name. */\n actorName: string | undefined;\n\n constructor(sql: SqlStorage, codec: ValueCodec, scope = \"\") {\n this.#sql = sql;\n this.#codec = codec;\n this.scope = scope;\n sql.rolledBack.add(() => {\n this.#ready = false; // the table may have been created inside the rolled-back transaction\n });\n }\n #init(): void {\n if (this.#ready) return;\n for (const ddl of CELLD_SCHEMA) this.#sql.internalExec(ddl);\n if (this.actorName !== undefined)\n this.#sql.internalExec(\n \"INSERT OR IGNORE INTO _cf_METADATA (scope, actor_name) VALUES (?, ?)\",\n [this.scope, this.actorName],\n );\n this.#ready = true;\n }\n get<T = unknown>(key: string): T | undefined {\n this.#init();\n const r = this.#sql.internalExec(\"SELECT v FROM _cf_KV WHERE scope = ? AND k = ?\", [\n this.scope,\n key,\n ]);\n if (!r.rows.length) return undefined;\n return this.#codec.decode(new Uint8Array(r.rows[0][0] as ArrayBuffer)) as T;\n }\n put(key: string, value: unknown): void {\n this.#init();\n // As celld: `undefined` is a storable value; what structured clone refuses is a TypeError.\n // ctx.exports.X({ props }) stubs are left to the codec, which stores them (workerd).\n try {\n structuredClone(withoutStoredStubs(value));\n } catch (e) {\n // Worded as V8 (workerd, celld) words it, by cellb's V8 serializer: SpiderMonkey says\n // \"Function object could not be cloned.\" for V8's \"() => 1 could not be cloned.\".\n try {\n serialize(withoutStoredStubs(value));\n } catch (v8) {\n throw new TypeError((v8 as Error).message);\n }\n // Browsers prefix the engine message (\"Failed to execute 'structuredClone' on …: \").\n throw new TypeError(\n (e as Error).message.replace(/^Failed to execute '[^']+' on '[^']+': /, \"\"),\n );\n }\n this.#sql.internalExec(\"INSERT OR REPLACE INTO _cf_KV (scope, k, v) VALUES (?, ?, ?)\", [\n this.scope,\n key,\n this.#codec.encode(value),\n ]);\n }\n delete(key: string): boolean {\n this.#init();\n return (\n this.#sql.internalExec(\"DELETE FROM _cf_KV WHERE scope = ? AND k = ?\", [this.scope, key])\n .rowsWritten > 0\n );\n }\n /**\n * Only one list() iterator is live at a time, as in workerd: a new call invalidates the\n * previous one, which throws on its next step.\n */\n list<T = unknown>(opts: ListOptions = {}): IterableIterator<[string, T]> {\n const generation = ++this.#listGeneration;\n const live = () => {\n if (generation !== this.#listGeneration)\n throw new Error(\n \"kv.list() iterator was invalidated because a new call to kv.list() was started. \" +\n \"Only one kv.list() iterator can exist at a time.\",\n );\n };\n const rows = this.#rows<T>(opts);\n return (function* () {\n live();\n for (const row of rows) {\n yield row;\n live();\n }\n })();\n }\n #listGeneration = 0;\n *#rows<T>(opts: ListOptions): IterableIterator<[string, T]> {\n this.#init();\n const where: string[] = [\"scope = ?\"];\n const params: unknown[] = [this.scope];\n if (opts.start !== undefined) where.push(\"k >= ?\"), params.push(opts.start);\n if (opts.startAfter !== undefined) where.push(\"k > ?\"), params.push(opts.startAfter);\n if (opts.end !== undefined) where.push(\"k < ?\"), params.push(opts.end);\n if (opts.prefix !== undefined)\n where.push(\"substr(k, 1, ?) = ?\"), params.push(opts.prefix.length, opts.prefix);\n let q = \"SELECT k, v FROM _cf_KV\";\n q += ` WHERE ${where.join(\" AND \")}`;\n q += ` ORDER BY k ${opts.reverse ? \"DESC\" : \"ASC\"}`;\n if (opts.limit !== undefined) (q += \" LIMIT ?\"), params.push(opts.limit);\n for (const [k, v] of this.#sql.internalExec(q, params).rows)\n yield [k as string, this.#codec.decode(new Uint8Array(v as ArrayBuffer)) as T];\n }\n deleteAll(): void {\n this.#init();\n this.#sql.internalExec(\"DELETE FROM _cf_KV WHERE scope = ?\", [this.scope]);\n }\n}\n\n/** Methods shared by `ctx.storage` and the `txn` object of `transaction()`. */\nexport class AsyncKvApi {\n protected kv: SyncKvStorage;\n protected gate: InputGate;\n constructor(kv: SyncKvStorage, gate: InputGate) {\n this.kv = kv;\n this.gate = gate;\n }\n /** Every async storage op closes the input gate until it (and its continuation) completes. */\n protected op<T>(fn: () => T): Promise<T> {\n return this.gate.runClosed(async () => {\n await Promise.resolve();\n return fn();\n });\n }\n get<T = unknown>(key: string): Promise<T | undefined>;\n get<T = unknown>(keys: string[]): Promise<Map<string, T>>;\n get(keyOrKeys: string | string[]): Promise<unknown> {\n return this.op(() => {\n if (!Array.isArray(keyOrKeys)) return this.kv.get(keyOrKeys);\n checkKeys(keyOrKeys);\n const m = new Map<string, unknown>();\n for (const k of [...keyOrKeys].sort()) {\n const v = this.kv.get(k);\n if (v !== undefined) m.set(k, v);\n }\n return m;\n });\n }\n put(key: string, value: unknown): Promise<void>;\n put(entries: Record<string, unknown>): Promise<void>;\n put(keyOrEntries: string | Record<string, unknown>, value?: unknown): Promise<void> {\n return this.op(() => {\n if (typeof keyOrEntries === \"string\") return this.kv.put(keyOrEntries, value);\n const entries = Object.entries(keyOrEntries);\n checkKeys(entries.map(([k]) => k));\n for (const [k, v] of entries) this.kv.put(k, v);\n });\n }\n delete(key: string): Promise<boolean>;\n delete(keys: string[]): Promise<number>;\n delete(keyOrKeys: string | string[]): Promise<boolean | number> {\n return this.op(() => {\n if (!Array.isArray(keyOrKeys)) return this.kv.delete(keyOrKeys);\n checkKeys(keyOrKeys);\n return keyOrKeys.filter((k) => this.kv.delete(k)).length;\n });\n }\n list<T = unknown>(opts?: ListOptions): Promise<Map<string, T>> {\n return this.op(() => new Map(this.kv.list<T>(opts)));\n }\n}\n\n// celld sets no limit on the number of keys of one get/put/delete (storage-details).\nfunction checkKeys(_keys: string[]): void {}\n\nexport class DurableObjectTransaction extends AsyncKvApi {\n rolledBack = false;\n rollback(): void {\n this.rolledBack = true;\n }\n}\n\n/** `ctx.storage` of a SQLite-backed Durable Object. */\nexport class DurableObjectStorage extends AsyncKvApi {\n readonly sql: SqlStorage;\n readonly kv: SyncKvStorage;\n #sync: () => Promise<void>;\n\n constructor(sql: SqlStorage, kv: SyncKvStorage, gate: InputGate, sync: () => Promise<void>) {\n super(kv, gate);\n this.sql = sql;\n sql.rolledBack.add(() => {\n this.#metaReady = false;\n });\n this.kv = kv;\n this.#sync = sync;\n }\n deleteAll(): Promise<void> {\n return this.op(() => {\n this.kv.deleteAll();\n // deleteAll() also deletes the alarm, as on Cloudflare, unless `delete_all_preserves_alarm`.\n if (!this.deleteAllPreservesAlarm) this.clearAlarmSync();\n const tables = this.sql.internalExec(\n \"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE '\\\\_cf\\\\_%' ESCAPE '\\\\' AND name NOT LIKE 'sqlite\\\\_%' ESCAPE '\\\\'\",\n ).rows;\n for (const [name] of tables)\n this.sql.internalExec(`DROP TABLE IF EXISTS \"${String(name).replace(/\"/g, '\"\"')}\"`);\n });\n }\n transactionSync<T>(fn: () => T): T {\n return this.sql.transactionSync(fn);\n }\n /**\n * Async transaction spanning awaits: the input gate stays closed (no other\n * event can interleave writes into the savepoint) and auto-commit is held.\n */\n transaction<T>(closure: (txn: DurableObjectTransaction) => Promise<T>): Promise<T> {\n return this.gate.runClosed(async () => {\n const release = this.sql.hold();\n const sp = \"_cf_atx\";\n this.sql.internalExec(`SAVEPOINT ${sp}`);\n const txn = new DurableObjectTransaction(this.kv, this.gate);\n try {\n const r = await closure(txn);\n if (txn.rolledBack) this.#rollbackTo(sp);\n else this.sql.internalExec(`RELEASE ${sp}`);\n return r;\n } catch (e) {\n this.#rollbackTo(sp);\n throw e;\n } finally {\n release();\n }\n });\n }\n #rollbackTo(sp: string): void {\n this.sql.internalExec(`ROLLBACK TO ${sp}`);\n this.sql.internalExec(`RELEASE ${sp}`);\n for (const f of this.sql.rolledBack) f(); // tables created inside may be gone\n }\n /** Resolves once all writes so far are durable (the output gate barrier). */\n sync(): Promise<void> {\n return this.#sync();\n }\n /** `delete_all_preserves_alarm`: deleteAll() leaves the alarm in place. */\n deleteAllPreservesAlarm = false;\n /** celld's harness hands its storage \"scope\" to engine ops; here it is the storage itself. */\n get _scope(): this {\n return this;\n }\n /** Called whenever the stored alarm changes (the runtime schedules it). */\n onAlarmChange: (at: number | null) => void = () => {};\n\n #metaReady = false;\n #meta(): void {\n if (this.#metaReady) return;\n for (const ddl of CELLD_SCHEMA) this.sql.internalExec(ddl);\n if (this.kv.actorName !== undefined)\n this.sql.internalExec(\n \"INSERT OR IGNORE INTO _cf_METADATA (scope, actor_name) VALUES (?, ?)\",\n [this.kv.scope, this.kv.actorName],\n );\n this.#metaReady = true;\n }\n /**\n * The alarm row as celld keeps it (storage.rs): due time, failure counters, and a random\n * generation that changes with every setAlarm() — so a handler's own change is detected.\n */\n alarmRowSync(): { at: number; retry: number; counted: number; generation: string } | null {\n this.#meta();\n const r = this.sql.internalExec(\n // generation is a 64-bit random(): read as text (beyond JS's safe integers)\n \"SELECT at_ms, retry, counted_retry, CAST(generation AS TEXT) FROM _cf_ALARM WHERE scope = ?\",\n [this.kv.scope],\n ).rows[0];\n return r\n ? { at: Number(r[0]), retry: Number(r[1]), counted: Number(r[2]), generation: String(r[3]) }\n : null;\n }\n /** The alarm being handled: getAlarm() reads null until the handler changes the alarm. */\n #active: { generation: string } | undefined;\n beginAlarm(row: { generation: string }): void {\n this.#active = { generation: row.generation };\n }\n /**\n * After the handler (celld's finish_alarm_handler): unless the handler changed the alarm,\n * success deletes it and failure reschedules it with backoff (2 s << min(retry, 6)) —\n * abandoned after 6 counted failures. Returns the alarm now stored.\n */\n finishAlarm(\n fired: { at: number; generation: string },\n succeeded: boolean,\n now: number,\n ): number | null {\n this.#active = undefined;\n const cur = this.alarmRowSync();\n if (!cur || cur.generation !== fired.generation) return cur?.at ?? null;\n if (succeeded) {\n this.sql.internalExec(\"DELETE FROM _cf_ALARM WHERE scope = ? AND at_ms = ?\", [\n this.kv.scope,\n fired.at,\n ]);\n } else if (cur.counted >= 6) {\n this.sql.internalExec(\"DELETE FROM _cf_ALARM WHERE scope = ?\", [this.kv.scope]);\n } else {\n const at = now + 2_000 * 2 ** Math.min(Math.max(cur.retry, 0), 6);\n this.sql.internalExec(\n \"UPDATE _cf_ALARM SET at_ms = ?, retry = retry + 1, counted_retry = counted_retry + 1 WHERE scope = ?\",\n [at, this.kv.scope],\n );\n }\n const after = this.alarmRowSync()?.at ?? null;\n this.onAlarmChange(after);\n return after;\n }\n /** Synchronous read of the stored alarm (ms since epoch) or null (null while it is handled). */\n alarmSync(): number | null {\n const row = this.alarmRowSync();\n if (row && this.#active && this.#active.generation === row.generation) return null;\n return row ? row.at : null;\n }\n /** One alarm per object, in celld's `_cf_ALARM` (same transaction as the event's writes). */\n getAlarm(_opts?: unknown): Promise<number | null> {\n return this.op(() => this.alarmSync());\n }\n setAlarm(scheduledTime: number | Date, _opts?: unknown): Promise<void> {\n // As celld: the time is coerced to a number and a non-number becomes 0 (due at once).\n const n = scheduledTime instanceof Date ? scheduledTime.getTime() : Number(scheduledTime);\n const at = Number.isNaN(n) ? 0 : n;\n return this.op(() => {\n this.#meta();\n this.sql.internalExec(\n // celld's statement: counters reset, a new random generation\n \"INSERT INTO _cf_ALARM(scope,at_ms,retry,counted_retry,generation) VALUES(?,?,0,0,random()) ON CONFLICT(scope) DO UPDATE SET at_ms=excluded.at_ms, retry=0, counted_retry=0, generation=random()\",\n [this.kv.scope, at],\n );\n this.onAlarmChange(at);\n });\n }\n /** setAlarm() inside a synchronous transaction (celld's harness ops). */\n setAlarmSync(at: number): void {\n this.#meta();\n this.sql.internalExec(\n \"INSERT INTO _cf_ALARM(scope,at_ms,retry,counted_retry,generation) VALUES(?,?,0,0,random()) ON CONFLICT(scope) DO UPDATE SET at_ms=excluded.at_ms, retry=0, counted_retry=0, generation=random()\",\n [this.kv.scope, at],\n );\n this.onAlarmChange(at);\n }\n deleteAlarm(_opts?: unknown): Promise<void> {\n return this.op(() => this.clearAlarmSync());\n }\n clearAlarmSync(): void {\n this.#meta();\n this.sql.internalExec(\"DELETE FROM _cf_ALARM WHERE scope = ?\", [this.kv.scope]);\n this.onAlarmChange(null);\n }\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unhandled rejections of Worker code, on Node: the Worker's, not the host process's.
|
|
3
|
+
*
|
|
4
|
+
* On workerd and celld a promise the Worker leaves rejected is the Worker's affair: workerd logs
|
|
5
|
+
* it, celld ignores it, and neither stops anything. On Node the Worker runs in the host's
|
|
6
|
+
* process, so such a rejection reached the process's own `unhandledRejection` listeners (a test
|
|
7
|
+
* runner reports it as an error; Node's default ends the process). Each Worker event now runs in
|
|
8
|
+
* a scope that names its runtime, and a rejection raised in that scope goes to the runtime's
|
|
9
|
+
* handler instead: Node calls `unhandledRejection` listeners in the async context of the
|
|
10
|
+
* rejected promise, so the scope is found there.
|
|
11
|
+
*
|
|
12
|
+
* Browsers need none of this: a Worker runs in a worker of its own there.
|
|
13
|
+
*/
|
|
14
|
+
/** Receives a Worker's unhandled rejection. */
|
|
15
|
+
export type RejectionHandler = (reason: unknown, promise: Promise<unknown>) => void;
|
|
16
|
+
/** Runs `fn` in a scope whose unhandled rejections go to `handler`. */
|
|
17
|
+
export type RejectionScope = <R>(fn: () => R) => R;
|
|
18
|
+
/** The default handler: one line on the host's stderr, outside the Worker's own console. */
|
|
19
|
+
export declare function reportToStderr(name: string): RejectionHandler;
|
|
20
|
+
/** A scope routing unhandled rejections to `handler` (on Node; elsewhere `fn` runs as is). */
|
|
21
|
+
export declare function rejectionScope(handler: RejectionHandler): RejectionScope;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unhandled rejections of Worker code, on Node: the Worker's, not the host process's.
|
|
3
|
+
*
|
|
4
|
+
* On workerd and celld a promise the Worker leaves rejected is the Worker's affair: workerd logs
|
|
5
|
+
* it, celld ignores it, and neither stops anything. On Node the Worker runs in the host's
|
|
6
|
+
* process, so such a rejection reached the process's own `unhandledRejection` listeners (a test
|
|
7
|
+
* runner reports it as an error; Node's default ends the process). Each Worker event now runs in
|
|
8
|
+
* a scope that names its runtime, and a rejection raised in that scope goes to the runtime's
|
|
9
|
+
* handler instead: Node calls `unhandledRejection` listeners in the async context of the
|
|
10
|
+
* rejected promise, so the scope is found there.
|
|
11
|
+
*
|
|
12
|
+
* Browsers need none of this: a Worker runs in a worker of its own there.
|
|
13
|
+
*/
|
|
14
|
+
const KEY = Symbol.for("cellb.workerRejections");
|
|
15
|
+
/** The scope store, installed once per process (its `process.emit` hook routes by it). */
|
|
16
|
+
function install() {
|
|
17
|
+
const g = globalThis;
|
|
18
|
+
if (g[KEY])
|
|
19
|
+
return g[KEY];
|
|
20
|
+
const proc = g.process;
|
|
21
|
+
const hooks = proc?.getBuiltinModule?.("node:async_hooks");
|
|
22
|
+
if (!proc || !hooks)
|
|
23
|
+
return undefined;
|
|
24
|
+
const scope = new hooks.AsyncLocalStorage();
|
|
25
|
+
const emit = proc.emit;
|
|
26
|
+
// `unhandledRejection` is emitted, not dispatched another way: a Worker's goes to its runtime
|
|
27
|
+
// and no further; everything else reaches the process's listeners as before.
|
|
28
|
+
proc.emit = function (event, ...args) {
|
|
29
|
+
if (event === "unhandledRejection") {
|
|
30
|
+
const handler = scope.getStore();
|
|
31
|
+
if (handler) {
|
|
32
|
+
handler(args[0], args[1]);
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return emit.call(this, event, ...args);
|
|
37
|
+
};
|
|
38
|
+
g[KEY] = scope;
|
|
39
|
+
return scope;
|
|
40
|
+
}
|
|
41
|
+
/** The default handler: one line on the host's stderr, outside the Worker's own console. */
|
|
42
|
+
export function reportToStderr(name) {
|
|
43
|
+
return (reason) => {
|
|
44
|
+
const err = reason;
|
|
45
|
+
const text = typeof err?.stack === "string" ? err.stack : String(reason);
|
|
46
|
+
const out = globalThis.process?.stderr;
|
|
47
|
+
out?.write(`[cellb] ${name}: unhandled rejection in Worker code: ${text}\n`);
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** A scope routing unhandled rejections to `handler` (on Node; elsewhere `fn` runs as is). */
|
|
51
|
+
export function rejectionScope(handler) {
|
|
52
|
+
const scope = install();
|
|
53
|
+
return scope ? (fn) => scope.run(handler, fn) : (fn) => fn();
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=worker-rejections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-rejections.js","sourceRoot":"","sources":["../../src/core/worker-rejections.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAmBH,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;AAEjD,0FAA0F;AAC1F,SAAS,OAAO;IACd,MAAM,CAAC,GAAG,UAAiE,CAAC;IAC5E,IAAI,CAAC,CAAC,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC,GAAG,CAA0B,CAAC;IACnD,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC;IACvB,MAAM,KAAK,GAAG,IAAI,EAAE,gBAAgB,EAAE,CAAC,kBAAkB,CAE5C,CAAC;IACd,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,iBAAiB,EAAoB,CAAC;IAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACvB,8FAA8F;IAC9F,6EAA6E;IAC7E,IAAI,CAAC,IAAI,GAAG,UAAyB,KAAsB,EAAE,GAAG,IAAe;QAC7E,IAAI,KAAK,KAAK,oBAAoB,EAAE,CAAC;YACnC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;YACjC,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAqB,CAAC,CAAC;gBAC9C,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC;IACzC,CAAC,CAAC;IACF,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACf,OAAO,KAAK,CAAC;AACf,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,CAAC,MAAM,EAAE,EAAE;QAChB,MAAM,GAAG,GAAG,MAA4B,CAAC;QACzC,MAAM,IAAI,GAAG,OAAO,GAAG,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzE,MAAM,GAAG,GAAI,UAAwC,CAAC,OAAO,EAAE,MAAM,CAAC;QACtE,GAAG,EAAE,KAAK,CAAC,WAAW,IAAI,yCAAyC,IAAI,IAAI,CAAC,CAAC;IAC/E,CAAC,CAAC;AACJ,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,cAAc,CAAC,OAAyB;IACtD,MAAM,KAAK,GAAG,OAAO,EAAE,CAAC;IACxB,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;AAC/D,CAAC","sourcesContent":["/**\n * Unhandled rejections of Worker code, on Node: the Worker's, not the host process's.\n *\n * On workerd and celld a promise the Worker leaves rejected is the Worker's affair: workerd logs\n * it, celld ignores it, and neither stops anything. On Node the Worker runs in the host's\n * process, so such a rejection reached the process's own `unhandledRejection` listeners (a test\n * runner reports it as an error; Node's default ends the process). Each Worker event now runs in\n * a scope that names its runtime, and a rejection raised in that scope goes to the runtime's\n * handler instead: Node calls `unhandledRejection` listeners in the async context of the\n * rejected promise, so the scope is found there.\n *\n * Browsers need none of this: a Worker runs in a worker of its own there.\n */\n\n/** Receives a Worker's unhandled rejection. */\nexport type RejectionHandler = (reason: unknown, promise: Promise<unknown>) => void;\n\n/** Runs `fn` in a scope whose unhandled rejections go to `handler`. */\nexport type RejectionScope = <R>(fn: () => R) => R;\n\ninterface Als<T> {\n run<R>(store: T, fn: () => R): R;\n getStore(): T | undefined;\n}\n\ntype NodeProcess = {\n getBuiltinModule?(id: string): unknown;\n emit: (event: string | symbol, ...args: unknown[]) => boolean;\n stderr?: { write(s: string): unknown };\n};\n\nconst KEY = Symbol.for(\"cellb.workerRejections\");\n\n/** The scope store, installed once per process (its `process.emit` hook routes by it). */\nfunction install(): Als<RejectionHandler> | undefined {\n const g = globalThis as { process?: NodeProcess } & Record<symbol, unknown>;\n if (g[KEY]) return g[KEY] as Als<RejectionHandler>;\n const proc = g.process;\n const hooks = proc?.getBuiltinModule?.(\"node:async_hooks\") as\n | { AsyncLocalStorage: new <T>() => Als<T> }\n | undefined;\n if (!proc || !hooks) return undefined;\n const scope = new hooks.AsyncLocalStorage<RejectionHandler>();\n const emit = proc.emit;\n // `unhandledRejection` is emitted, not dispatched another way: a Worker's goes to its runtime\n // and no further; everything else reaches the process's listeners as before.\n proc.emit = function (this: unknown, event: string | symbol, ...args: unknown[]) {\n if (event === \"unhandledRejection\") {\n const handler = scope.getStore();\n if (handler) {\n handler(args[0], args[1] as Promise<unknown>);\n return true;\n }\n }\n return emit.call(this, event, ...args);\n };\n g[KEY] = scope;\n return scope;\n}\n\n/** The default handler: one line on the host's stderr, outside the Worker's own console. */\nexport function reportToStderr(name: string): RejectionHandler {\n return (reason) => {\n const err = reason as { stack?: string };\n const text = typeof err?.stack === \"string\" ? err.stack : String(reason);\n const out = (globalThis as { process?: NodeProcess }).process?.stderr;\n out?.write(`[cellb] ${name}: unhandled rejection in Worker code: ${text}\\n`);\n };\n}\n\n/** A scope routing unhandled rejections to `handler` (on Node; elsewhere `fn` runs as is). */\nexport function rejectionScope(handler: RejectionHandler): RejectionScope {\n const scope = install();\n return scope ? (fn) => scope.run(handler, fn) : (fn) => fn();\n}\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export { type FilesApiBackupOptions, filesApiBackup } from "./adapters/files-backup.js";
|
|
2
|
+
export { type ChangeLogOptions, filesApiChangeLog } from "./adapters/files-changelog.js";
|
|
3
|
+
export { type FilesApiLtxLogOptions, filesApiLtxLog } from "./adapters/files-ltx.js";
|
|
4
|
+
export { wasmMemoryOpener } from "./adapters/wasm-sqlite.js";
|
|
5
|
+
export { AiError, type AiRunOptions, type WorkersAiOptions, workersAi, } from "./bindings/workers-ai.js";
|
|
6
|
+
export { type CelldBucketOptions, celldBucket } from "./bucket/celld-cells.js";
|
|
7
|
+
export { filesApiObjectStore, memoryObjectStore, type ObjectStore, PreconditionFailedError, } from "./bucket/object-store.js";
|
|
8
|
+
export { type S3Options, s3ObjectStore } from "./bucket/s3-object-store.js";
|
|
9
|
+
export { DurableObject, type ExecutionContext, WorkerEntrypoint } from "./core/durable-object.js";
|
|
10
|
+
export { DurableObjectNamespace, type DurableObjectStub, runInDurableObject, } from "./core/namespace.js";
|
|
11
|
+
export { BrokenObjectError, CellOwnedElsewhereError } from "./core/object-host.js";
|
|
12
|
+
export { type CellRuntime, type CellRuntimeOptions, createCellRuntime, type WorkerModule, } from "./core/runtime.js";
|
|
13
|
+
export { shardOf } from "./core/shard.js";
|
|
14
|
+
export { DurableObjectState } from "./core/state.js";
|
|
15
|
+
export * from "./ports.js";
|
|
16
|
+
export { createProjectRuntime, type ProjectHost, type ProjectRuntime, type WranglerConfig, } from "./project/wrangler.js";
|
|
17
|
+
export { CellRouter, type CellRouterOptions, ShardOwnerLostError } from "./router/cell-router.js";
|
|
18
|
+
export { createShardWorker, type ShardWorker, type ShardWorkerOptions, shardRouting, } from "./router/shard-worker.js";
|
|
19
|
+
export { type CellsHttpOptions, cellsHttpHandler, type RemoteRuntime, remoteRuntime, } from "./transport/cells-http.js";
|
|
20
|
+
export { type CellPort, connectRuntime, linkOverPort, serveHandlerOverPort, serveRuntime, } from "./transport/port.js";
|
|
21
|
+
export { type CellsWebSocketClass, createWebSocketClass, type WebSocketConnector, } from "./ws/client.js";
|
|
22
|
+
export { CellsResponse, takeClientPort, WebSocketPair } from "./ws/server.js";
|