@statewalker/cellb 0.0.0-stage → 0.1.1
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 +373 -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,53 @@
|
|
|
1
|
+
import type { CommitChanges, SqlResult, SyncSqlDriver } from "../ports.js";
|
|
2
|
+
/** `ctx.storage.sql.exec()` cursor (iterable, one-shot like the CF one). */
|
|
3
|
+
export declare class SqlStorageCursor<T = Record<string, unknown>> implements Iterable<T> {
|
|
4
|
+
#private;
|
|
5
|
+
readonly columnNames: string[];
|
|
6
|
+
readonly rowsRead: number;
|
|
7
|
+
readonly rowsWritten: number;
|
|
8
|
+
constructor(r: SqlResult);
|
|
9
|
+
next(): IteratorResult<T>;
|
|
10
|
+
[Symbol.iterator](): Iterator<T>;
|
|
11
|
+
toArray(): T[];
|
|
12
|
+
one(): T;
|
|
13
|
+
raw(): IterableIterator<unknown[]>;
|
|
14
|
+
}
|
|
15
|
+
export declare class SqlStorage {
|
|
16
|
+
#private;
|
|
17
|
+
constructor(driver: SyncSqlDriver, onCommit: (changes?: CommitChanges) => void, opts?: {
|
|
18
|
+
capture?: boolean;
|
|
19
|
+
});
|
|
20
|
+
exec<T = Record<string, unknown>>(query: string, ...bindings: unknown[]): SqlStorageCursor<T>;
|
|
21
|
+
/**
|
|
22
|
+
* workerd's `sql.prepare(query)`: a reusable statement, called with bindings.
|
|
23
|
+
* Not in Cloudflare's public docs, but used by Miniflare's simulator objects.
|
|
24
|
+
*/
|
|
25
|
+
prepare<T = Record<string, unknown>>(query: string): (...bindings: unknown[]) => SqlStorageCursor<T>;
|
|
26
|
+
/**
|
|
27
|
+
* workerd's experimental `sql.ingest(text)`, for SQL that arrives in pieces: runs the complete
|
|
28
|
+
* statements at the start of `text` and returns the rest, to be prefixed to the next piece.
|
|
29
|
+
* As celld: errors read `prepare ingested SQL: …` (refused, or not valid SQL) or `step ingested
|
|
30
|
+
* SQL: …` (failed while running); statements before a failing one stay applied; `rowsWritten`
|
|
31
|
+
* includes trigger writes; there is no `rowsRead`.
|
|
32
|
+
*/
|
|
33
|
+
ingest(text: string): {
|
|
34
|
+
remainder: string;
|
|
35
|
+
statementCount: number;
|
|
36
|
+
rowsWritten: number;
|
|
37
|
+
};
|
|
38
|
+
get databaseSize(): number;
|
|
39
|
+
/** Unguarded path for the runtime's own tables (_cf_KV, _cf_METADATA). */
|
|
40
|
+
internalExec(query: string, bindings?: unknown[]): SqlResult;
|
|
41
|
+
transactionSync<T>(fn: () => T): T;
|
|
42
|
+
/** Suspends auto-commit (used by the async `transaction()` which spans awaits). */
|
|
43
|
+
hold(): () => void;
|
|
44
|
+
/** True while an async transaction() holds auto-commit (no consistent snapshot possible). */
|
|
45
|
+
get held(): boolean;
|
|
46
|
+
/** Commits the implicit transaction now (no-op if none, or if held). */
|
|
47
|
+
commit(): void;
|
|
48
|
+
/** Called after a rollback (lazily created internal tables may be gone). */
|
|
49
|
+
readonly rolledBack: Set<() => void>;
|
|
50
|
+
rollback(): void;
|
|
51
|
+
}
|
|
52
|
+
/** Parameters a statement expects: anonymous `?` count, highest `?NNN`, distinct named ones. */
|
|
53
|
+
export declare function countParameters(sql: string): number;
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
import { LOG_SEQ_READ, LOG_SEQ_WRITE, LOG_TABLE } from "./celld-schema.js";
|
|
2
|
+
import { completeSqlStatements, lacksStatement } from "./sql-split.js";
|
|
3
|
+
const FORBIDDEN_TXN = /^\s*(BEGIN|COMMIT|END|ROLLBACK|SAVEPOINT|RELEASE)\b/i;
|
|
4
|
+
const FORBIDDEN_INTERNAL = /\b_cf_\w*/i;
|
|
5
|
+
/** Creating or dropping an object with an internal name (any case): celld refuses it outright. */
|
|
6
|
+
const FORBIDDEN_DDL = /^\s*(CREATE|DROP)\b[^(]*?\b_cf_/i;
|
|
7
|
+
/**
|
|
8
|
+
* Runs `fn` after the current macrotask, as workerd commits an implicit transaction after the
|
|
9
|
+
* current turn of its event loop: the writes of every microtask until then share one commit.
|
|
10
|
+
* `setImmediate` on Node; a MessageChannel message in browsers (no timer clamping).
|
|
11
|
+
*/
|
|
12
|
+
const afterTurn = (() => {
|
|
13
|
+
const g = globalThis;
|
|
14
|
+
if (typeof g.setImmediate === "function")
|
|
15
|
+
return (fn) => void g.setImmediate(fn);
|
|
16
|
+
if (typeof MessageChannel === "function") {
|
|
17
|
+
const queue = [];
|
|
18
|
+
const channel = new MessageChannel();
|
|
19
|
+
channel.port1.onmessage = () => {
|
|
20
|
+
for (const f of queue.splice(0))
|
|
21
|
+
f();
|
|
22
|
+
};
|
|
23
|
+
return (fn) => {
|
|
24
|
+
if (queue.push(fn) === 1)
|
|
25
|
+
channel.port2.postMessage(null);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return (fn) => void setTimeout(fn, 0);
|
|
29
|
+
})();
|
|
30
|
+
/** The SQL text with string literals and comments blanked out (quoted identifiers stay). */
|
|
31
|
+
function withoutLiterals(sql) {
|
|
32
|
+
return sql.replace(/'(?:[^']|'')*'|--[^\n]*|\/\*[\s\S]*?\*\//g, " ");
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Why celld's authorizer refuses a statement at prepare time, or undefined: transaction
|
|
36
|
+
* statements and internal tables. Names inside string literals and comments are values, not
|
|
37
|
+
* tables: `WHERE callback = '_cf_x'` is allowed (the Agents SDK writes one).
|
|
38
|
+
*/
|
|
39
|
+
function refusal(query) {
|
|
40
|
+
const code = withoutLiterals(query);
|
|
41
|
+
if (FORBIDDEN_TXN.test(code) || FORBIDDEN_DDL.test(code))
|
|
42
|
+
return "not authorized";
|
|
43
|
+
const internal = FORBIDDEN_INTERNAL.exec(code);
|
|
44
|
+
if (!internal)
|
|
45
|
+
return undefined;
|
|
46
|
+
const table = internal[0];
|
|
47
|
+
// celld names the first column of its own internal schema (_cf_KV starts with `scope`).
|
|
48
|
+
return `access to ${table}.${table.toLowerCase() === "_cf_kv" ? "scope" : "key"} is prohibited`;
|
|
49
|
+
}
|
|
50
|
+
/** SQLite's own message, without the prefix SQLite WASM adds to it. */
|
|
51
|
+
const sqliteMessage = (e) => String(e?.message ?? e).replace(/^SQLITE_\w+: sqlite3 result code \d+: /, "");
|
|
52
|
+
/** `ctx.storage.sql.exec()` cursor (iterable, one-shot like the CF one). */
|
|
53
|
+
export class SqlStorageCursor {
|
|
54
|
+
columnNames;
|
|
55
|
+
rowsRead;
|
|
56
|
+
rowsWritten;
|
|
57
|
+
#rows;
|
|
58
|
+
#pos = 0;
|
|
59
|
+
constructor(r) {
|
|
60
|
+
this.columnNames = r.columnNames;
|
|
61
|
+
this.#rows = r.rows;
|
|
62
|
+
this.rowsRead = r.rows.length;
|
|
63
|
+
this.rowsWritten = r.rowsWritten;
|
|
64
|
+
}
|
|
65
|
+
next() {
|
|
66
|
+
// As workerd: the final result has no `value` key ({ done: true }).
|
|
67
|
+
if (this.#pos >= this.#rows.length)
|
|
68
|
+
return { done: true };
|
|
69
|
+
return { done: false, value: this.#obj(this.#rows[this.#pos++]) };
|
|
70
|
+
}
|
|
71
|
+
[Symbol.iterator]() {
|
|
72
|
+
return this;
|
|
73
|
+
}
|
|
74
|
+
toArray() {
|
|
75
|
+
return [...this];
|
|
76
|
+
}
|
|
77
|
+
one() {
|
|
78
|
+
const rest = this.toArray();
|
|
79
|
+
if (rest.length !== 1)
|
|
80
|
+
throw new Error(`Expected exactly one result from SQL query, but got ${rest.length === 0 ? "no" : "multiple"} results`);
|
|
81
|
+
return rest[0];
|
|
82
|
+
}
|
|
83
|
+
*raw() {
|
|
84
|
+
while (this.#pos < this.#rows.length)
|
|
85
|
+
yield this.#rows[this.#pos++];
|
|
86
|
+
}
|
|
87
|
+
#obj(row) {
|
|
88
|
+
const o = {};
|
|
89
|
+
for (const [i, c] of this.columnNames.entries())
|
|
90
|
+
o[c] = row[i];
|
|
91
|
+
return o;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* `ctx.storage.sql` with SQLite-backed-DO semantics: every write opens an
|
|
96
|
+
* IMPLICIT transaction that commits on the next microtask (i.e. when the
|
|
97
|
+
* handler yields). Sync writes therefore coalesce atomically, and the
|
|
98
|
+
* output gate only has to await durability of the commit.
|
|
99
|
+
*/
|
|
100
|
+
const DDL = /^\s*(CREATE|ALTER|DROP)\b/i;
|
|
101
|
+
/** Errors after which SQLite may roll the whole transaction back by itself. */
|
|
102
|
+
const ROLLS_BACK = /SQLITE_(IOERR|FULL|NOMEM|BUSY|INTERRUPT|CORRUPT)|disk I\/O error|database or disk is full|out of memory|interrupted/i;
|
|
103
|
+
/** Statements that may write (a conservative test: WITH … and PRAGMAs count as writes). */
|
|
104
|
+
const WRITES = /^\s*(INSERT|REPLACE|UPDATE|DELETE|CREATE|ALTER|DROP|WITH|PRAGMA)\b/i;
|
|
105
|
+
const WRITE_TARGET = /^\s*(?:INSERT|REPLACE)(?:\s+OR\s+\w+)?\s+INTO\s+["`[]?([\w$]+)|^\s*UPDATE(?:\s+OR\s+\w+)?\s+["`[]?([\w$]+)|^\s*DELETE\s+FROM\s+["`[]?([\w$]+)/i;
|
|
106
|
+
export class SqlStorage {
|
|
107
|
+
#driver;
|
|
108
|
+
#onCommit;
|
|
109
|
+
#inTxn = false;
|
|
110
|
+
/** The implicit transaction has written (its loss must fail the commit, not pass silently). */
|
|
111
|
+
#wrote = false;
|
|
112
|
+
/** Why SQLite rolled the implicit transaction back by itself (after an I/O error), if it did. */
|
|
113
|
+
#lost;
|
|
114
|
+
#holds = 0;
|
|
115
|
+
#depth = 0;
|
|
116
|
+
// Transaction-log capture (only when the durability port asks for it).
|
|
117
|
+
#capture;
|
|
118
|
+
#ddl = [];
|
|
119
|
+
#statements = [];
|
|
120
|
+
#noPk = new Map();
|
|
121
|
+
#changesAtBegin = 0;
|
|
122
|
+
#schemaAtBegin = 0;
|
|
123
|
+
#schemaVersion() {
|
|
124
|
+
return Number(this.#driver.exec("PRAGMA schema_version", []).rows[0]?.[0] ?? 0);
|
|
125
|
+
}
|
|
126
|
+
#totalChanges() {
|
|
127
|
+
return Number(this.#driver.exec("SELECT total_changes()", []).rows[0]?.[0] ?? 0);
|
|
128
|
+
}
|
|
129
|
+
constructor(driver, onCommit, opts = {}) {
|
|
130
|
+
this.#driver = driver;
|
|
131
|
+
this.#onCommit = onCommit;
|
|
132
|
+
this.#capture = !!opts.capture;
|
|
133
|
+
if (this.#capture && !driver.captureStart)
|
|
134
|
+
throw new Error("This SyncSqlDriver cannot capture changes: no transaction-log durability");
|
|
135
|
+
}
|
|
136
|
+
/** Records what the changeset cannot carry: schema changes, and writes to PK-less tables. */
|
|
137
|
+
#record(query, bindings) {
|
|
138
|
+
if (!this.#capture)
|
|
139
|
+
return;
|
|
140
|
+
if (DDL.test(query)) {
|
|
141
|
+
this.#ddl.push(query);
|
|
142
|
+
this.#noPk.clear();
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (this.#driver.captureCoversRowidTables !== false)
|
|
146
|
+
return;
|
|
147
|
+
const m = WRITE_TARGET.exec(query);
|
|
148
|
+
const table = m?.[1] ?? m?.[2] ?? m?.[3];
|
|
149
|
+
if (table && this.#tableHasNoPk(table))
|
|
150
|
+
this.#statements.push([query, bindings]);
|
|
151
|
+
}
|
|
152
|
+
#tableHasNoPk(table) {
|
|
153
|
+
let v = this.#noPk.get(table);
|
|
154
|
+
if (v === undefined) {
|
|
155
|
+
const info = this.#driver.exec(`SELECT count(*) FROM pragma_table_info(?) WHERE pk > 0`, [
|
|
156
|
+
table,
|
|
157
|
+
]);
|
|
158
|
+
v = Number(info.rows[0]?.[0] ?? 0) === 0;
|
|
159
|
+
this.#noPk.set(table, v);
|
|
160
|
+
}
|
|
161
|
+
return v;
|
|
162
|
+
}
|
|
163
|
+
exec(query, ...bindings) {
|
|
164
|
+
// Messages as celld words them (storage-details project).
|
|
165
|
+
const refused = refusal(query);
|
|
166
|
+
if (refused)
|
|
167
|
+
throw new Error(`SQL error: prepare SQL cursor: ${refused}`);
|
|
168
|
+
if (bindings.length && countParameters(query) !== bindings.length)
|
|
169
|
+
throw new Error("SQL error: Wrong number of parameter bindings for SQL query.");
|
|
170
|
+
// Statement after statement, as workerd and celld prepare them: none at all, or a last one
|
|
171
|
+
// of comments alone, is refused.
|
|
172
|
+
if (lacksStatement(query))
|
|
173
|
+
throw new Error("SQL code did not contain a statement.");
|
|
174
|
+
return new SqlStorageCursor(this.internalExec(query, bindings));
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* workerd's `sql.prepare(query)`: a reusable statement, called with bindings.
|
|
178
|
+
* Not in Cloudflare's public docs, but used by Miniflare's simulator objects.
|
|
179
|
+
*/
|
|
180
|
+
prepare(query) {
|
|
181
|
+
return (...bindings) => this.exec(query, ...bindings);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* workerd's experimental `sql.ingest(text)`, for SQL that arrives in pieces: runs the complete
|
|
185
|
+
* statements at the start of `text` and returns the rest, to be prefixed to the next piece.
|
|
186
|
+
* As celld: errors read `prepare ingested SQL: …` (refused, or not valid SQL) or `step ingested
|
|
187
|
+
* SQL: …` (failed while running); statements before a failing one stay applied; `rowsWritten`
|
|
188
|
+
* includes trigger writes; there is no `rowsRead`.
|
|
189
|
+
*/
|
|
190
|
+
ingest(text) {
|
|
191
|
+
const { statements, remainder } = completeSqlStatements(String(text));
|
|
192
|
+
const before = this.#totalChanges();
|
|
193
|
+
for (const statement of statements) {
|
|
194
|
+
const refused = refusal(statement);
|
|
195
|
+
if (refused)
|
|
196
|
+
throw new Error(`SQL error: prepare ingested SQL: ${refused}`);
|
|
197
|
+
try {
|
|
198
|
+
this.#driver.exec(`EXPLAIN ${statement}`, []); // prepares it without running it
|
|
199
|
+
}
|
|
200
|
+
catch (e) {
|
|
201
|
+
throw new Error(`SQL error: prepare ingested SQL: ${sqliteMessage(e)}`);
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
this.internalExec(statement);
|
|
205
|
+
}
|
|
206
|
+
catch (e) {
|
|
207
|
+
throw new Error(`SQL error: step ingested SQL: ${sqliteMessage(e)}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
remainder,
|
|
212
|
+
statementCount: statements.length,
|
|
213
|
+
rowsWritten: this.#totalChanges() - before,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
get databaseSize() {
|
|
217
|
+
return this.#driver.databaseSize();
|
|
218
|
+
}
|
|
219
|
+
/** Unguarded path for the runtime's own tables (_cf_KV, _cf_METADATA). */
|
|
220
|
+
internalExec(query, bindings = []) {
|
|
221
|
+
this.#ensureTxn();
|
|
222
|
+
let r;
|
|
223
|
+
try {
|
|
224
|
+
r = this.#driver.exec(query, bindings);
|
|
225
|
+
}
|
|
226
|
+
catch (e) {
|
|
227
|
+
this.#afterFailure(e);
|
|
228
|
+
throw e;
|
|
229
|
+
}
|
|
230
|
+
if (!this.#wrote && WRITES.test(query))
|
|
231
|
+
this.#wrote = true;
|
|
232
|
+
this.#record(query, bindings);
|
|
233
|
+
return r;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* After a failed statement: SQLite rolls the whole transaction back by itself on some errors
|
|
237
|
+
* (I/O, disk full, out of memory). A read-only transaction lost nothing: the statement's error
|
|
238
|
+
* fails the request, and the next one starts afresh. One that had written lost those writes:
|
|
239
|
+
* its commit fails with the cause (the object resets, as workerd's does).
|
|
240
|
+
*/
|
|
241
|
+
#afterFailure(e) {
|
|
242
|
+
if (!this.#inTxn)
|
|
243
|
+
return;
|
|
244
|
+
const open = this.#driver.inTransaction?.();
|
|
245
|
+
if (open === true)
|
|
246
|
+
return; // only the statement failed
|
|
247
|
+
if (open === undefined) {
|
|
248
|
+
// No way to ask the driver: only errors after which SQLite rolls back are checked, with a
|
|
249
|
+
// statement (one that fails, and is logged by some builds, while the transaction is open).
|
|
250
|
+
if (!ROLLS_BACK.test(String(e?.message ?? e)))
|
|
251
|
+
return;
|
|
252
|
+
try {
|
|
253
|
+
this.#driver.exec("BEGIN", []); // succeeds only outside a transaction
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
this.#driver.exec("ROLLBACK", []); // the probe's own transaction
|
|
259
|
+
}
|
|
260
|
+
const wrote = this.#wrote;
|
|
261
|
+
this.#inTxn = false;
|
|
262
|
+
this.#wrote = false;
|
|
263
|
+
this.#driver.discardDirtyPages?.();
|
|
264
|
+
for (const f of this.rolledBack)
|
|
265
|
+
f();
|
|
266
|
+
if (this.#capture) {
|
|
267
|
+
this.#driver.captureDiscard?.();
|
|
268
|
+
this.#ddl = [];
|
|
269
|
+
this.#statements = [];
|
|
270
|
+
}
|
|
271
|
+
if (wrote)
|
|
272
|
+
this.#lost = e;
|
|
273
|
+
}
|
|
274
|
+
transactionSync(fn) {
|
|
275
|
+
this.#ensureTxn();
|
|
276
|
+
const sp = `_cf_sp${++this.#depth}`;
|
|
277
|
+
this.#driver.exec(`SAVEPOINT ${sp}`, []);
|
|
278
|
+
const marks = [this.#ddl.length, this.#statements.length];
|
|
279
|
+
try {
|
|
280
|
+
const r = fn();
|
|
281
|
+
this.#driver.exec(`RELEASE ${sp}`, []);
|
|
282
|
+
return r;
|
|
283
|
+
}
|
|
284
|
+
catch (e) {
|
|
285
|
+
// SQLite rolled the whole transaction back by itself (#afterFailure): no savepoint left.
|
|
286
|
+
if (!this.#inTxn)
|
|
287
|
+
throw e;
|
|
288
|
+
this.#driver.exec(`ROLLBACK TO ${sp}`, []);
|
|
289
|
+
for (const f of this.rolledBack)
|
|
290
|
+
f();
|
|
291
|
+
this.#ddl.length = marks[0];
|
|
292
|
+
this.#statements.length = marks[1];
|
|
293
|
+
this.#driver.exec(`RELEASE ${sp}`, []);
|
|
294
|
+
throw e;
|
|
295
|
+
}
|
|
296
|
+
finally {
|
|
297
|
+
this.#depth--;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/** Suspends auto-commit (used by the async `transaction()` which spans awaits). */
|
|
301
|
+
hold() {
|
|
302
|
+
this.#holds++;
|
|
303
|
+
let released = false;
|
|
304
|
+
return () => {
|
|
305
|
+
if (released)
|
|
306
|
+
return;
|
|
307
|
+
released = true;
|
|
308
|
+
if (--this.#holds === 0)
|
|
309
|
+
afterTurn(() => this.commit());
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
/** True while an async transaction() holds auto-commit (no consistent snapshot possible). */
|
|
313
|
+
get held() {
|
|
314
|
+
return this.#holds > 0;
|
|
315
|
+
}
|
|
316
|
+
/** Commits the implicit transaction now (no-op if none, or if held). */
|
|
317
|
+
commit() {
|
|
318
|
+
if (this.#lost !== undefined && this.#holds === 0) {
|
|
319
|
+
const cause = this.#lost;
|
|
320
|
+
this.#lost = undefined;
|
|
321
|
+
throw new Error(`the transaction's writes were rolled back after: ${sqliteMessage(cause)}`, {
|
|
322
|
+
cause,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
if (!this.#inTxn || this.#holds > 0)
|
|
326
|
+
return;
|
|
327
|
+
let changes;
|
|
328
|
+
// Read-only transactions produce no log segment ("IF NOT EXISTS" DDL that changed
|
|
329
|
+
// nothing included: the schema version tells).
|
|
330
|
+
if (this.#capture && this.#ddl.length && this.#schemaVersion() === this.#schemaAtBegin)
|
|
331
|
+
this.#ddl = [];
|
|
332
|
+
if (this.#capture && (this.#ddl.length || this.#totalChanges() !== this.#changesAtBegin)) {
|
|
333
|
+
// The log sequence number lives in the database, inside the same transaction.
|
|
334
|
+
this.#driver.exec(LOG_TABLE, []);
|
|
335
|
+
const row = this.#driver.exec(LOG_SEQ_READ, []).rows[0];
|
|
336
|
+
const logSeq = Number(row?.[0] ?? 0) + 1;
|
|
337
|
+
this.#driver.exec(LOG_SEQ_WRITE, [logSeq]);
|
|
338
|
+
changes = {
|
|
339
|
+
logSeq,
|
|
340
|
+
ddl: this.#ddl,
|
|
341
|
+
changeset: new Uint8Array(),
|
|
342
|
+
statements: this.#statements,
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
this.#inTxn = false;
|
|
346
|
+
this.#wrote = false;
|
|
347
|
+
this.#driver.exec("COMMIT", []);
|
|
348
|
+
if (this.#capture) {
|
|
349
|
+
const changeset = this.#driver.captureTake();
|
|
350
|
+
if (changes)
|
|
351
|
+
changes.changeset = changeset;
|
|
352
|
+
this.#ddl = [];
|
|
353
|
+
this.#statements = [];
|
|
354
|
+
}
|
|
355
|
+
this.#onCommit(changes);
|
|
356
|
+
}
|
|
357
|
+
/** Called after a rollback (lazily created internal tables may be gone). */
|
|
358
|
+
rolledBack = new Set();
|
|
359
|
+
rollback() {
|
|
360
|
+
this.#lost = undefined;
|
|
361
|
+
if (!this.#inTxn)
|
|
362
|
+
return;
|
|
363
|
+
this.#inTxn = false;
|
|
364
|
+
this.#wrote = false;
|
|
365
|
+
this.#driver.exec("ROLLBACK", []);
|
|
366
|
+
this.#driver.discardDirtyPages?.(); // pages a rolled-back transaction spilled are not a commit
|
|
367
|
+
for (const f of this.rolledBack)
|
|
368
|
+
f();
|
|
369
|
+
if (this.#capture) {
|
|
370
|
+
this.#driver.captureDiscard?.();
|
|
371
|
+
this.#ddl = [];
|
|
372
|
+
this.#statements = [];
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
#ensureTxn() {
|
|
376
|
+
if (this.#inTxn)
|
|
377
|
+
return;
|
|
378
|
+
this.#driver.exec("BEGIN", []);
|
|
379
|
+
if (this.#capture) {
|
|
380
|
+
this.#driver.captureStart();
|
|
381
|
+
this.#changesAtBegin = this.#totalChanges();
|
|
382
|
+
this.#schemaAtBegin = this.#schemaVersion();
|
|
383
|
+
}
|
|
384
|
+
this.#inTxn = true;
|
|
385
|
+
afterTurn(() => this.commit());
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
/** Parameters a statement expects: anonymous `?` count, highest `?NNN`, distinct named ones. */
|
|
389
|
+
export function countParameters(sql) {
|
|
390
|
+
let anon = 0;
|
|
391
|
+
let maxNumbered = 0;
|
|
392
|
+
const named = new Set();
|
|
393
|
+
const re = /'(?:[^']|'')*'|"(?:[^"]|"")*"|--[^\n]*|\/\*[\s\S]*?\*\/|\?(\d*)|([:@$][A-Za-z_]\w*)/g;
|
|
394
|
+
for (let m = re.exec(sql); m; m = re.exec(sql)) {
|
|
395
|
+
if (m[1] !== undefined) {
|
|
396
|
+
if (m[1] === "")
|
|
397
|
+
anon++;
|
|
398
|
+
else
|
|
399
|
+
maxNumbered = Math.max(maxNumbered, Number(m[1]));
|
|
400
|
+
}
|
|
401
|
+
else if (m[2])
|
|
402
|
+
named.add(m[2]);
|
|
403
|
+
}
|
|
404
|
+
const positional = maxNumbered ? Math.max(maxNumbered, anon) : anon;
|
|
405
|
+
return positional + named.size;
|
|
406
|
+
}
|
|
407
|
+
//# sourceMappingURL=sql-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-storage.js","sourceRoot":"","sources":["../../src/core/sql-storage.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CommitChanges, SqlResult, SyncSqlDriver } from \"../ports.js\";\nimport { LOG_SEQ_READ, LOG_SEQ_WRITE, LOG_TABLE } from \"./celld-schema.js\";\nimport { completeSqlStatements, lacksStatement } from \"./sql-split.js\";\n\nconst FORBIDDEN_TXN = /^\\s*(BEGIN|COMMIT|END|ROLLBACK|SAVEPOINT|RELEASE)\\b/i;\nconst FORBIDDEN_INTERNAL = /\\b_cf_\\w*/i;\n/** Creating or dropping an object with an internal name (any case): celld refuses it outright. */\nconst FORBIDDEN_DDL = /^\\s*(CREATE|DROP)\\b[^(]*?\\b_cf_/i;\n\n/**\n * Runs `fn` after the current macrotask, as workerd commits an implicit transaction after the\n * current turn of its event loop: the writes of every microtask until then share one commit.\n * `setImmediate` on Node; a MessageChannel message in browsers (no timer clamping).\n */\nconst afterTurn: (fn: () => void) => void = (() => {\n const g = globalThis as { setImmediate?: (fn: () => void) => unknown };\n if (typeof g.setImmediate === \"function\") return (fn) => void g.setImmediate!(fn);\n if (typeof MessageChannel === \"function\") {\n const queue: (() => void)[] = [];\n const channel = new MessageChannel();\n channel.port1.onmessage = () => {\n for (const f of queue.splice(0)) f();\n };\n return (fn) => {\n if (queue.push(fn) === 1) channel.port2.postMessage(null);\n };\n }\n return (fn) => void setTimeout(fn, 0);\n})();\n\n/** The SQL text with string literals and comments blanked out (quoted identifiers stay). */\nfunction withoutLiterals(sql: string): string {\n return sql.replace(/'(?:[^']|'')*'|--[^\\n]*|\\/\\*[\\s\\S]*?\\*\\//g, \" \");\n}\n\n/**\n * Why celld's authorizer refuses a statement at prepare time, or undefined: transaction\n * statements and internal tables. Names inside string literals and comments are values, not\n * tables: `WHERE callback = '_cf_x'` is allowed (the Agents SDK writes one).\n */\nfunction refusal(query: string): string | undefined {\n const code = withoutLiterals(query);\n if (FORBIDDEN_TXN.test(code) || FORBIDDEN_DDL.test(code)) return \"not authorized\";\n const internal = FORBIDDEN_INTERNAL.exec(code);\n if (!internal) return undefined;\n const table = internal[0];\n // celld names the first column of its own internal schema (_cf_KV starts with `scope`).\n return `access to ${table}.${table.toLowerCase() === \"_cf_kv\" ? \"scope\" : \"key\"} is prohibited`;\n}\n\n/** SQLite's own message, without the prefix SQLite WASM adds to it. */\nconst sqliteMessage = (e: unknown) =>\n String((e as Error)?.message ?? e).replace(/^SQLITE_\\w+: sqlite3 result code \\d+: /, \"\");\n\n/** `ctx.storage.sql.exec()` cursor (iterable, one-shot like the CF one). */\nexport class SqlStorageCursor<T = Record<string, unknown>> implements Iterable<T> {\n readonly columnNames: string[];\n readonly rowsRead: number;\n readonly rowsWritten: number;\n #rows: unknown[][];\n #pos = 0;\n constructor(r: SqlResult) {\n this.columnNames = r.columnNames;\n this.#rows = r.rows;\n this.rowsRead = r.rows.length;\n this.rowsWritten = r.rowsWritten;\n }\n next(): IteratorResult<T> {\n // As workerd: the final result has no `value` key ({ done: true }).\n if (this.#pos >= this.#rows.length) return { done: true } as IteratorReturnResult<undefined>;\n return { done: false, value: this.#obj(this.#rows[this.#pos++]) };\n }\n [Symbol.iterator](): Iterator<T> {\n return this;\n }\n toArray(): T[] {\n return [...this];\n }\n one(): T {\n const rest = this.toArray();\n if (rest.length !== 1)\n throw new Error(\n `Expected exactly one result from SQL query, but got ${rest.length === 0 ? \"no\" : \"multiple\"} results`,\n );\n return rest[0];\n }\n *raw(): IterableIterator<unknown[]> {\n while (this.#pos < this.#rows.length) yield this.#rows[this.#pos++];\n }\n #obj(row: unknown[]): T {\n const o: Record<string, unknown> = {};\n for (const [i, c] of this.columnNames.entries()) o[c] = row[i];\n return o as T;\n }\n}\n\n/**\n * `ctx.storage.sql` with SQLite-backed-DO semantics: every write opens an\n * IMPLICIT transaction that commits on the next microtask (i.e. when the\n * handler yields). Sync writes therefore coalesce atomically, and the\n * output gate only has to await durability of the commit.\n */\nconst DDL = /^\\s*(CREATE|ALTER|DROP)\\b/i;\n/** Errors after which SQLite may roll the whole transaction back by itself. */\nconst ROLLS_BACK =\n /SQLITE_(IOERR|FULL|NOMEM|BUSY|INTERRUPT|CORRUPT)|disk I\\/O error|database or disk is full|out of memory|interrupted/i;\n/** Statements that may write (a conservative test: WITH … and PRAGMAs count as writes). */\nconst WRITES = /^\\s*(INSERT|REPLACE|UPDATE|DELETE|CREATE|ALTER|DROP|WITH|PRAGMA)\\b/i;\nconst WRITE_TARGET =\n /^\\s*(?:INSERT|REPLACE)(?:\\s+OR\\s+\\w+)?\\s+INTO\\s+[\"`[]?([\\w$]+)|^\\s*UPDATE(?:\\s+OR\\s+\\w+)?\\s+[\"`[]?([\\w$]+)|^\\s*DELETE\\s+FROM\\s+[\"`[]?([\\w$]+)/i;\n\nexport class SqlStorage {\n #driver: SyncSqlDriver;\n #onCommit: (changes?: CommitChanges) => void;\n #inTxn = false;\n /** The implicit transaction has written (its loss must fail the commit, not pass silently). */\n #wrote = false;\n /** Why SQLite rolled the implicit transaction back by itself (after an I/O error), if it did. */\n #lost: unknown;\n #holds = 0;\n #depth = 0;\n // Transaction-log capture (only when the durability port asks for it).\n readonly #capture: boolean;\n #ddl: string[] = [];\n #statements: [string, unknown[]][] = [];\n readonly #noPk = new Map<string, boolean>();\n #changesAtBegin = 0;\n #schemaAtBegin = 0;\n #schemaVersion(): number {\n return Number(this.#driver.exec(\"PRAGMA schema_version\", []).rows[0]?.[0] ?? 0);\n }\n #totalChanges(): number {\n return Number(this.#driver.exec(\"SELECT total_changes()\", []).rows[0]?.[0] ?? 0);\n }\n\n constructor(\n driver: SyncSqlDriver,\n onCommit: (changes?: CommitChanges) => void,\n opts: { capture?: boolean } = {},\n ) {\n this.#driver = driver;\n this.#onCommit = onCommit;\n this.#capture = !!opts.capture;\n if (this.#capture && !driver.captureStart)\n throw new Error(\"This SyncSqlDriver cannot capture changes: no transaction-log durability\");\n }\n\n /** Records what the changeset cannot carry: schema changes, and writes to PK-less tables. */\n #record(query: string, bindings: unknown[]): void {\n if (!this.#capture) return;\n if (DDL.test(query)) {\n this.#ddl.push(query);\n this.#noPk.clear();\n return;\n }\n if (this.#driver.captureCoversRowidTables !== false) return;\n const m = WRITE_TARGET.exec(query);\n const table = m?.[1] ?? m?.[2] ?? m?.[3];\n if (table && this.#tableHasNoPk(table)) this.#statements.push([query, bindings]);\n }\n\n #tableHasNoPk(table: string): boolean {\n let v = this.#noPk.get(table);\n if (v === undefined) {\n const info = this.#driver.exec(`SELECT count(*) FROM pragma_table_info(?) WHERE pk > 0`, [\n table,\n ]);\n v = Number(info.rows[0]?.[0] ?? 0) === 0;\n this.#noPk.set(table, v);\n }\n return v;\n }\n\n exec<T = Record<string, unknown>>(query: string, ...bindings: unknown[]): SqlStorageCursor<T> {\n // Messages as celld words them (storage-details project).\n const refused = refusal(query);\n if (refused) throw new Error(`SQL error: prepare SQL cursor: ${refused}`);\n if (bindings.length && countParameters(query) !== bindings.length)\n throw new Error(\"SQL error: Wrong number of parameter bindings for SQL query.\");\n // Statement after statement, as workerd and celld prepare them: none at all, or a last one\n // of comments alone, is refused.\n if (lacksStatement(query)) throw new Error(\"SQL code did not contain a statement.\");\n return new SqlStorageCursor<T>(this.internalExec(query, bindings));\n }\n\n /**\n * workerd's `sql.prepare(query)`: a reusable statement, called with bindings.\n * Not in Cloudflare's public docs, but used by Miniflare's simulator objects.\n */\n prepare<T = Record<string, unknown>>(\n query: string,\n ): (...bindings: unknown[]) => SqlStorageCursor<T> {\n return (...bindings) => this.exec<T>(query, ...bindings);\n }\n\n /**\n * workerd's experimental `sql.ingest(text)`, for SQL that arrives in pieces: runs the complete\n * statements at the start of `text` and returns the rest, to be prefixed to the next piece.\n * As celld: errors read `prepare ingested SQL: …` (refused, or not valid SQL) or `step ingested\n * SQL: …` (failed while running); statements before a failing one stay applied; `rowsWritten`\n * includes trigger writes; there is no `rowsRead`.\n */\n ingest(text: string): { remainder: string; statementCount: number; rowsWritten: number } {\n const { statements, remainder } = completeSqlStatements(String(text));\n const before = this.#totalChanges();\n for (const statement of statements) {\n const refused = refusal(statement);\n if (refused) throw new Error(`SQL error: prepare ingested SQL: ${refused}`);\n try {\n this.#driver.exec(`EXPLAIN ${statement}`, []); // prepares it without running it\n } catch (e) {\n throw new Error(`SQL error: prepare ingested SQL: ${sqliteMessage(e)}`);\n }\n try {\n this.internalExec(statement);\n } catch (e) {\n throw new Error(`SQL error: step ingested SQL: ${sqliteMessage(e)}`);\n }\n }\n return {\n remainder,\n statementCount: statements.length,\n rowsWritten: this.#totalChanges() - before,\n };\n }\n\n get databaseSize(): number {\n return this.#driver.databaseSize();\n }\n\n /** Unguarded path for the runtime's own tables (_cf_KV, _cf_METADATA). */\n internalExec(query: string, bindings: unknown[] = []): SqlResult {\n this.#ensureTxn();\n let r: SqlResult;\n try {\n r = this.#driver.exec(query, bindings);\n } catch (e) {\n this.#afterFailure(e);\n throw e;\n }\n if (!this.#wrote && WRITES.test(query)) this.#wrote = true;\n this.#record(query, bindings);\n return r;\n }\n\n /**\n * After a failed statement: SQLite rolls the whole transaction back by itself on some errors\n * (I/O, disk full, out of memory). A read-only transaction lost nothing: the statement's error\n * fails the request, and the next one starts afresh. One that had written lost those writes:\n * its commit fails with the cause (the object resets, as workerd's does).\n */\n #afterFailure(e: unknown): void {\n if (!this.#inTxn) return;\n const open = this.#driver.inTransaction?.();\n if (open === true) return; // only the statement failed\n if (open === undefined) {\n // No way to ask the driver: only errors after which SQLite rolls back are checked, with a\n // statement (one that fails, and is logged by some builds, while the transaction is open).\n if (!ROLLS_BACK.test(String((e as Error)?.message ?? e))) return;\n try {\n this.#driver.exec(\"BEGIN\", []); // succeeds only outside a transaction\n } catch {\n return;\n }\n this.#driver.exec(\"ROLLBACK\", []); // the probe's own transaction\n }\n const wrote = this.#wrote;\n this.#inTxn = false;\n this.#wrote = false;\n this.#driver.discardDirtyPages?.();\n for (const f of this.rolledBack) f();\n if (this.#capture) {\n this.#driver.captureDiscard?.();\n this.#ddl = [];\n this.#statements = [];\n }\n if (wrote) this.#lost = e;\n }\n\n transactionSync<T>(fn: () => T): T {\n this.#ensureTxn();\n const sp = `_cf_sp${++this.#depth}`;\n this.#driver.exec(`SAVEPOINT ${sp}`, []);\n const marks = [this.#ddl.length, this.#statements.length] as const;\n try {\n const r = fn();\n this.#driver.exec(`RELEASE ${sp}`, []);\n return r;\n } catch (e) {\n // SQLite rolled the whole transaction back by itself (#afterFailure): no savepoint left.\n if (!this.#inTxn) throw e;\n this.#driver.exec(`ROLLBACK TO ${sp}`, []);\n for (const f of this.rolledBack) f();\n this.#ddl.length = marks[0];\n this.#statements.length = marks[1];\n this.#driver.exec(`RELEASE ${sp}`, []);\n throw e;\n } finally {\n this.#depth--;\n }\n }\n\n /** Suspends auto-commit (used by the async `transaction()` which spans awaits). */\n hold(): () => void {\n this.#holds++;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n if (--this.#holds === 0) afterTurn(() => this.commit());\n };\n }\n\n /** True while an async transaction() holds auto-commit (no consistent snapshot possible). */\n get held(): boolean {\n return this.#holds > 0;\n }\n\n /** Commits the implicit transaction now (no-op if none, or if held). */\n commit(): void {\n if (this.#lost !== undefined && this.#holds === 0) {\n const cause = this.#lost;\n this.#lost = undefined;\n throw new Error(`the transaction's writes were rolled back after: ${sqliteMessage(cause)}`, {\n cause,\n });\n }\n if (!this.#inTxn || this.#holds > 0) return;\n let changes: CommitChanges | undefined;\n // Read-only transactions produce no log segment (\"IF NOT EXISTS\" DDL that changed\n // nothing included: the schema version tells).\n if (this.#capture && this.#ddl.length && this.#schemaVersion() === this.#schemaAtBegin)\n this.#ddl = [];\n if (this.#capture && (this.#ddl.length || this.#totalChanges() !== this.#changesAtBegin)) {\n // The log sequence number lives in the database, inside the same transaction.\n this.#driver.exec(LOG_TABLE, []);\n const row = this.#driver.exec(LOG_SEQ_READ, []).rows[0];\n const logSeq = Number(row?.[0] ?? 0) + 1;\n this.#driver.exec(LOG_SEQ_WRITE, [logSeq]);\n changes = {\n logSeq,\n ddl: this.#ddl,\n changeset: new Uint8Array(),\n statements: this.#statements,\n };\n }\n this.#inTxn = false;\n this.#wrote = false;\n this.#driver.exec(\"COMMIT\", []);\n if (this.#capture) {\n const changeset = this.#driver.captureTake!();\n if (changes) changes.changeset = changeset;\n this.#ddl = [];\n this.#statements = [];\n }\n this.#onCommit(changes);\n }\n\n /** Called after a rollback (lazily created internal tables may be gone). */\n readonly rolledBack = new Set<() => void>();\n\n rollback(): void {\n this.#lost = undefined;\n if (!this.#inTxn) return;\n this.#inTxn = false;\n this.#wrote = false;\n this.#driver.exec(\"ROLLBACK\", []);\n this.#driver.discardDirtyPages?.(); // pages a rolled-back transaction spilled are not a commit\n for (const f of this.rolledBack) f();\n if (this.#capture) {\n this.#driver.captureDiscard?.();\n this.#ddl = [];\n this.#statements = [];\n }\n }\n\n #ensureTxn(): void {\n if (this.#inTxn) return;\n this.#driver.exec(\"BEGIN\", []);\n if (this.#capture) {\n this.#driver.captureStart!();\n this.#changesAtBegin = this.#totalChanges();\n this.#schemaAtBegin = this.#schemaVersion();\n }\n this.#inTxn = true;\n afterTurn(() => this.commit());\n }\n}\n\n/** Parameters a statement expects: anonymous `?` count, highest `?NNN`, distinct named ones. */\nexport function countParameters(sql: string): number {\n let anon = 0;\n let maxNumbered = 0;\n const named = new Set<string>();\n const re = /'(?:[^']|'')*'|\"(?:[^\"]|\"\")*\"|--[^\\n]*|\\/\\*[\\s\\S]*?\\*\\/|\\?(\\d*)|([:@$][A-Za-z_]\\w*)/g;\n for (let m = re.exec(sql); m; m = re.exec(sql)) {\n if (m[1] !== undefined) {\n if (m[1] === \"\") anon++;\n else maxNumbered = Math.max(maxNumbered, Number(m[1]));\n } else if (m[2]) named.add(m[2]);\n }\n const positional = maxNumbered ? Math.max(maxNumbered, anon) : anon;\n return positional + named.size;\n}\n"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { InputGate } from "./gates.js";
|
|
2
|
+
import type { DurableObjectId } from "./id.js";
|
|
3
|
+
import type { DurableObjectStorage } from "./storage.js";
|
|
4
|
+
/** `ctx` passed to a Durable Object constructor. */
|
|
5
|
+
export declare class DurableObjectState {
|
|
6
|
+
#private;
|
|
7
|
+
/** Not readonly: an object woken by id alone gets its recorded name back (celld). */
|
|
8
|
+
id: DurableObjectId;
|
|
9
|
+
readonly storage: DurableObjectStorage;
|
|
10
|
+
constructor(id: DurableObjectId, storage: DurableObjectStorage, gate: InputGate, waitUntil: (p: Promise<unknown>) => void, onBlockFailure?: (e: unknown) => void);
|
|
11
|
+
/** No event is delivered to the object until `fn` settles. */
|
|
12
|
+
blockConcurrencyWhile<T>(fn: () => Promise<T>): Promise<T>;
|
|
13
|
+
waitUntil(p: Promise<unknown>): void;
|
|
14
|
+
/** `ctx.exports`: loopback handles of the Worker's exports (set by the host). */
|
|
15
|
+
exports: Record<string, unknown>;
|
|
16
|
+
/** `ctx.props`: what a facet's class handle was given as `{ props }` (set by the host). */
|
|
17
|
+
props: unknown;
|
|
18
|
+
/** `ctx.facets`: child objects with their own SQLite (set by the host). */
|
|
19
|
+
facets: {
|
|
20
|
+
get(name: string, start: () => unknown): Record<string, any>;
|
|
21
|
+
abort(name: string, reason?: unknown): void;
|
|
22
|
+
delete(name: string): Promise<void>;
|
|
23
|
+
};
|
|
24
|
+
/** Set by the ObjectHost: delivers an event to the live instance. */
|
|
25
|
+
attachDispatcher(dispatch: (fn: (instance: any) => unknown) => Promise<unknown>): void;
|
|
26
|
+
acceptWebSocket(ws: WebSocketLike, tags?: string[]): void;
|
|
27
|
+
getWebSockets(tag?: string): WebSocketLike[];
|
|
28
|
+
getTags(ws: WebSocketLike): string[];
|
|
29
|
+
setWebSocketAutoResponse(pair?: {
|
|
30
|
+
request: string;
|
|
31
|
+
response: string;
|
|
32
|
+
}): void;
|
|
33
|
+
getWebSocketAutoResponse(): {
|
|
34
|
+
request: string;
|
|
35
|
+
response: string;
|
|
36
|
+
} | null;
|
|
37
|
+
}
|
|
38
|
+
/** The server end of a WebSocketPair, as seen by the hibernation API. */
|
|
39
|
+
export interface WebSocketLike {
|
|
40
|
+
accept(): void;
|
|
41
|
+
send(data: string | ArrayBuffer | ArrayBufferView): void;
|
|
42
|
+
close(code?: number, reason?: string): void;
|
|
43
|
+
addEventListener(type: string, fn: (e: any) => void): void;
|
|
44
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/** `ctx` passed to a Durable Object constructor. */
|
|
2
|
+
export class DurableObjectState {
|
|
3
|
+
/** Not readonly: an object woken by id alone gets its recorded name back (celld). */
|
|
4
|
+
id;
|
|
5
|
+
storage;
|
|
6
|
+
#gate;
|
|
7
|
+
#waitUntil;
|
|
8
|
+
#onBlockFailure;
|
|
9
|
+
constructor(id, storage, gate, waitUntil, onBlockFailure = () => { }) {
|
|
10
|
+
this.#onBlockFailure = onBlockFailure;
|
|
11
|
+
this.id = id;
|
|
12
|
+
this.storage = storage;
|
|
13
|
+
this.#gate = gate;
|
|
14
|
+
this.#waitUntil = waitUntil;
|
|
15
|
+
}
|
|
16
|
+
/** Open blockConcurrencyWhile() sections (nested ones are open together). */
|
|
17
|
+
#blockDepth = 0;
|
|
18
|
+
/** No event is delivered to the object until `fn` settles. */
|
|
19
|
+
blockConcurrencyWhile(fn) {
|
|
20
|
+
// As workerd (io-context.h) and celld: at most 64 nested sections; the next throws at once.
|
|
21
|
+
if (this.#blockDepth >= 64)
|
|
22
|
+
throw new Error("blockConcurrencyWhile() calls are nested too deeply.");
|
|
23
|
+
this.#blockDepth++;
|
|
24
|
+
const p = this.#gate.runClosed(fn).finally(() => this.#blockDepth--);
|
|
25
|
+
// A failure resets the object even when the caller (typically the
|
|
26
|
+
// constructor) does not await the promise; the rejection is then observed.
|
|
27
|
+
p.catch((e) => this.#onBlockFailure(e));
|
|
28
|
+
return p;
|
|
29
|
+
}
|
|
30
|
+
waitUntil(p) {
|
|
31
|
+
this.#waitUntil(p);
|
|
32
|
+
}
|
|
33
|
+
/** `ctx.exports`: loopback handles of the Worker's exports (set by the host). */
|
|
34
|
+
exports = {};
|
|
35
|
+
/** `ctx.props`: what a facet's class handle was given as `{ props }` (set by the host). */
|
|
36
|
+
props;
|
|
37
|
+
/** `ctx.facets`: child objects with their own SQLite (set by the host). */
|
|
38
|
+
facets;
|
|
39
|
+
// ---- WebSocket hibernation API ------------------------------------------------
|
|
40
|
+
// Sockets accepted here belong to the RUNTIME, not to the object instance: their
|
|
41
|
+
// events are delivered as object events (through the input gate) to
|
|
42
|
+
// webSocketMessage / webSocketClose / webSocketError on whatever instance is live.
|
|
43
|
+
#dispatch;
|
|
44
|
+
#sockets = new Map();
|
|
45
|
+
#autoResponse;
|
|
46
|
+
/** Set by the ObjectHost: delivers an event to the live instance. */
|
|
47
|
+
attachDispatcher(dispatch) {
|
|
48
|
+
this.#dispatch = dispatch;
|
|
49
|
+
}
|
|
50
|
+
acceptWebSocket(ws, tags = []) {
|
|
51
|
+
if (this.#sockets.has(ws))
|
|
52
|
+
throw new Error("WebSocket already accepted");
|
|
53
|
+
if (tags.length > 10)
|
|
54
|
+
throw new Error("A WebSocket can have at most 10 tags");
|
|
55
|
+
this.#sockets.set(ws, [...tags]);
|
|
56
|
+
ws.hibernatable = true;
|
|
57
|
+
// webSocketMessage() gets string | ArrayBuffer, whatever the pair's default binaryType.
|
|
58
|
+
ws.binaryType = "arraybuffer";
|
|
59
|
+
ws.accept();
|
|
60
|
+
const deliver = (fn) => this.#dispatch?.(fn).catch(() => { });
|
|
61
|
+
ws.addEventListener("message", (e) => {
|
|
62
|
+
const auto = this.#autoResponse;
|
|
63
|
+
if (auto && e.data === auto.request) {
|
|
64
|
+
ws.send(auto.response);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
void deliver((o) => o.webSocketMessage?.(ws, e.data));
|
|
68
|
+
});
|
|
69
|
+
ws.addEventListener("close", (e) => {
|
|
70
|
+
this.#sockets.delete(ws);
|
|
71
|
+
void deliver((o) => o.webSocketClose?.(ws, e.code, e.reason, e.wasClean));
|
|
72
|
+
});
|
|
73
|
+
ws.addEventListener("error", (e) => void deliver((o) => o.webSocketError?.(ws, e.error ?? e)));
|
|
74
|
+
}
|
|
75
|
+
getWebSockets(tag) {
|
|
76
|
+
return [...this.#sockets]
|
|
77
|
+
.filter(([, tags]) => tag === undefined || tags.includes(tag))
|
|
78
|
+
.map(([ws]) => ws);
|
|
79
|
+
}
|
|
80
|
+
getTags(ws) {
|
|
81
|
+
const tags = this.#sockets.get(ws);
|
|
82
|
+
if (!tags)
|
|
83
|
+
throw new Error("WebSocket was not accepted with acceptWebSocket()");
|
|
84
|
+
return [...tags];
|
|
85
|
+
}
|
|
86
|
+
setWebSocketAutoResponse(pair) {
|
|
87
|
+
this.#autoResponse = pair;
|
|
88
|
+
}
|
|
89
|
+
getWebSocketAutoResponse() {
|
|
90
|
+
return this.#autoResponse ?? null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=state.js.map
|