@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,295 @@
|
|
|
1
|
+
import { CellsCloseEvent, checkClose, toFrameData } from "./frames.js";
|
|
2
|
+
const kPort = Symbol("cellb.ws.port");
|
|
3
|
+
/** Server ends accepted in this realm and not yet closed (see `CfWebSocket.goAway`). */
|
|
4
|
+
const acceptedEnds = new Set();
|
|
5
|
+
/**
|
|
6
|
+
* Cloudflare Workers' server-side WebSocket (one end of a WebSocketPair):
|
|
7
|
+
* events are delivered only after `accept()`; `send`/`close` as in workerd.
|
|
8
|
+
* Hibernation (`ctx.acceptWebSocket`) is a later prototype.
|
|
9
|
+
*/
|
|
10
|
+
export class CfWebSocket extends EventTarget {
|
|
11
|
+
static READY_STATE_CONNECTING = 0;
|
|
12
|
+
static READY_STATE_OPEN = 1;
|
|
13
|
+
static READY_STATE_CLOSING = 2;
|
|
14
|
+
static READY_STATE_CLOSED = 3;
|
|
15
|
+
readyState = 1;
|
|
16
|
+
url = null;
|
|
17
|
+
protocol = null;
|
|
18
|
+
extensions = null;
|
|
19
|
+
#binaryType = "arraybuffer";
|
|
20
|
+
/** How binary messages arrive; other values are ignored, as in browsers. */
|
|
21
|
+
get binaryType() {
|
|
22
|
+
return this.#binaryType;
|
|
23
|
+
}
|
|
24
|
+
set binaryType(v) {
|
|
25
|
+
if (v === "blob" || v === "arraybuffer")
|
|
26
|
+
this.#binaryType = v;
|
|
27
|
+
}
|
|
28
|
+
[kPort];
|
|
29
|
+
#accepted = false;
|
|
30
|
+
#queued = [];
|
|
31
|
+
#attachment;
|
|
32
|
+
#lastPing = 0;
|
|
33
|
+
#watch;
|
|
34
|
+
constructor(port) {
|
|
35
|
+
super();
|
|
36
|
+
this[kPort] = port;
|
|
37
|
+
port.onmessage = (e) => {
|
|
38
|
+
const f = e.data;
|
|
39
|
+
if (f.t === "p")
|
|
40
|
+
return this.#ping(f.hb); // answered even before accept()
|
|
41
|
+
if (this.#accepted)
|
|
42
|
+
this.#frame(f);
|
|
43
|
+
else
|
|
44
|
+
this.#queued.push(f);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Heartbeat: answer the client's ping; close 1006 when pings stop for 3 periods. */
|
|
48
|
+
#ping(hb) {
|
|
49
|
+
this.#lastPing = Date.now();
|
|
50
|
+
this[kPort]?.postMessage({ t: "q" });
|
|
51
|
+
if (this.#watch || !hb)
|
|
52
|
+
return;
|
|
53
|
+
this.#watch = setInterval(() => {
|
|
54
|
+
if (this.readyState === 3)
|
|
55
|
+
return clearInterval(this.#watch);
|
|
56
|
+
if (Date.now() - this.#lastPing > 3 * hb)
|
|
57
|
+
this.#gone();
|
|
58
|
+
}, hb);
|
|
59
|
+
}
|
|
60
|
+
/** The client stopped pinging (tab closed, worker killed): abnormal closure. */
|
|
61
|
+
#gone() {
|
|
62
|
+
clearInterval(this.#watch);
|
|
63
|
+
if (this.readyState === 3)
|
|
64
|
+
return;
|
|
65
|
+
this.readyState = 3;
|
|
66
|
+
acceptedEnds.delete(this);
|
|
67
|
+
this[kPort]?.close();
|
|
68
|
+
this.dispatchEvent(new CellsCloseEvent("close", { code: 1006, reason: "", wasClean: false }));
|
|
69
|
+
}
|
|
70
|
+
/** The other end of the WebSocketPair (the runtime checks how the server end was accepted). */
|
|
71
|
+
peer;
|
|
72
|
+
/** Accepted through ctx.acceptWebSocket() (hibernatable) rather than accept(). */
|
|
73
|
+
hibernatable = false;
|
|
74
|
+
get accepted() {
|
|
75
|
+
return this.#accepted;
|
|
76
|
+
}
|
|
77
|
+
accept() {
|
|
78
|
+
if (this.#accepted)
|
|
79
|
+
return;
|
|
80
|
+
if (!this[kPort])
|
|
81
|
+
throw new TypeError("This WebSocket end was handed to a client; it cannot be accepted.");
|
|
82
|
+
this.#accepted = true;
|
|
83
|
+
acceptedEnds.add(this);
|
|
84
|
+
this[kPort].start?.();
|
|
85
|
+
for (const f of this.#queued.splice(0))
|
|
86
|
+
this.#frame(f);
|
|
87
|
+
}
|
|
88
|
+
serializeAttachment(v) {
|
|
89
|
+
this.#attachment = structuredClone(v);
|
|
90
|
+
}
|
|
91
|
+
deserializeAttachment() {
|
|
92
|
+
return structuredClone(this.#attachment);
|
|
93
|
+
}
|
|
94
|
+
#frame(f) {
|
|
95
|
+
if (f.t === "m") {
|
|
96
|
+
const data = typeof f.d !== "string" && this.#binaryType === "blob" ? new Blob([f.d]) : f.d;
|
|
97
|
+
this.dispatchEvent(new MessageEvent("message", { data }));
|
|
98
|
+
this[kPort]?.postMessage({ t: "a" }); // the sender's bufferedAmount drains
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (f.t !== "c")
|
|
102
|
+
return;
|
|
103
|
+
const wasOpen = this.readyState === 1;
|
|
104
|
+
if (wasOpen)
|
|
105
|
+
this[kPort].postMessage({ t: "c", code: f.code, reason: f.reason });
|
|
106
|
+
this.readyState = 3;
|
|
107
|
+
acceptedEnds.delete(this);
|
|
108
|
+
clearInterval(this.#watch);
|
|
109
|
+
this[kPort].close();
|
|
110
|
+
this.dispatchEvent(new CellsCloseEvent("close", { code: f.code, reason: f.reason, wasClean: true }));
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Closes every server end accepted in this realm with 1001 (going away). A shard worker that
|
|
114
|
+
* hands its cells to another tab does it before it stops, so that clients reconnect at once
|
|
115
|
+
* instead of noticing through the heartbeat; Worker code cannot send 1001 itself (`close`).
|
|
116
|
+
*/
|
|
117
|
+
static goAway(reason = "moving to another worker") {
|
|
118
|
+
for (const ws of acceptedEnds) {
|
|
119
|
+
acceptedEnds.delete(ws);
|
|
120
|
+
if (ws.readyState >= 2)
|
|
121
|
+
continue;
|
|
122
|
+
ws.readyState = 2;
|
|
123
|
+
ws[kPort]?.postMessage({ t: "c", code: 1001, reason });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
send(data) {
|
|
127
|
+
// celld lets either end of a pair send before accept() (workerd refuses); frames wait in
|
|
128
|
+
// the port until the other end listens.
|
|
129
|
+
if (this.readyState !== 1)
|
|
130
|
+
throw new TypeError("Can't call WebSocket send() after close().");
|
|
131
|
+
const d = toFrameData(data);
|
|
132
|
+
this[kPort].postMessage({ t: "m", d }, typeof d === "string" ? [] : [d]);
|
|
133
|
+
}
|
|
134
|
+
close(code, reason) {
|
|
135
|
+
checkClose(code, reason);
|
|
136
|
+
if (this.readyState >= 2)
|
|
137
|
+
return;
|
|
138
|
+
this.readyState = 2;
|
|
139
|
+
this[kPort].postMessage({ t: "c", code: code ?? 1005, reason: reason ?? "" });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** The host's own WebSocket (Node's, or the browser's): the client sockets Worker code opens. */
|
|
143
|
+
const HostWebSocket = globalThis.WebSocket;
|
|
144
|
+
/**
|
|
145
|
+
* The `WebSocket` global of Worker code. On workerd one class covers both ends of a
|
|
146
|
+
* WebSocketPair and the client sockets `new WebSocket(url)` opens, and libraries rely on that:
|
|
147
|
+
* the Agents SDK (partyserver) reads attachments with
|
|
148
|
+
* `WebSocket.prototype.deserializeAttachment.call(ws)` and compares `readyState` with
|
|
149
|
+
* `WebSocket.READY_STATE_OPEN`. So its prototype is the server end's (`CfWebSocket`), its
|
|
150
|
+
* statics are workerd's, `instanceof` holds for both kinds, and `new WebSocket(url)` still opens
|
|
151
|
+
* the host's client socket.
|
|
152
|
+
*/
|
|
153
|
+
export const WorkersWebSocket = (() => {
|
|
154
|
+
function WebSocket(url, protocols) {
|
|
155
|
+
if (!new.target)
|
|
156
|
+
throw new TypeError("Failed to construct 'WebSocket': Please use the 'new' operator.");
|
|
157
|
+
if (!HostWebSocket)
|
|
158
|
+
throw new Error("WebSocket clients are not available in this realm.");
|
|
159
|
+
return new HostWebSocket(url, protocols);
|
|
160
|
+
}
|
|
161
|
+
WebSocket.prototype = CfWebSocket.prototype;
|
|
162
|
+
const states = { CONNECTING: 0, OPEN: 1, CLOSING: 2, CLOSED: 3 };
|
|
163
|
+
for (const [name, value] of Object.entries(states)) {
|
|
164
|
+
Object.defineProperty(WebSocket, name, { value, enumerable: true });
|
|
165
|
+
Object.defineProperty(WebSocket, `READY_STATE_${name}`, { value, enumerable: true });
|
|
166
|
+
}
|
|
167
|
+
Object.defineProperty(WebSocket, Symbol.hasInstance, {
|
|
168
|
+
value: (v) => v instanceof CfWebSocket || (HostWebSocket !== undefined && v instanceof HostWebSocket),
|
|
169
|
+
});
|
|
170
|
+
return WebSocket;
|
|
171
|
+
})();
|
|
172
|
+
/** `new WebSocketPair()` → `{ 0: client, 1: server }`, entangled over a MessageChannel. */
|
|
173
|
+
export class WebSocketPair {
|
|
174
|
+
0;
|
|
175
|
+
1;
|
|
176
|
+
constructor() {
|
|
177
|
+
const { port1, port2 } = new MessageChannel();
|
|
178
|
+
this[0] = new CfWebSocket(port1);
|
|
179
|
+
this[1] = new CfWebSocket(port2);
|
|
180
|
+
this[0].peer = this[1];
|
|
181
|
+
this[1].peer = this[0];
|
|
182
|
+
}
|
|
183
|
+
/** `const [client, server] = new WebSocketPair()`, as in workerd. */
|
|
184
|
+
*[Symbol.iterator]() {
|
|
185
|
+
yield this[0];
|
|
186
|
+
yield this[1];
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* `WebSocketPair` under the `websocket_standard_binary_type` compatibility flag: both ends
|
|
191
|
+
* start with `binaryType` "blob", as browsers' WebSockets do. Without it they start with
|
|
192
|
+
* "arraybuffer", workerd's older default.
|
|
193
|
+
*/
|
|
194
|
+
export class StandardWebSocketPair extends WebSocketPair {
|
|
195
|
+
constructor() {
|
|
196
|
+
super();
|
|
197
|
+
this[0].binaryType = "blob";
|
|
198
|
+
this[1].binaryType = "blob";
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Detaches the transport of the CLIENT end returned in a 101 response, so the
|
|
203
|
+
* runtime can hand the raw MessagePort to the real client (transferable).
|
|
204
|
+
*/
|
|
205
|
+
export function takeClientPort(ws) {
|
|
206
|
+
const port = ws[kPort];
|
|
207
|
+
if (!port)
|
|
208
|
+
throw new TypeError("WebSocket end already handed over");
|
|
209
|
+
ws[kPort] = undefined;
|
|
210
|
+
port.onmessage = null;
|
|
211
|
+
ws.readyState = 3; // handed over: this end must not answer pings any more
|
|
212
|
+
return port;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* `Response` that also accepts Cloudflare's `{ status: 101, webSocket }` init —
|
|
216
|
+
* the platform `Response` rejects status 101. Provided to user code via ~deps.
|
|
217
|
+
*/
|
|
218
|
+
/** The platform `Response`, as this module sees it (it is external to user bundles). */
|
|
219
|
+
const HostResponse = Response;
|
|
220
|
+
/** Browsers drop `Set-Cookie` from every Response they build (Node keeps it). */
|
|
221
|
+
const dropsSetCookie = !new HostResponse(null, { headers: { "set-cookie": "a=b" } }).headers.has("set-cookie");
|
|
222
|
+
export class CellsResponse extends Response {
|
|
223
|
+
#status;
|
|
224
|
+
webSocket;
|
|
225
|
+
constructor(body, init = {}) {
|
|
226
|
+
const upgrade = init.status === 101;
|
|
227
|
+
// The init's members read one by one, as Fetch reads a dictionary: an init that is itself a
|
|
228
|
+
// Response (`new Response(body, response)`, as opencode's SDK does) keeps its headers and
|
|
229
|
+
// statusText, which a spread would drop (they are getters on its prototype).
|
|
230
|
+
super(upgrade ? null : body, {
|
|
231
|
+
status: upgrade ? 200 : init.status,
|
|
232
|
+
statusText: init.statusText,
|
|
233
|
+
headers: init.headers,
|
|
234
|
+
});
|
|
235
|
+
this.#status = init.status ?? 200;
|
|
236
|
+
this.webSocket = init.webSocket ?? null;
|
|
237
|
+
if (dropsSetCookie) {
|
|
238
|
+
// In a browser the platform's headers drop `Set-Cookie`, which Workers set (Astro appends
|
|
239
|
+
// its cookies to the response): the response keeps its headers in a standalone `Headers`,
|
|
240
|
+
// the ones the platform derived (content-type) plus the Set-Cookie values of the init.
|
|
241
|
+
const headers = new Headers(super.headers);
|
|
242
|
+
const given = init.headers instanceof Headers ? init.headers : new Headers(init.headers);
|
|
243
|
+
for (const c of given.getSetCookie())
|
|
244
|
+
headers.append("set-cookie", c);
|
|
245
|
+
Object.defineProperty(this, "headers", {
|
|
246
|
+
value: headers,
|
|
247
|
+
configurable: true,
|
|
248
|
+
enumerable: true,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
get status() {
|
|
253
|
+
// Static helpers (CellsResponse.json(), .redirect(), .error()) may build instances
|
|
254
|
+
// without running this constructor: fall back to the platform's status.
|
|
255
|
+
return #status in this ? this.#status : super.status;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Every platform `Response` is a Workers `Response`, as on workerd: `Response.json()`,
|
|
259
|
+
* `Response.redirect()` and `Response.error()` (the platform's static helpers, which build
|
|
260
|
+
* platform instances, not instances of this subclass) and `fetch()` results pass
|
|
261
|
+
* `instanceof Response` in Worker code. Astro checks every endpoint's result that way.
|
|
262
|
+
*/
|
|
263
|
+
static [Symbol.hasInstance](v) {
|
|
264
|
+
return v instanceof HostResponse;
|
|
265
|
+
}
|
|
266
|
+
// In a browser the platform's static helpers build platform responses, whose headers drop
|
|
267
|
+
// `Set-Cookie`: these build instances of this class there (`Response.json()` is how most
|
|
268
|
+
// APIs answer, and their cookies are appended to it afterwards).
|
|
269
|
+
static json(data, init = {}) {
|
|
270
|
+
if (!dropsSetCookie)
|
|
271
|
+
return super.json(data, init);
|
|
272
|
+
const headers = new Headers(init.headers);
|
|
273
|
+
if (!headers.has("content-type"))
|
|
274
|
+
headers.set("content-type", "application/json");
|
|
275
|
+
return new CellsResponse(JSON.stringify(data), { ...init, headers });
|
|
276
|
+
}
|
|
277
|
+
static redirect(url, status = 302) {
|
|
278
|
+
if (!dropsSetCookie)
|
|
279
|
+
return super.redirect(url, status);
|
|
280
|
+
if (![301, 302, 303, 307, 308].includes(status))
|
|
281
|
+
throw new RangeError(`Invalid status ${status}`);
|
|
282
|
+
const base = globalThis.location?.href;
|
|
283
|
+
return new CellsResponse(null, { status, headers: { location: new URL(url, base).href } });
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/** Workers `WebSocketRequestResponsePair` (ctx.setWebSocketAutoResponse). */
|
|
287
|
+
export class WebSocketRequestResponsePair {
|
|
288
|
+
request;
|
|
289
|
+
response;
|
|
290
|
+
constructor(request, response) {
|
|
291
|
+
this.request = request;
|
|
292
|
+
this.response = response;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/ws/server.ts"],"names":[],"mappings":"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","sourcesContent":["import { CellsCloseEvent, checkClose, type Frame, toFrameData } from \"./frames.js\";\n\nconst kPort = Symbol(\"cellb.ws.port\");\n/** Server ends accepted in this realm and not yet closed (see `CfWebSocket.goAway`). */\nconst acceptedEnds = new Set<CfWebSocket>();\n\n/**\n * Cloudflare Workers' server-side WebSocket (one end of a WebSocketPair):\n * events are delivered only after `accept()`; `send`/`close` as in workerd.\n * Hibernation (`ctx.acceptWebSocket`) is a later prototype.\n */\nexport class CfWebSocket extends EventTarget {\n static readonly READY_STATE_CONNECTING = 0;\n static readonly READY_STATE_OPEN = 1;\n static readonly READY_STATE_CLOSING = 2;\n static readonly READY_STATE_CLOSED = 3;\n readyState = 1;\n url: string | null = null;\n\n protocol: string | null = null;\n extensions: string | null = null;\n #binaryType: \"blob\" | \"arraybuffer\" = \"arraybuffer\";\n /** How binary messages arrive; other values are ignored, as in browsers. */\n get binaryType(): \"blob\" | \"arraybuffer\" {\n return this.#binaryType;\n }\n set binaryType(v: \"blob\" | \"arraybuffer\") {\n if (v === \"blob\" || v === \"arraybuffer\") this.#binaryType = v;\n }\n [kPort]: MessagePort | undefined;\n #accepted = false;\n #queued: Frame[] = [];\n #attachment: unknown;\n\n #lastPing = 0;\n #watch: ReturnType<typeof setInterval> | undefined;\n\n constructor(port: MessagePort) {\n super();\n this[kPort] = port;\n port.onmessage = (e) => {\n const f = e.data as Frame;\n if (f.t === \"p\") return this.#ping(f.hb); // answered even before accept()\n if (this.#accepted) this.#frame(f);\n else this.#queued.push(f);\n };\n }\n\n /** Heartbeat: answer the client's ping; close 1006 when pings stop for 3 periods. */\n #ping(hb: number): void {\n this.#lastPing = Date.now();\n this[kPort]?.postMessage({ t: \"q\" } satisfies Frame);\n if (this.#watch || !hb) return;\n this.#watch = setInterval(() => {\n if (this.readyState === 3) return clearInterval(this.#watch);\n if (Date.now() - this.#lastPing > 3 * hb) this.#gone();\n }, hb);\n }\n\n /** The client stopped pinging (tab closed, worker killed): abnormal closure. */\n #gone(): void {\n clearInterval(this.#watch);\n if (this.readyState === 3) return;\n this.readyState = 3;\n acceptedEnds.delete(this);\n this[kPort]?.close();\n this.dispatchEvent(new CellsCloseEvent(\"close\", { code: 1006, reason: \"\", wasClean: false }));\n }\n\n /** The other end of the WebSocketPair (the runtime checks how the server end was accepted). */\n peer?: CfWebSocket;\n /** Accepted through ctx.acceptWebSocket() (hibernatable) rather than accept(). */\n hibernatable = false;\n get accepted(): boolean {\n return this.#accepted;\n }\n\n accept(): void {\n if (this.#accepted) return;\n if (!this[kPort])\n throw new TypeError(\"This WebSocket end was handed to a client; it cannot be accepted.\");\n this.#accepted = true;\n acceptedEnds.add(this);\n this[kPort].start?.();\n for (const f of this.#queued.splice(0)) this.#frame(f);\n }\n\n serializeAttachment(v: unknown): void {\n this.#attachment = structuredClone(v);\n }\n deserializeAttachment(): unknown {\n return structuredClone(this.#attachment);\n }\n\n #frame(f: Frame): void {\n if (f.t === \"m\") {\n const data = typeof f.d !== \"string\" && this.#binaryType === \"blob\" ? new Blob([f.d]) : f.d;\n this.dispatchEvent(new MessageEvent(\"message\", { data }));\n this[kPort]?.postMessage({ t: \"a\" } satisfies Frame); // the sender's bufferedAmount drains\n return;\n }\n if (f.t !== \"c\") return;\n const wasOpen = this.readyState === 1;\n if (wasOpen)\n this[kPort]!.postMessage({ t: \"c\", code: f.code, reason: f.reason } satisfies Frame);\n this.readyState = 3;\n acceptedEnds.delete(this);\n clearInterval(this.#watch);\n this[kPort]!.close();\n this.dispatchEvent(\n new CellsCloseEvent(\"close\", { code: f.code, reason: f.reason, wasClean: true }),\n );\n }\n\n /**\n * Closes every server end accepted in this realm with 1001 (going away). A shard worker that\n * hands its cells to another tab does it before it stops, so that clients reconnect at once\n * instead of noticing through the heartbeat; Worker code cannot send 1001 itself (`close`).\n */\n static goAway(reason = \"moving to another worker\"): void {\n for (const ws of acceptedEnds) {\n acceptedEnds.delete(ws);\n if (ws.readyState >= 2) continue;\n ws.readyState = 2;\n ws[kPort]?.postMessage({ t: \"c\", code: 1001, reason } satisfies Frame);\n }\n }\n\n send(data: string | ArrayBuffer | ArrayBufferView): void {\n // celld lets either end of a pair send before accept() (workerd refuses); frames wait in\n // the port until the other end listens.\n if (this.readyState !== 1) throw new TypeError(\"Can't call WebSocket send() after close().\");\n const d = toFrameData(data);\n this[kPort]!.postMessage({ t: \"m\", d } satisfies Frame, typeof d === \"string\" ? [] : [d]);\n }\n\n close(code?: number, reason?: string): void {\n checkClose(code, reason);\n if (this.readyState >= 2) return;\n this.readyState = 2;\n this[kPort]!.postMessage({ t: \"c\", code: code ?? 1005, reason: reason ?? \"\" } satisfies Frame);\n }\n}\n\n/** The host's own WebSocket (Node's, or the browser's): the client sockets Worker code opens. */\nconst HostWebSocket = (\n globalThis as { WebSocket?: new (url: string, p?: string | string[]) => object }\n).WebSocket;\n\n/**\n * The `WebSocket` global of Worker code. On workerd one class covers both ends of a\n * WebSocketPair and the client sockets `new WebSocket(url)` opens, and libraries rely on that:\n * the Agents SDK (partyserver) reads attachments with\n * `WebSocket.prototype.deserializeAttachment.call(ws)` and compares `readyState` with\n * `WebSocket.READY_STATE_OPEN`. So its prototype is the server end's (`CfWebSocket`), its\n * statics are workerd's, `instanceof` holds for both kinds, and `new WebSocket(url)` still opens\n * the host's client socket.\n */\nexport const WorkersWebSocket = (() => {\n function WebSocket(this: unknown, url: string, protocols?: string | string[]): object {\n if (!new.target)\n throw new TypeError(\"Failed to construct 'WebSocket': Please use the 'new' operator.\");\n if (!HostWebSocket) throw new Error(\"WebSocket clients are not available in this realm.\");\n return new HostWebSocket(url, protocols);\n }\n WebSocket.prototype = CfWebSocket.prototype;\n const states = { CONNECTING: 0, OPEN: 1, CLOSING: 2, CLOSED: 3 } as const;\n for (const [name, value] of Object.entries(states)) {\n Object.defineProperty(WebSocket, name, { value, enumerable: true });\n Object.defineProperty(WebSocket, `READY_STATE_${name}`, { value, enumerable: true });\n }\n Object.defineProperty(WebSocket, Symbol.hasInstance, {\n value: (v: unknown) =>\n v instanceof CfWebSocket || (HostWebSocket !== undefined && v instanceof HostWebSocket),\n });\n return WebSocket as unknown as typeof CfWebSocket & {\n new (url: string, protocols?: string | string[]): CfWebSocket;\n readonly CONNECTING: 0;\n readonly OPEN: 1;\n readonly CLOSING: 2;\n readonly CLOSED: 3;\n };\n})();\n\n/** `new WebSocketPair()` → `{ 0: client, 1: server }`, entangled over a MessageChannel. */\nexport class WebSocketPair {\n 0: CfWebSocket;\n 1: CfWebSocket;\n constructor() {\n const { port1, port2 } = new MessageChannel();\n this[0] = new CfWebSocket(port1);\n this[1] = new CfWebSocket(port2);\n this[0].peer = this[1];\n this[1].peer = this[0];\n }\n /** `const [client, server] = new WebSocketPair()`, as in workerd. */\n *[Symbol.iterator](): IterableIterator<CfWebSocket> {\n yield this[0];\n yield this[1];\n }\n}\n\n/**\n * `WebSocketPair` under the `websocket_standard_binary_type` compatibility flag: both ends\n * start with `binaryType` \"blob\", as browsers' WebSockets do. Without it they start with\n * \"arraybuffer\", workerd's older default.\n */\nexport class StandardWebSocketPair extends WebSocketPair {\n constructor() {\n super();\n this[0].binaryType = \"blob\";\n this[1].binaryType = \"blob\";\n }\n}\n\n/**\n * Detaches the transport of the CLIENT end returned in a 101 response, so the\n * runtime can hand the raw MessagePort to the real client (transferable).\n */\nexport function takeClientPort(ws: CfWebSocket): MessagePort {\n const port = ws[kPort];\n if (!port) throw new TypeError(\"WebSocket end already handed over\");\n ws[kPort] = undefined;\n port.onmessage = null;\n ws.readyState = 3; // handed over: this end must not answer pings any more\n return port;\n}\n\n/**\n * `Response` that also accepts Cloudflare's `{ status: 101, webSocket }` init —\n * the platform `Response` rejects status 101. Provided to user code via ~deps.\n */\n/** The platform `Response`, as this module sees it (it is external to user bundles). */\nconst HostResponse = Response;\n\n/** Browsers drop `Set-Cookie` from every Response they build (Node keeps it). */\nconst dropsSetCookie = !new HostResponse(null, { headers: { \"set-cookie\": \"a=b\" } }).headers.has(\n \"set-cookie\",\n);\n\nexport class CellsResponse extends Response {\n readonly #status: number;\n readonly webSocket: CfWebSocket | null;\n constructor(\n body?: BodyInit | null,\n init: ResponseInit & { webSocket?: CfWebSocket | null } = {},\n ) {\n const upgrade = init.status === 101;\n // The init's members read one by one, as Fetch reads a dictionary: an init that is itself a\n // Response (`new Response(body, response)`, as opencode's SDK does) keeps its headers and\n // statusText, which a spread would drop (they are getters on its prototype).\n super(upgrade ? null : body, {\n status: upgrade ? 200 : init.status,\n statusText: init.statusText,\n headers: init.headers,\n });\n this.#status = init.status ?? 200;\n this.webSocket = init.webSocket ?? null;\n if (dropsSetCookie) {\n // In a browser the platform's headers drop `Set-Cookie`, which Workers set (Astro appends\n // its cookies to the response): the response keeps its headers in a standalone `Headers`,\n // the ones the platform derived (content-type) plus the Set-Cookie values of the init.\n const headers = new Headers(super.headers);\n const given = init.headers instanceof Headers ? init.headers : new Headers(init.headers);\n for (const c of given.getSetCookie()) headers.append(\"set-cookie\", c);\n Object.defineProperty(this, \"headers\", {\n value: headers,\n configurable: true,\n enumerable: true,\n });\n }\n }\n get status(): number {\n // Static helpers (CellsResponse.json(), .redirect(), .error()) may build instances\n // without running this constructor: fall back to the platform's status.\n return #status in this ? this.#status : super.status;\n }\n\n /**\n * Every platform `Response` is a Workers `Response`, as on workerd: `Response.json()`,\n * `Response.redirect()` and `Response.error()` (the platform's static helpers, which build\n * platform instances, not instances of this subclass) and `fetch()` results pass\n * `instanceof Response` in Worker code. Astro checks every endpoint's result that way.\n */\n static [Symbol.hasInstance](v: unknown): boolean {\n return v instanceof HostResponse;\n }\n\n // In a browser the platform's static helpers build platform responses, whose headers drop\n // `Set-Cookie`: these build instances of this class there (`Response.json()` is how most\n // APIs answer, and their cookies are appended to it afterwards).\n static override json(data: unknown, init: ResponseInit = {}): Response {\n if (!dropsSetCookie) return super.json(data, init);\n const headers = new Headers(init.headers);\n if (!headers.has(\"content-type\")) headers.set(\"content-type\", \"application/json\");\n return new CellsResponse(JSON.stringify(data), { ...init, headers });\n }\n\n static override redirect(url: string | URL, status = 302): Response {\n if (!dropsSetCookie) return super.redirect(url, status);\n if (![301, 302, 303, 307, 308].includes(status))\n throw new RangeError(`Invalid status ${status}`);\n const base = (globalThis as { location?: { href: string } }).location?.href;\n return new CellsResponse(null, { status, headers: { location: new URL(url, base).href } });\n }\n}\n\n/** Workers `WebSocketRequestResponsePair` (ctx.setWebSocketAutoResponse). */\nexport class WebSocketRequestResponsePair {\n readonly request: string;\n readonly response: string;\n constructor(request: string, response: string) {\n this.request = request;\n this.response = response;\n }\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WebSocketConnector } from "./client.js";
|
|
2
|
+
/** The message a page posts to the ServiceWorker to open a socket (a reply port rides along). */
|
|
3
|
+
export declare const SW_SOCKET = "cells-ws";
|
|
4
|
+
/**
|
|
5
|
+
* Page-side connector: asks the controlling ServiceWorker (a CellRouter) to open
|
|
6
|
+
* a socket and receives the socket's MessagePort in return.
|
|
7
|
+
* `new (createWebSocketClass(serviceWorkerConnector()))(url)` then behaves like a
|
|
8
|
+
* browser WebSocket towards a Durable Object in a shard worker.
|
|
9
|
+
*/
|
|
10
|
+
export declare function serviceWorkerConnector(sw?: () => Promise<ServiceWorker>): WebSocketConnector;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** The message a page posts to the ServiceWorker to open a socket (a reply port rides along). */
|
|
2
|
+
export const SW_SOCKET = "cells-ws";
|
|
3
|
+
/**
|
|
4
|
+
* Page-side connector: asks the controlling ServiceWorker (a CellRouter) to open
|
|
5
|
+
* a socket and receives the socket's MessagePort in return.
|
|
6
|
+
* `new (createWebSocketClass(serviceWorkerConnector()))(url)` then behaves like a
|
|
7
|
+
* browser WebSocket towards a Durable Object in a shard worker.
|
|
8
|
+
*/
|
|
9
|
+
export function serviceWorkerConnector(sw = async () => {
|
|
10
|
+
const reg = await navigator.serviceWorker.ready;
|
|
11
|
+
return navigator.serviceWorker.controller ?? reg.active;
|
|
12
|
+
}) {
|
|
13
|
+
return async (url, protocols) => {
|
|
14
|
+
const target = await sw();
|
|
15
|
+
const { port1, port2 } = new MessageChannel();
|
|
16
|
+
const answer = new Promise((resolve) => (port1.onmessage = (e) => resolve(e.data)));
|
|
17
|
+
target.postMessage({ type: SW_SOCKET, url, protocols }, [port2]);
|
|
18
|
+
const a = await answer;
|
|
19
|
+
port1.close();
|
|
20
|
+
if (!a.ok || !a.port)
|
|
21
|
+
throw new Error(a.error ?? "WebSocket refused");
|
|
22
|
+
return { port: a.port, protocol: a.protocol };
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=sw-connector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sw-connector.js","sourceRoot":"","sources":["../../src/ws/sw-connector.ts"],"names":[],"mappings":"AAEA,iGAAiG;AACjG,MAAM,CAAC,MAAM,SAAS,GAAG,UAAU,CAAC;AAEpC;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,EAAE,GAAiC,KAAK,IAAI,EAAE;IAC5C,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC;IAChD,OAAO,SAAS,CAAC,aAAa,CAAC,UAAU,IAAK,GAAG,CAAC,MAAwB,CAAC;AAC7E,CAAC;IAED,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE;QAC9B,MAAM,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC;QAC1B,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,cAAc,EAAE,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,OAAO,CAKvB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5D,MAAM,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QACjE,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC;QACvB,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,mBAAmB,CAAC,CAAC;QACtE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAChD,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type { WebSocketConnector } from \"./client.js\";\n\n/** The message a page posts to the ServiceWorker to open a socket (a reply port rides along). */\nexport const SW_SOCKET = \"cells-ws\";\n\n/**\n * Page-side connector: asks the controlling ServiceWorker (a CellRouter) to open\n * a socket and receives the socket's MessagePort in return.\n * `new (createWebSocketClass(serviceWorkerConnector()))(url)` then behaves like a\n * browser WebSocket towards a Durable Object in a shard worker.\n */\nexport function serviceWorkerConnector(\n sw: () => Promise<ServiceWorker> = async () => {\n const reg = await navigator.serviceWorker.ready;\n return navigator.serviceWorker.controller ?? (reg.active as ServiceWorker);\n },\n): WebSocketConnector {\n return async (url, protocols) => {\n const target = await sw();\n const { port1, port2 } = new MessageChannel();\n const answer = new Promise<{\n ok: boolean;\n port?: MessagePort;\n protocol?: string;\n error?: string;\n }>((resolve) => (port1.onmessage = (e) => resolve(e.data)));\n target.postMessage({ type: SW_SOCKET, url, protocols }, [port2]);\n const a = await answer;\n port1.close();\n if (!a.ok || !a.port) throw new Error(a.error ?? \"WebSocket refused\");\n return { port: a.port, protocol: a.protocol };\n };\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare function withUpgrade<R extends Request>(req: R, value?: string, extra?: HeadersInit): R;
|
|
2
|
+
/**
|
|
3
|
+
* `req` with `extra` headers set on top of its own, as an own `headers` property (a standalone
|
|
4
|
+
* `Headers`, which keeps the names a browser drops from Requests: `Cookie`, `Upgrade`, `Sec-*`).
|
|
5
|
+
*/
|
|
6
|
+
export declare function withHeaders<R extends Request>(req: R, extra: HeadersInit): R;
|
|
7
|
+
/**
|
|
8
|
+
* Copies `Upgrade`, `Sec-WebSocket-*` and `Cookie` from `from` onto a rebuilt request (no-op if
|
|
9
|
+
* none): a browser drops them from every `new Request()`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function carryWebSocketHeaders<R extends Request>(from: Headers, to: R): R;
|
|
12
|
+
declare const HostRequest: {
|
|
13
|
+
new (input: RequestInfo | URL, init?: RequestInit): Request;
|
|
14
|
+
prototype: Request;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The `Request` global of Worker code. A browser drops `Upgrade`, `Sec-WebSocket-*` and `Cookie`
|
|
18
|
+
* from every `new Request()`, so a Worker that copies an upgrade request (`new Request(req)`, as
|
|
19
|
+
* partyserver does before it forwards a socket to its Durable Object) or a request with cookies
|
|
20
|
+
* would lose them; this one carries them over, like the rest of the headers. Requests the host
|
|
21
|
+
* makes are instances too.
|
|
22
|
+
*/
|
|
23
|
+
export declare class CellsRequest extends HostRequest {
|
|
24
|
+
constructor(input: RequestInfo | URL, init?: RequestInit);
|
|
25
|
+
clone(): Request;
|
|
26
|
+
static [Symbol.hasInstance](v: unknown): boolean;
|
|
27
|
+
}
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browsers silently drop FORBIDDEN request headers from `new Request(...)`: `Upgrade`,
|
|
3
|
+
* and every `Sec-*` header such as `Sec-WebSocket-Protocol` (Node/undici keeps them).
|
|
4
|
+
* Cloudflare code reads `request.headers.get("Upgrade")` and the offered subprotocols,
|
|
5
|
+
* so the runtime re-attaches them as an own `headers` property backed by a standalone
|
|
6
|
+
* `Headers` object (guard "none" accepts any name).
|
|
7
|
+
*/
|
|
8
|
+
const isWebSocketHeader = (name) => name === "upgrade" || name.startsWith("sec-websocket-");
|
|
9
|
+
export function withUpgrade(req, value = "websocket", extra) {
|
|
10
|
+
const headers = new Headers(req.headers);
|
|
11
|
+
headers.set("Upgrade", value);
|
|
12
|
+
for (const [k, v] of new Headers(extra))
|
|
13
|
+
headers.set(k, v);
|
|
14
|
+
Object.defineProperty(req, "headers", { value: headers, configurable: true, enumerable: true });
|
|
15
|
+
return req;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* `req` with `extra` headers set on top of its own, as an own `headers` property (a standalone
|
|
19
|
+
* `Headers`, which keeps the names a browser drops from Requests: `Cookie`, `Upgrade`, `Sec-*`).
|
|
20
|
+
*/
|
|
21
|
+
export function withHeaders(req, extra) {
|
|
22
|
+
const headers = new Headers(req.headers);
|
|
23
|
+
for (const [k, v] of new Headers(extra))
|
|
24
|
+
headers.set(k, v);
|
|
25
|
+
Object.defineProperty(req, "headers", { value: headers, configurable: true, enumerable: true });
|
|
26
|
+
return req;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Copies `Upgrade`, `Sec-WebSocket-*` and `Cookie` from `from` onto a rebuilt request (no-op if
|
|
30
|
+
* none): a browser drops them from every `new Request()`.
|
|
31
|
+
*/
|
|
32
|
+
export function carryWebSocketHeaders(from, to) {
|
|
33
|
+
const upgrade = from.get("Upgrade");
|
|
34
|
+
const cookie = from.get("Cookie");
|
|
35
|
+
if (cookie !== null && to.headers.get("Cookie") !== cookie)
|
|
36
|
+
withHeaders(to, { cookie });
|
|
37
|
+
if (!upgrade)
|
|
38
|
+
return to;
|
|
39
|
+
const extra = [];
|
|
40
|
+
for (const [k, v] of from)
|
|
41
|
+
if (k !== "upgrade" && isWebSocketHeader(k))
|
|
42
|
+
extra.push([k, v]);
|
|
43
|
+
return withUpgrade(to, upgrade, extra);
|
|
44
|
+
}
|
|
45
|
+
const HostRequest = globalThis.Request;
|
|
46
|
+
/**
|
|
47
|
+
* The `Request` global of Worker code. A browser drops `Upgrade`, `Sec-WebSocket-*` and `Cookie`
|
|
48
|
+
* from every `new Request()`, so a Worker that copies an upgrade request (`new Request(req)`, as
|
|
49
|
+
* partyserver does before it forwards a socket to its Durable Object) or a request with cookies
|
|
50
|
+
* would lose them; this one carries them over, like the rest of the headers. Requests the host
|
|
51
|
+
* makes are instances too.
|
|
52
|
+
*/
|
|
53
|
+
export class CellsRequest extends HostRequest {
|
|
54
|
+
constructor(input, init) {
|
|
55
|
+
super(input, init);
|
|
56
|
+
// `init.headers` replaces the input's headers, as in `Request` itself.
|
|
57
|
+
// Not a fresh `Headers` from a Request's own: a browser's would drop what it carries.
|
|
58
|
+
const from = init?.headers !== undefined
|
|
59
|
+
? init.headers instanceof Headers
|
|
60
|
+
? init.headers
|
|
61
|
+
: new Headers(init.headers)
|
|
62
|
+
: input instanceof HostRequest
|
|
63
|
+
? input.headers
|
|
64
|
+
: undefined;
|
|
65
|
+
if (from)
|
|
66
|
+
carryWebSocketHeaders(from, this);
|
|
67
|
+
}
|
|
68
|
+
clone() {
|
|
69
|
+
return carryWebSocketHeaders(this.headers, super.clone());
|
|
70
|
+
}
|
|
71
|
+
static [Symbol.hasInstance](v) {
|
|
72
|
+
return v instanceof HostRequest;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=upgrade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../src/ws/upgrade.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Browsers silently drop FORBIDDEN request headers from `new Request(...)`: `Upgrade`,\n * and every `Sec-*` header such as `Sec-WebSocket-Protocol` (Node/undici keeps them).\n * Cloudflare code reads `request.headers.get(\"Upgrade\")` and the offered subprotocols,\n * so the runtime re-attaches them as an own `headers` property backed by a standalone\n * `Headers` object (guard \"none\" accepts any name).\n */\nconst isWebSocketHeader = (name: string) => name === \"upgrade\" || name.startsWith(\"sec-websocket-\");\n\nexport function withUpgrade<R extends Request>(\n req: R,\n value = \"websocket\",\n extra?: HeadersInit,\n): R {\n const headers = new Headers(req.headers);\n headers.set(\"Upgrade\", value);\n for (const [k, v] of new Headers(extra)) headers.set(k, v);\n Object.defineProperty(req, \"headers\", { value: headers, configurable: true, enumerable: true });\n return req;\n}\n\n/**\n * `req` with `extra` headers set on top of its own, as an own `headers` property (a standalone\n * `Headers`, which keeps the names a browser drops from Requests: `Cookie`, `Upgrade`, `Sec-*`).\n */\nexport function withHeaders<R extends Request>(req: R, extra: HeadersInit): R {\n const headers = new Headers(req.headers);\n for (const [k, v] of new Headers(extra)) headers.set(k, v);\n Object.defineProperty(req, \"headers\", { value: headers, configurable: true, enumerable: true });\n return req;\n}\n\n/**\n * Copies `Upgrade`, `Sec-WebSocket-*` and `Cookie` from `from` onto a rebuilt request (no-op if\n * none): a browser drops them from every `new Request()`.\n */\nexport function carryWebSocketHeaders<R extends Request>(from: Headers, to: R): R {\n const upgrade = from.get(\"Upgrade\");\n const cookie = from.get(\"Cookie\");\n if (cookie !== null && to.headers.get(\"Cookie\") !== cookie) withHeaders(to, { cookie });\n if (!upgrade) return to;\n const extra: [string, string][] = [];\n for (const [k, v] of from) if (k !== \"upgrade\" && isWebSocketHeader(k)) extra.push([k, v]);\n return withUpgrade(to, upgrade, extra);\n}\n\nconst HostRequest = globalThis.Request;\n\n/**\n * The `Request` global of Worker code. A browser drops `Upgrade`, `Sec-WebSocket-*` and `Cookie`\n * from every `new Request()`, so a Worker that copies an upgrade request (`new Request(req)`, as\n * partyserver does before it forwards a socket to its Durable Object) or a request with cookies\n * would lose them; this one carries them over, like the rest of the headers. Requests the host\n * makes are instances too.\n */\nexport class CellsRequest extends HostRequest {\n constructor(input: RequestInfo | URL, init?: RequestInit) {\n super(input, init);\n // `init.headers` replaces the input's headers, as in `Request` itself.\n // Not a fresh `Headers` from a Request's own: a browser's would drop what it carries.\n const from =\n init?.headers !== undefined\n ? init.headers instanceof Headers\n ? init.headers\n : new Headers(init.headers)\n : input instanceof HostRequest\n ? input.headers\n : undefined;\n if (from) carryWebSocketHeaders(from, this);\n }\n\n override clone(): Request {\n return carryWebSocketHeaders(this.headers, super.clone());\n }\n\n static [Symbol.hasInstance](v: unknown): boolean {\n return v instanceof HostRequest;\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,114 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statewalker/cellb",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "cellb: isomorphic Durable Objects runtime (celld/Cloudflare-compatible surface) for browsers and servers",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/statewalker/cellb.dev.git",
|
|
10
|
+
"directory": "packages/cellb"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/statewalker/cellb.dev/tree/main/packages/cellb#readme",
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=22.13"
|
|
15
|
+
},
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./node": {
|
|
22
|
+
"types": "./dist/node.d.ts",
|
|
23
|
+
"default": "./dist/node.js"
|
|
24
|
+
},
|
|
25
|
+
"./browser": {
|
|
26
|
+
"types": "./dist/browser.d.ts",
|
|
27
|
+
"default": "./dist/browser.js"
|
|
28
|
+
},
|
|
29
|
+
"./host-modules": {
|
|
30
|
+
"types": "./dist/project/host-modules.d.ts",
|
|
31
|
+
"default": "./dist/project/host-modules.js"
|
|
32
|
+
},
|
|
33
|
+
"./isolate-worker": {
|
|
34
|
+
"types": "./dist/isolate/isolate-worker.d.ts",
|
|
35
|
+
"default": "./dist/isolate/isolate-worker.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"vendor",
|
|
41
|
+
"README.md",
|
|
42
|
+
"LICENSE"
|
|
43
|
+
],
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@noble/hashes": "^1.8.0",
|
|
49
|
+
"@sqlite.org/sqlite-wasm": "^3.53.4-build1",
|
|
50
|
+
"@statewalker/webrun-files": "^0.10.0",
|
|
51
|
+
"@statewalker/webrun-files-browser": "^0.10.0",
|
|
52
|
+
"@statewalker/webrun-files-mem": "^0.10.0",
|
|
53
|
+
"@statewalker/webrun-http-browser": "^0.7.0",
|
|
54
|
+
"@statewalker/webrun-http-streams": "^0.3.0",
|
|
55
|
+
"@statewalker/webrun-modules": "^0.3.5",
|
|
56
|
+
"@statewalker/webrun-rpc": "^0.5.0",
|
|
57
|
+
"@statewalker/webrun-site-builder": "^0.2.0",
|
|
58
|
+
"@statewalker/webrun-site-host": "^0.3.0",
|
|
59
|
+
"@statewalker/webrun-streams": "^0.2.0",
|
|
60
|
+
"acorn": "^8.19.0",
|
|
61
|
+
"assert": "^2.1.0",
|
|
62
|
+
"buffer": "^6.0.3",
|
|
63
|
+
"events": "^3.3.0",
|
|
64
|
+
"path-browserify": "^1.0.1",
|
|
65
|
+
"sqlite-vec": "^0.1.7",
|
|
66
|
+
"util": "^0.12.5",
|
|
67
|
+
"worker-timers": "^8.0.0",
|
|
68
|
+
"ws": "^8.22.0"
|
|
69
|
+
},
|
|
70
|
+
"peerDependencies": {
|
|
71
|
+
"esbuild": ">=0.25"
|
|
72
|
+
},
|
|
73
|
+
"peerDependenciesMeta": {
|
|
74
|
+
"esbuild": {
|
|
75
|
+
"optional": true
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"devDependencies": {
|
|
79
|
+
"@playwright/test": "^1.63.0",
|
|
80
|
+
"@sparticuz/chromium": "^153.0.0",
|
|
81
|
+
"@statewalker/webrun-http-browser": "^0.7.0",
|
|
82
|
+
"@types/node": "^26.6.4",
|
|
83
|
+
"@types/ws": "^8.18.2",
|
|
84
|
+
"esbuild": "^0.28.0",
|
|
85
|
+
"html-rewriter-wasm": "^0.4.1",
|
|
86
|
+
"miniflare": "4.20260730.0",
|
|
87
|
+
"sqlite-vec-wasm-demo": "0.1.6",
|
|
88
|
+
"typescript": "^7.0.2",
|
|
89
|
+
"vite": "^8.3.2",
|
|
90
|
+
"vitest": "^5.0.3",
|
|
91
|
+
"zod": "^3.25.0"
|
|
92
|
+
},
|
|
93
|
+
"scripts": {
|
|
94
|
+
"build": "node scripts/build.mjs",
|
|
95
|
+
"test": "vitest run",
|
|
96
|
+
"test:unit": "vitest run test/",
|
|
97
|
+
"test:e2e": "vitest run e2e/",
|
|
98
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p e2e-browser/pages/tsconfig.json",
|
|
99
|
+
"mutate": "node scripts/mutate.mjs",
|
|
100
|
+
"browser:prepare": "mkdir -p e2e-browser/pages/public/vendor && cp node_modules/@statewalker/webrun-http-browser/dist/sw-worker.js e2e-browser/pages/public/vendor/webrun-http-sw-worker.js",
|
|
101
|
+
"browser:dev": "pnpm run browser:prepare && vite e2e-browser/pages --config e2e-browser/pages/vite.config.ts",
|
|
102
|
+
"browser:build": "pnpm run browser:prepare && vite build e2e-browser/pages --config e2e-browser/pages/vite.config.ts",
|
|
103
|
+
"e2e": "playwright test",
|
|
104
|
+
"e2e:firefox": "PW_BROWSERS=firefox playwright test",
|
|
105
|
+
"e2e:webkit": "PW_BROWSERS=webkit playwright test",
|
|
106
|
+
"interop": "scripts/interop-env.sh vitest run e2e/ test/p09-celld-conformance.test.ts",
|
|
107
|
+
"interop:browser": "scripts/interop-env.sh playwright test celld-bucket opfs-bucket",
|
|
108
|
+
"e2e:npm-chromium": "PW_CHROMIUM=\"$(node scripts/npm-chromium.mjs)\" playwright test",
|
|
109
|
+
"mutate:browser": "node scripts/mutate-browser.mjs",
|
|
110
|
+
"mutate:check": "node scripts/mutate.mjs --check && node scripts/mutate-browser.mjs --check",
|
|
111
|
+
"probes:browser": "PW_CHROMIUM=\"${PW_CHROMIUM:-$(node scripts/npm-chromium.mjs)}\" playwright test --config playwright.probes.config.ts --reporter=line",
|
|
112
|
+
"probes:node": "node --no-warnings probes/sqlite-lock.probe.mjs"
|
|
113
|
+
}
|
|
6
114
|
}
|