devflare 1.0.0-next.32 → 1.0.0-next.33
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/bin/devflare.js +1 -3
- package/dist/{account-g99mzrqp.js → account-p9eywryw.js} +27 -16
- package/dist/ai-r3zqmxan.js +261 -0
- package/dist/{api-2n6dd2ws.js → api-6z01z734.js} +1 -1
- package/dist/bridge/client.d.ts.map +1 -1
- package/dist/bridge/miniflare.d.ts.map +1 -1
- package/dist/bridge/proxy.d.ts.map +1 -1
- package/dist/bridge/server.d.ts.map +1 -1
- package/dist/bridge/v2/body-streams.d.ts.map +1 -1
- package/dist/bridge/v2/codec.d.ts.map +1 -1
- package/dist/bridge/v2/frames.d.ts.map +1 -1
- package/dist/bridge/v2/value-codec.d.ts.map +1 -1
- package/dist/bridge/v2/value-serialization.d.ts.map +1 -1
- package/dist/bridge/v2/wire.d.ts.map +1 -1
- package/dist/bridge/v2/ws-relay.d.ts +1 -1
- package/dist/bridge/v2/ws-relay.d.ts.map +1 -1
- package/dist/browser-shim/handler.d.ts +1 -1
- package/dist/browser-shim/handler.d.ts.map +1 -1
- package/dist/browser-shim/server.d.ts.map +1 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +5 -5
- package/dist/{build-4tyjywn9.js → build-8bn7frg8.js} +16 -16
- package/dist/bundler/do-bundler.d.ts.map +1 -1
- package/dist/bundler/rolldown-shared.d.ts.map +1 -1
- package/dist/bundler/worker-bundler.d.ts.map +1 -1
- package/dist/bundler/worker-compat.d.ts.map +1 -1
- package/dist/cli/build-manifest.d.ts.map +1 -1
- package/dist/cli/command-utils.d.ts.map +1 -1
- package/dist/cli/commands/account.d.ts +1 -1
- package/dist/cli/commands/account.d.ts.map +1 -1
- package/dist/cli/commands/ai.d.ts.map +1 -1
- package/dist/cli/commands/build-artifacts.d.ts +3 -3
- package/dist/cli/commands/build-artifacts.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts +2 -2
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/config.d.ts +2 -2
- package/dist/cli/commands/config.d.ts.map +1 -1
- package/dist/cli/commands/deploy.d.ts.map +1 -1
- package/dist/cli/commands/dev.d.ts +1 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/doctor.d.ts +2 -2
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts +2 -2
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/login.d.ts +1 -1
- package/dist/cli/commands/login.d.ts.map +1 -1
- package/dist/cli/commands/previews-support/cleanup.d.ts.map +1 -1
- package/dist/cli/commands/previews-support/family.d.ts.map +1 -1
- package/dist/cli/commands/previews-support/render.d.ts +1 -1
- package/dist/cli/commands/previews-support/render.d.ts.map +1 -1
- package/dist/cli/commands/previews-support/theme.d.ts +1 -1
- package/dist/cli/commands/previews-support/theme.d.ts.map +1 -1
- package/dist/cli/commands/previews-support/types.d.ts +1 -1
- package/dist/cli/commands/previews-support/types.d.ts.map +1 -1
- package/dist/cli/commands/previews.d.ts.map +1 -1
- package/dist/cli/commands/productions.d.ts +1 -1
- package/dist/cli/commands/productions.d.ts.map +1 -1
- package/dist/cli/commands/remote.d.ts +1 -1
- package/dist/cli/commands/remote.d.ts.map +1 -1
- package/dist/cli/commands/secrets.d.ts.map +1 -1
- package/dist/cli/commands/token.d.ts +2 -2
- package/dist/cli/commands/token.d.ts.map +1 -1
- package/dist/cli/commands/type-generation/discovery.d.ts.map +1 -1
- package/dist/cli/commands/type-generation/generator.d.ts.map +1 -1
- package/dist/cli/commands/types.d.ts +2 -2
- package/dist/cli/commands/types.d.ts.map +1 -1
- package/dist/cli/commands/worker.d.ts +2 -2
- package/dist/cli/commands/worker.d.ts.map +1 -1
- package/dist/cli/dependencies.d.ts +1 -1
- package/dist/cli/dependencies.d.ts.map +1 -1
- package/dist/cli/deploy-strategy.d.ts.map +1 -1
- package/dist/cli/deploy-target.d.ts.map +1 -1
- package/dist/cli/generated-artifacts.d.ts.map +1 -1
- package/dist/cli/help-pages/pages/account.d.ts.map +1 -1
- package/dist/cli/help-pages/pages/core.d.ts.map +1 -1
- package/dist/cli/help-pages/pages/misc.d.ts.map +1 -1
- package/dist/cli/help-pages/pages/previews.d.ts.map +1 -1
- package/dist/cli/help-pages/pages/productions.d.ts.map +1 -1
- package/dist/cli/help-pages/render.d.ts +1 -1
- package/dist/cli/help-pages/render.d.ts.map +1 -1
- package/dist/cli/help-pages/shared.d.ts.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/preview-bindings.d.ts.map +1 -1
- package/dist/cli/preview.d.ts.map +1 -1
- package/dist/cli/ui.d.ts.map +1 -1
- package/dist/cli/workspace-build-guard.d.ts.map +1 -1
- package/dist/cloudflare/account-core.d.ts.map +1 -1
- package/dist/cloudflare/account-resources.d.ts.map +1 -1
- package/dist/cloudflare/account-status.d.ts.map +1 -1
- package/dist/cloudflare/account-workers.d.ts.map +1 -1
- package/dist/cloudflare/api.d.ts.map +1 -1
- package/dist/cloudflare/auth.d.ts.map +1 -1
- package/dist/cloudflare/index.d.ts +6 -6
- package/dist/cloudflare/index.d.ts.map +1 -1
- package/dist/cloudflare/index.js +6 -6
- package/dist/cloudflare/kv-namespace.d.ts.map +1 -1
- package/dist/cloudflare/preferences.d.ts.map +1 -1
- package/dist/cloudflare/preview-registry-cache.d.ts.map +1 -1
- package/dist/cloudflare/preview-registry-inference.d.ts +1 -1
- package/dist/cloudflare/preview-registry-inference.d.ts.map +1 -1
- package/dist/cloudflare/preview-registry-shape.d.ts +1 -1
- package/dist/cloudflare/preview-registry-shape.d.ts.map +1 -1
- package/dist/cloudflare/preview-registry-types.d.ts +1 -1
- package/dist/cloudflare/preview-registry-types.d.ts.map +1 -1
- package/dist/cloudflare/preview-registry.d.ts +1 -1
- package/dist/cloudflare/preview-registry.d.ts.map +1 -1
- package/dist/cloudflare/preview-urls.d.ts.map +1 -1
- package/dist/cloudflare/registry-schema.d.ts.map +1 -1
- package/dist/cloudflare/remote-config.d.ts.map +1 -1
- package/dist/cloudflare/tokens.d.ts.map +1 -1
- package/dist/cloudflare/usage.d.ts.map +1 -1
- package/dist/config/binding-resolution-helpers.d.ts.map +1 -1
- package/dist/config/define.d.ts +1 -1
- package/dist/config/define.d.ts.map +1 -1
- package/dist/config/deploy-resources.d.ts +2 -2
- package/dist/config/deploy-resources.d.ts.map +1 -1
- package/dist/config/env-vars.d.ts.map +1 -1
- package/dist/config/framework-providers.d.ts.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/preview-resources.d.ts.map +1 -1
- package/dist/config/preview.d.ts +1 -3
- package/dist/config/preview.d.ts.map +1 -1
- package/dist/config/ref.d.ts +1 -1
- package/dist/config/ref.d.ts.map +1 -1
- package/dist/config/resolve-phased.d.ts.map +1 -1
- package/dist/config/resource-resolution.d.ts +3 -3
- package/dist/config/resource-resolution.d.ts.map +1 -1
- package/dist/config/schema-bindings.d.ts.map +1 -1
- package/dist/config/schema-build.d.ts.map +1 -1
- package/dist/config/schema-env.d.ts.map +1 -1
- package/dist/config/schema-normalization.d.ts +1 -1
- package/dist/config/schema-normalization.d.ts.map +1 -1
- package/dist/config/schema-runtime.d.ts.map +1 -1
- package/dist/config/schema-types-bindings-resources.d.ts +1 -2
- package/dist/config/schema-types-bindings-resources.d.ts.map +1 -1
- package/dist/config/schema-types-bindings.d.ts +1 -1
- package/dist/config/schema-types-bindings.d.ts.map +1 -1
- package/dist/config/schema-types-runtime.d.ts +2 -2
- package/dist/config/schema-types-runtime.d.ts.map +1 -1
- package/dist/config/schema-types.d.ts +1 -1
- package/dist/config/schema-types.d.ts.map +1 -1
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/service-bindings-validation.d.ts.map +1 -1
- package/dist/config-entry.js +2 -2
- package/dist/{config-88sdhx3w.js → config-gphd6wx7.js} +6 -6
- package/dist/decorators/durable-object.d.ts.map +1 -1
- package/dist/decorators/index.js +1 -1
- package/dist/{deploy-8fpav2cw.js → deploy-vpcp41fw.js} +19 -19
- package/dist/{dev-nxevkfdv.js → dev-9scy9gap.js} +251 -255
- package/dist/dev-server/d1-migrations.d.ts.map +1 -1
- package/dist/dev-server/dev-server-state.d.ts +2 -2
- package/dist/dev-server/dev-server-state.d.ts.map +1 -1
- package/dist/dev-server/gateway-script.d.ts.map +1 -1
- package/dist/dev-server/miniflare-bindings.d.ts.map +1 -1
- package/dist/dev-server/miniflare-dev-config.d.ts +2 -2
- package/dist/dev-server/miniflare-dev-config.d.ts.map +1 -1
- package/dist/dev-server/miniflare-log.d.ts.map +1 -1
- package/dist/dev-server/miniflare-worker-config.d.ts +1 -1
- package/dist/dev-server/miniflare-worker-config.d.ts.map +1 -1
- package/dist/dev-server/server-startup-helpers.d.ts +2 -2
- package/dist/dev-server/server-startup-helpers.d.ts.map +1 -1
- package/dist/dev-server/server.d.ts.map +1 -1
- package/dist/dev-server/vite-process.d.ts.map +1 -1
- package/dist/dev-server/vite-utils.d.ts.map +1 -1
- package/dist/dev-server/worker-source-watcher.d.ts.map +1 -1
- package/dist/dev-server/worker-surface-paths.d.ts +1 -1
- package/dist/dev-server/worker-surface-paths.d.ts.map +1 -1
- package/dist/{doctor-ztwx1y95.js → doctor-swfeeqny.js} +12 -12
- package/dist/{durable-object-v3gsnybk.js → durable-object-pf6gabpn.js} +1 -1
- package/dist/env.d.ts.map +1 -1
- package/dist/{index-mg8vwqxf.js → index-04wh9bxx.js} +2 -2
- package/dist/{index-fcmj6641.js → index-13sfensw.js} +1 -1
- package/dist/{index-6sj0v0dk.js → index-1trss579.js} +1373 -1358
- package/dist/{index-3jme4hgw.js → index-2xz4etye.js} +25 -33
- package/dist/{index-q8f4kawk.js → index-34dejneh.js} +12 -2
- package/dist/{index-rzp9ejrh.js → index-3t0e51a0.js} +1 -1
- package/dist/{index-ptwem1nt.js → index-3z20d3kd.js} +160 -208
- package/dist/{index-d8bdkx2h.js → index-4xmtkg9g.js} +2 -2
- package/dist/{index-qwgr4q7s.js → index-5dkjffqz.js} +2 -14
- package/dist/{index-aqrwyy57.js → index-7m557715.js} +2 -7
- package/dist/{index-85yjb686.js → index-97rfy7n2.js} +1 -1
- package/dist/{index-11p28kxx.js → index-atwc3csp.js} +1 -1
- package/dist/{index-ft3trvra.js → index-b20xx2vk.js} +5 -19
- package/dist/{index-s3km3y34.js → index-bhxj7ff6.js} +234 -219
- package/dist/{index-3edvz3hs.js → index-by27mzra.js} +4 -4
- package/dist/{index-t9y0sve5.js → index-c4zd39tc.js} +1 -1
- package/dist/{index-69c0ed4a.js → index-dem45895.js} +6 -11
- package/dist/{index-k9x5v335.js → index-dgx495pv.js} +30 -27
- package/dist/{index-7qd7nmdd.js → index-e7xn30bh.js} +2 -2
- package/dist/{index-1d4jg11n.js → index-h7r11y4a.js} +5 -8
- package/dist/{index-vez803pp.js → index-ksqth51q.js} +2 -2
- package/dist/{index-stgn34cr.js → index-maw0jjnn.js} +0 -1
- package/dist/{index-hpwa6vsw.js → index-n4xkaymm.js} +1 -4
- package/dist/{index-dfcp9hsd.js → index-pd97hk2j.js} +64 -72
- package/dist/{index-67gr49zr.js → index-pmnb7eke.js} +3 -3
- package/dist/{index-xz18tstn.js → index-t0r7evpw.js} +9 -9
- package/dist/{index-qz6nbwpw.js → index-t23wq5js.js} +1 -1
- package/dist/{index-hjjfxv02.js → index-w8c8tjc5.js} +1 -1
- package/dist/{index-c8p4njqy.js → index-wxdcrzcp.js} +1 -5
- package/dist/{index-15fpa5tx.js → index-x0wpeb3x.js} +2 -2
- package/dist/{index-qmmqww7h.js → index-x2fd1361.js} +5 -5
- package/dist/{index-a855bdsx.js → index-y7w3x9p1.js} +1 -1
- package/dist/{index-gn5wy09x.js → index-zdd0d9qa.js} +3 -9
- package/dist/index.js +12 -12
- package/dist/{init-cwpergap.js → init-tb8jqgvr.js} +2 -2
- package/dist/{login-r5ve73kf.js → login-7vyzeqy4.js} +10 -10
- package/dist/{previews-qjj98rpp.js → previews-jfbectpc.js} +25 -22
- package/dist/{productions-gzdtge0e.js → productions-49ct4kjm.js} +21 -18
- package/dist/{remote-q59qk463.js → remote-6876k6mz.js} +3 -3
- package/dist/runtime/context-events.d.ts.map +1 -1
- package/dist/runtime/context-types.d.ts.map +1 -1
- package/dist/runtime/context.d.ts.map +1 -1
- package/dist/runtime/exports.d.ts +21 -21
- package/dist/runtime/exports.d.ts.map +1 -1
- package/dist/runtime/index.js +5 -5
- package/dist/runtime/middleware.d.ts.map +1 -1
- package/dist/runtime/router/index.d.ts +1 -1
- package/dist/runtime/router/index.d.ts.map +1 -1
- package/dist/runtime/router/types.d.ts.map +1 -1
- package/dist/secrets/local-secrets.d.ts.map +1 -1
- package/dist/{secrets-4w5166km.js → secrets-9ne7armr.js} +7 -7
- package/dist/shims/local-hyperdrive.d.ts.map +1 -1
- package/dist/shims/local-media-bindings.d.ts.map +1 -1
- package/dist/shims/local-worker-loader.d.ts.map +1 -1
- package/dist/sveltekit/index.d.ts.map +1 -1
- package/dist/sveltekit/index.js +12 -15
- package/dist/sveltekit/local-bindings.d.ts.map +1 -1
- package/dist/sveltekit/platform.d.ts.map +1 -1
- package/dist/test/binding-hints.d.ts +1 -1
- package/dist/test/binding-hints.d.ts.map +1 -1
- package/dist/test/cf.d.ts +1 -1
- package/dist/test/containers.d.ts.map +1 -1
- package/dist/test/email.d.ts +4 -4
- package/dist/test/email.d.ts.map +1 -1
- package/dist/test/index.js +1404 -1402
- package/dist/test/offline-bindings.d.ts.map +1 -1
- package/dist/test/queue.d.ts.map +1 -1
- package/dist/test/remote-ai.d.ts.map +1 -1
- package/dist/test/remote-cloudflare.d.ts.map +1 -1
- package/dist/test/remote-vectorize.d.ts.map +1 -1
- package/dist/test/resolve-service-bindings.d.ts.map +1 -1
- package/dist/test/scheduled.d.ts.map +1 -1
- package/dist/test/simple-context-bindings.d.ts.map +1 -1
- package/dist/test/simple-context-durable-objects.d.ts.map +1 -1
- package/dist/test/simple-context-env.d.ts.map +1 -1
- package/dist/test/simple-context-handlers.d.ts.map +1 -1
- package/dist/test/simple-context-lifecycle.d.ts +1 -1
- package/dist/test/simple-context-lifecycle.d.ts.map +1 -1
- package/dist/test/simple-context-mfconfig.d.ts.map +1 -1
- package/dist/test/simple-context-multi-worker.d.ts +1 -1
- package/dist/test/simple-context-multi-worker.d.ts.map +1 -1
- package/dist/test/simple-context-paths.d.ts.map +1 -1
- package/dist/test/simple-context-runtime.d.ts.map +1 -1
- package/dist/test/simple-context-startup.d.ts.map +1 -1
- package/dist/test/simple-context.d.ts.map +1 -1
- package/dist/test/tail.d.ts +1 -1
- package/dist/test/tail.d.ts.map +1 -1
- package/dist/test/utilities/env.d.ts.map +1 -1
- package/dist/test/worker.d.ts.map +1 -1
- package/dist/{token-35jcdqq8.js → token-yp1qa70y.js} +4 -4
- package/dist/transform/durable-object.d.ts.map +1 -1
- package/dist/transform/worker-entrypoint.d.ts.map +1 -1
- package/dist/{types-6vc02evc.js → types-zekmbebk.js} +16 -18
- package/dist/utils/glob.d.ts.map +1 -1
- package/dist/utils/resolve-package.d.ts.map +1 -1
- package/dist/utils/send-email.d.ts.map +1 -1
- package/dist/utils/send-email.js +1 -1
- package/dist/vite/config-file.d.ts +1 -1
- package/dist/vite/config-file.d.ts.map +1 -1
- package/dist/vite/index.js +12 -12
- package/dist/vite/plugin-config-hook.d.ts.map +1 -1
- package/dist/vite/plugin-context.d.ts.map +1 -1
- package/dist/vite/plugin-durable-objects.d.ts +1 -1
- package/dist/vite/plugin-durable-objects.d.ts.map +1 -1
- package/dist/vite/plugin-programmatic.d.ts.map +1 -1
- package/dist/vite/plugin-service-bindings.d.ts.map +1 -1
- package/dist/vite/plugin-transform.d.ts.map +1 -1
- package/dist/vite/plugin.d.ts.map +1 -1
- package/dist/{worker-f2v85f7d.js → worker-706g8qeh.js} +14 -14
- package/dist/worker-entry/composed-worker.d.ts.map +1 -1
- package/dist/worker-entry/extensions.d.ts.map +1 -1
- package/dist/worker-entry/routes.d.ts.map +1 -1
- package/dist/worker-entry/surface-paths.d.ts.map +1 -1
- package/dist/{worker-entrypoint-3rmzd4c1.js → worker-entrypoint-y8s9kdcx.js} +1 -1
- package/dist/workflows/local-workflow-entrypoints.d.ts.map +1 -1
- package/package.json +2 -1
- package/dist/ai-dx4fr9jh.js +0 -107
- package/dist/{index-vhqww6tt.js → index-p93cngdp.js} +1 -1
|
@@ -1,1228 +1,839 @@
|
|
|
1
1
|
import {
|
|
2
2
|
wrapEnvSendEmailBindings
|
|
3
|
-
} from "./index-
|
|
3
|
+
} from "./index-n4xkaymm.js";
|
|
4
4
|
|
|
5
|
-
// src/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
` + `1. Accessing context at module top-level (runs at cold start, not per-request)
|
|
28
|
-
` + `2. Accessing context in setTimeout/setInterval callbacks
|
|
29
|
-
` + `3. Missing 'nodejs_compat' compatibility flag in your worker config
|
|
30
|
-
|
|
31
|
-
` + `Fix: Move the access inside your handler, middleware, or a helper called from that handler trail.
|
|
32
|
-
` + `Learn more: https://devflare.dev/docs/context-errors`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
function createContextProxy(getter, name, options = {}) {
|
|
36
|
-
const mutable = options.mutable ?? true;
|
|
37
|
-
return new Proxy({}, {
|
|
38
|
-
get(_target, prop) {
|
|
39
|
-
const ctx = getter();
|
|
40
|
-
if (ctx === undefined || ctx === null) {
|
|
41
|
-
throw new ContextAccessError(name, String(prop));
|
|
42
|
-
}
|
|
43
|
-
return ctx[prop];
|
|
44
|
-
},
|
|
45
|
-
set(_target, prop, value) {
|
|
46
|
-
if (!mutable) {
|
|
47
|
-
throw new TypeError(`Cannot assign to '${String(prop)}' on '${name}' because it is read-only.
|
|
48
|
-
` + `Use 'locals' for mutable request-scoped data.`);
|
|
49
|
-
}
|
|
50
|
-
const ctx = getter();
|
|
51
|
-
if (ctx === undefined || ctx === null) {
|
|
52
|
-
throw new ContextAccessError(name, String(prop));
|
|
53
|
-
}
|
|
54
|
-
ctx[prop] = value;
|
|
55
|
-
return true;
|
|
56
|
-
},
|
|
57
|
-
deleteProperty(_target, prop) {
|
|
58
|
-
if (!mutable) {
|
|
59
|
-
throw new TypeError(`Cannot delete property '${String(prop)}' from '${name}' because it is read-only.`);
|
|
60
|
-
}
|
|
61
|
-
const ctx = getter();
|
|
62
|
-
if (ctx === undefined || ctx === null) {
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
return Reflect.deleteProperty(ctx, prop);
|
|
66
|
-
},
|
|
67
|
-
has(_target, prop) {
|
|
68
|
-
const ctx = getter();
|
|
69
|
-
if (ctx === undefined || ctx === null) {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
return prop in ctx;
|
|
73
|
-
},
|
|
74
|
-
ownKeys(_target) {
|
|
75
|
-
const ctx = getter();
|
|
76
|
-
if (ctx === undefined || ctx === null) {
|
|
77
|
-
return [];
|
|
78
|
-
}
|
|
79
|
-
return Reflect.ownKeys(ctx);
|
|
80
|
-
},
|
|
81
|
-
getOwnPropertyDescriptor(_target, prop) {
|
|
82
|
-
const ctx = getter();
|
|
83
|
-
if (ctx === undefined || ctx === null) {
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
const descriptor = Reflect.getOwnPropertyDescriptor(ctx, prop);
|
|
87
|
-
if (!descriptor) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
if (!mutable) {
|
|
91
|
-
return { ...descriptor, writable: false };
|
|
92
|
-
}
|
|
93
|
-
return descriptor;
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// src/runtime/context-events.ts
|
|
99
|
-
function createLocals(locals) {
|
|
100
|
-
return locals ?? {};
|
|
101
|
-
}
|
|
102
|
-
function prepareEventShell(env, options = {}) {
|
|
103
|
-
return {
|
|
104
|
-
env: wrapEnvSendEmailBindings(env),
|
|
105
|
-
locals: createLocals(options.locals)
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
function createAugmentedTarget(target, extra) {
|
|
109
|
-
return new Proxy(target, {
|
|
110
|
-
get(target2, prop) {
|
|
111
|
-
if (prop in extra) {
|
|
112
|
-
return extra[prop];
|
|
113
|
-
}
|
|
114
|
-
const value = Reflect.get(target2, prop, target2);
|
|
115
|
-
return typeof value === "function" ? value.bind(target2) : value;
|
|
116
|
-
},
|
|
117
|
-
has(target2, prop) {
|
|
118
|
-
return prop in extra || prop in target2;
|
|
119
|
-
},
|
|
120
|
-
ownKeys(target2) {
|
|
121
|
-
return Array.from(new Set([
|
|
122
|
-
...Reflect.ownKeys(target2),
|
|
123
|
-
...Reflect.ownKeys(extra)
|
|
124
|
-
]));
|
|
125
|
-
},
|
|
126
|
-
getOwnPropertyDescriptor(target2, prop) {
|
|
127
|
-
if (prop in extra) {
|
|
128
|
-
return {
|
|
129
|
-
configurable: true,
|
|
130
|
-
enumerable: true,
|
|
131
|
-
writable: false,
|
|
132
|
-
value: extra[prop]
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
return Reflect.getOwnPropertyDescriptor(target2, prop);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
function createBaseEvent(type, env, ctx, options = {}) {
|
|
140
|
-
const shell = prepareEventShell(env, { locals: options.locals });
|
|
141
|
-
return {
|
|
142
|
-
type,
|
|
143
|
-
ctx,
|
|
144
|
-
...shell,
|
|
145
|
-
request: options.request ?? null,
|
|
146
|
-
params: options.params
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
function createFetchEvent(request, env, ctx, options = {}) {
|
|
150
|
-
const shell = prepareEventShell(env, { locals: options.locals });
|
|
151
|
-
return createAugmentedTarget(request, {
|
|
152
|
-
type: "fetch",
|
|
153
|
-
ctx,
|
|
154
|
-
...shell,
|
|
155
|
-
url: new URL(request.url),
|
|
156
|
-
request,
|
|
157
|
-
params: options.params ?? {}
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
function createQueueEvent(batch, env, ctx, options = {}) {
|
|
161
|
-
const shell = prepareEventShell(env, { locals: options.locals });
|
|
162
|
-
return createAugmentedTarget(batch, {
|
|
163
|
-
type: "queue",
|
|
164
|
-
ctx,
|
|
165
|
-
...shell,
|
|
166
|
-
batch
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
function createScheduledEvent(controller, env, ctx, options = {}) {
|
|
170
|
-
const shell = prepareEventShell(env, { locals: options.locals });
|
|
171
|
-
return createAugmentedTarget(controller, {
|
|
172
|
-
type: "scheduled",
|
|
173
|
-
ctx,
|
|
174
|
-
...shell,
|
|
175
|
-
controller
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
function createEmailEvent(message, env, ctx, options = {}) {
|
|
179
|
-
const shell = prepareEventShell(env, { locals: options.locals });
|
|
180
|
-
return createAugmentedTarget(message, {
|
|
181
|
-
type: "email",
|
|
182
|
-
ctx,
|
|
183
|
-
...shell,
|
|
184
|
-
message
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
function createTailEvent(events, env, ctx, options = {}) {
|
|
188
|
-
const shell = prepareEventShell(env, { locals: options.locals });
|
|
189
|
-
return createAugmentedTarget(events, {
|
|
190
|
-
type: "tail",
|
|
191
|
-
ctx,
|
|
192
|
-
...shell,
|
|
193
|
-
events
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
function createDurableObjectFetchEvent(request, env, state, options = {}) {
|
|
197
|
-
const shell = prepareEventShell(env, { locals: options.locals });
|
|
198
|
-
return createAugmentedTarget(request, {
|
|
199
|
-
type: "durable-object-fetch",
|
|
200
|
-
ctx: state,
|
|
201
|
-
state,
|
|
202
|
-
...shell,
|
|
203
|
-
request
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
function createDurableObjectAlarmEvent(env, state, options = {}) {
|
|
207
|
-
const shell = prepareEventShell(env, { locals: options.locals });
|
|
208
|
-
return {
|
|
209
|
-
type: "durable-object-alarm",
|
|
210
|
-
ctx: state,
|
|
211
|
-
state,
|
|
212
|
-
...shell
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
function createDurableObjectWebSocketMessageEvent(ws, message, env, state, options = {}) {
|
|
216
|
-
const shell = prepareEventShell(env, { locals: options.locals });
|
|
217
|
-
return createAugmentedTarget(ws, {
|
|
218
|
-
type: "durable-object-websocket-message",
|
|
219
|
-
ctx: state,
|
|
220
|
-
state,
|
|
221
|
-
...shell,
|
|
222
|
-
ws,
|
|
223
|
-
message
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
function createDurableObjectWebSocketCloseEvent(ws, code, reason, wasClean, env, state, options = {}) {
|
|
227
|
-
const shell = prepareEventShell(env, { locals: options.locals });
|
|
228
|
-
return createAugmentedTarget(ws, {
|
|
229
|
-
type: "durable-object-websocket-close",
|
|
230
|
-
ctx: state,
|
|
231
|
-
state,
|
|
232
|
-
...shell,
|
|
233
|
-
ws,
|
|
234
|
-
code,
|
|
235
|
-
reason,
|
|
236
|
-
wasClean
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
function createDurableObjectWebSocketErrorEvent(ws, error, env, state, options = {}) {
|
|
240
|
-
const shell = prepareEventShell(env, { locals: options.locals });
|
|
241
|
-
return createAugmentedTarget(ws, {
|
|
242
|
-
type: "durable-object-websocket-error",
|
|
243
|
-
ctx: state,
|
|
244
|
-
state,
|
|
245
|
-
...shell,
|
|
246
|
-
ws,
|
|
247
|
-
error
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
function createDefaultEvent(env, ctx, request, type, locals) {
|
|
251
|
-
switch (type) {
|
|
252
|
-
case "fetch": {
|
|
253
|
-
if (request && ctx) {
|
|
254
|
-
return createFetchEvent(request, env, ctx, { locals });
|
|
255
|
-
}
|
|
256
|
-
return createBaseEvent(type, env, ctx, { locals, request });
|
|
257
|
-
}
|
|
258
|
-
case "durable-object-fetch": {
|
|
259
|
-
if (request && ctx) {
|
|
260
|
-
return createDurableObjectFetchEvent(request, env, ctx, { locals });
|
|
261
|
-
}
|
|
262
|
-
return createBaseEvent(type, env, ctx, { locals, request });
|
|
263
|
-
}
|
|
264
|
-
case "durable-object-alarm": {
|
|
265
|
-
if (ctx) {
|
|
266
|
-
return createDurableObjectAlarmEvent(env, ctx, { locals });
|
|
267
|
-
}
|
|
268
|
-
return createBaseEvent(type, env, ctx, { locals });
|
|
269
|
-
}
|
|
270
|
-
case "queue":
|
|
271
|
-
case "scheduled":
|
|
272
|
-
case "email":
|
|
273
|
-
case "tail":
|
|
274
|
-
case "durable-object-websocket-message":
|
|
275
|
-
case "durable-object-websocket-close":
|
|
276
|
-
case "durable-object-websocket-error":
|
|
277
|
-
return createBaseEvent(type, env, ctx, { locals, request });
|
|
278
|
-
default: {
|
|
279
|
-
const exhaustive = type;
|
|
280
|
-
throw new Error(`createDefaultEvent: unknown event type ${String(exhaustive)}`);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// src/runtime/context.ts
|
|
286
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
287
|
-
var storage = new AsyncLocalStorage;
|
|
288
|
-
function createLocals2() {
|
|
289
|
-
return {};
|
|
290
|
-
}
|
|
291
|
-
function runWithContext(env, ctx, request, fn, type = "fetch") {
|
|
292
|
-
const locals = createLocals2();
|
|
293
|
-
const event = createDefaultEvent(env, ctx, request, type, locals);
|
|
294
|
-
return runWithEventContext(event, fn);
|
|
295
|
-
}
|
|
296
|
-
function runWithEventContext(event, fn) {
|
|
297
|
-
const context = {
|
|
298
|
-
env: event.env,
|
|
299
|
-
ctx: event.ctx,
|
|
300
|
-
request: event.request ?? null,
|
|
301
|
-
locals: event.locals,
|
|
302
|
-
type: event.type,
|
|
303
|
-
event
|
|
304
|
-
};
|
|
305
|
-
return storage.run(context, fn);
|
|
306
|
-
}
|
|
307
|
-
function getContext() {
|
|
308
|
-
const context = storage.getStore();
|
|
309
|
-
if (!context) {
|
|
310
|
-
throw ContextAccessError.contextUnavailable();
|
|
311
|
-
}
|
|
312
|
-
return context;
|
|
313
|
-
}
|
|
314
|
-
function getContextOrNull() {
|
|
315
|
-
const context = storage.getStore();
|
|
316
|
-
return context ?? null;
|
|
317
|
-
}
|
|
318
|
-
function getEventContext() {
|
|
319
|
-
return getContext().event;
|
|
320
|
-
}
|
|
321
|
-
function getEventContextOrNull() {
|
|
322
|
-
return getContextOrNull()?.event ?? null;
|
|
323
|
-
}
|
|
324
|
-
function hasContext() {
|
|
325
|
-
return storage.getStore() !== undefined;
|
|
326
|
-
}
|
|
327
|
-
function createEventAccessor(name, matcher) {
|
|
328
|
-
const accessor = () => {
|
|
329
|
-
const currentEvent = getEventContextOrNull();
|
|
330
|
-
if (!currentEvent) {
|
|
331
|
-
throw ContextAccessError.contextUnavailable();
|
|
332
|
-
}
|
|
333
|
-
if (!matcher(currentEvent)) {
|
|
334
|
-
throw ContextAccessError.contextUnavailable(`${name} is not available in the current '${currentEvent.type}' context.
|
|
335
|
-
|
|
336
|
-
Devflare stores event objects in AsyncLocalStorage so helpers called within a handler can reach the active event.
|
|
337
|
-
Use ${name}.safe() to return null instead of throwing, or call the getter that matches the active surface.`);
|
|
338
|
-
}
|
|
339
|
-
return currentEvent;
|
|
340
|
-
};
|
|
341
|
-
accessor.safe = () => {
|
|
342
|
-
const currentEvent = getEventContextOrNull();
|
|
343
|
-
return currentEvent && matcher(currentEvent) ? currentEvent : null;
|
|
344
|
-
};
|
|
345
|
-
return accessor;
|
|
346
|
-
}
|
|
347
|
-
function isFetchEvent(event) {
|
|
348
|
-
return event.type === "fetch" && event.request instanceof Request;
|
|
349
|
-
}
|
|
350
|
-
function isQueueEvent(event) {
|
|
351
|
-
return event.type === "queue" && "batch" in event;
|
|
352
|
-
}
|
|
353
|
-
function isScheduledEvent(event) {
|
|
354
|
-
return event.type === "scheduled" && "controller" in event;
|
|
355
|
-
}
|
|
356
|
-
function isEmailEvent(event) {
|
|
357
|
-
return event.type === "email" && "message" in event;
|
|
358
|
-
}
|
|
359
|
-
function isTailEvent(event) {
|
|
360
|
-
return event.type === "tail" && Array.isArray(event) && "events" in event;
|
|
361
|
-
}
|
|
362
|
-
function isDurableObjectEvent(event) {
|
|
363
|
-
return event.type.startsWith("durable-object-") && "state" in event;
|
|
364
|
-
}
|
|
365
|
-
function isDurableObjectFetchEvent(event) {
|
|
366
|
-
return event.type === "durable-object-fetch" && event.request instanceof Request;
|
|
367
|
-
}
|
|
368
|
-
function isDurableObjectAlarmEvent(event) {
|
|
369
|
-
return event.type === "durable-object-alarm" && "state" in event;
|
|
370
|
-
}
|
|
371
|
-
function isDurableObjectWebSocketMessageEvent(event) {
|
|
372
|
-
return event.type === "durable-object-websocket-message" && "ws" in event && "message" in event;
|
|
373
|
-
}
|
|
374
|
-
function isDurableObjectWebSocketCloseEvent(event) {
|
|
375
|
-
return event.type === "durable-object-websocket-close" && "ws" in event && "code" in event;
|
|
376
|
-
}
|
|
377
|
-
function isDurableObjectWebSocketErrorEvent(event) {
|
|
378
|
-
return event.type === "durable-object-websocket-error" && "ws" in event && "error" in event;
|
|
379
|
-
}
|
|
380
|
-
var getFetchEvent = createEventAccessor("getFetchEvent()", isFetchEvent);
|
|
381
|
-
var getQueueEvent = createEventAccessor("getQueueEvent()", isQueueEvent);
|
|
382
|
-
var getScheduledEvent = createEventAccessor("getScheduledEvent()", isScheduledEvent);
|
|
383
|
-
var getEmailEvent = createEventAccessor("getEmailEvent()", isEmailEvent);
|
|
384
|
-
var getTailEvent = createEventAccessor("getTailEvent()", isTailEvent);
|
|
385
|
-
var getDurableObjectEvent = createEventAccessor("getDurableObjectEvent()", isDurableObjectEvent);
|
|
386
|
-
var getDurableObjectFetchEvent = createEventAccessor("getDurableObjectFetchEvent()", isDurableObjectFetchEvent);
|
|
387
|
-
var getDurableObjectAlarmEvent = createEventAccessor("getDurableObjectAlarmEvent()", isDurableObjectAlarmEvent);
|
|
388
|
-
var getDurableObjectWebSocketMessageEvent = createEventAccessor("getDurableObjectWebSocketMessageEvent()", isDurableObjectWebSocketMessageEvent);
|
|
389
|
-
var getDurableObjectWebSocketCloseEvent = createEventAccessor("getDurableObjectWebSocketCloseEvent()", isDurableObjectWebSocketCloseEvent);
|
|
390
|
-
var getDurableObjectWebSocketErrorEvent = createEventAccessor("getDurableObjectWebSocketErrorEvent()", isDurableObjectWebSocketErrorEvent);
|
|
5
|
+
// src/bridge/log.ts
|
|
6
|
+
var isDebugEnabled = () => {
|
|
7
|
+
try {
|
|
8
|
+
const env = globalThis.process?.env;
|
|
9
|
+
return Boolean(env?.DEVFLARE_DEBUG_BRIDGE);
|
|
10
|
+
} catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var bridgeLog = {
|
|
15
|
+
warn(message, error) {
|
|
16
|
+
if (!isDebugEnabled())
|
|
17
|
+
return;
|
|
18
|
+
console.warn(`[devflare:bridge] ${message}`, error);
|
|
19
|
+
},
|
|
20
|
+
debug(message, error) {
|
|
21
|
+
if (!isDebugEnabled())
|
|
22
|
+
return;
|
|
23
|
+
console.debug(`[devflare:bridge] ${message}`, error);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
391
26
|
|
|
392
|
-
// src/bridge/v2/
|
|
393
|
-
var
|
|
27
|
+
// src/bridge/v2/frames.ts
|
|
28
|
+
var TRANSPORT_V2_PROTOCOL_VERSION = 2;
|
|
29
|
+
var TRANSPORT_V2_UNSUPPORTED_VERSION_CLOSE_CODE = 4001;
|
|
30
|
+
var TransportV2BinaryKind = {
|
|
394
31
|
StreamChunk: 1,
|
|
395
|
-
WsData: 2
|
|
32
|
+
WsData: 2,
|
|
33
|
+
BodyChunk: 3
|
|
396
34
|
};
|
|
397
|
-
var
|
|
35
|
+
var TransportV2BinaryFlags = {
|
|
398
36
|
FIN: 1,
|
|
399
|
-
TEXT: 2
|
|
37
|
+
TEXT: 2,
|
|
38
|
+
ABORT: 4
|
|
400
39
|
};
|
|
401
|
-
var
|
|
402
|
-
function
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
view.
|
|
407
|
-
view.
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
40
|
+
var TRANSPORT_V2_BINARY_HEADER_SIZE = 10;
|
|
41
|
+
function decodeTransportV2BinaryFrame(frame) {
|
|
42
|
+
if (frame.byteLength < TRANSPORT_V2_BINARY_HEADER_SIZE) {
|
|
43
|
+
throw new Error(`Invalid transport v2 binary frame: too short (${frame.byteLength} bytes, need at least ${TRANSPORT_V2_BINARY_HEADER_SIZE})`);
|
|
44
|
+
}
|
|
45
|
+
const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
|
|
46
|
+
const kind = view.getUint8(0);
|
|
47
|
+
if (kind !== TransportV2BinaryKind.StreamChunk && kind !== TransportV2BinaryKind.WsData && kind !== TransportV2BinaryKind.BodyChunk) {
|
|
48
|
+
throw new Error(`Invalid transport v2 binary frame: unknown kind ${kind}`);
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
kind,
|
|
52
|
+
id: view.getUint32(1, true),
|
|
53
|
+
seq: view.getUint32(5, true),
|
|
54
|
+
flags: view.getUint8(9),
|
|
55
|
+
payload: frame.subarray(TRANSPORT_V2_BINARY_HEADER_SIZE)
|
|
56
|
+
};
|
|
411
57
|
}
|
|
412
|
-
function
|
|
58
|
+
function transportV2IsFin(flags) {
|
|
59
|
+
return (flags & TransportV2BinaryFlags.FIN) !== 0;
|
|
60
|
+
}
|
|
61
|
+
function transportV2IsAbort(flags) {
|
|
62
|
+
return (flags & TransportV2BinaryFlags.ABORT) !== 0;
|
|
63
|
+
}
|
|
64
|
+
var KNOWN_V2_CONTROL_TYPES = new Set(["hello", "welcome", "body.open", "body.end", "body.abort"]);
|
|
65
|
+
function parseTransportV2ControlMsg(data) {
|
|
413
66
|
const msg = JSON.parse(data);
|
|
414
67
|
if (typeof msg !== "object" || msg === null || !("t" in msg)) {
|
|
415
|
-
throw new Error("Invalid message: missing type field");
|
|
68
|
+
throw new Error("Invalid transport v2 control message: missing type field");
|
|
69
|
+
}
|
|
70
|
+
if (!KNOWN_V2_CONTROL_TYPES.has(msg.t)) {
|
|
71
|
+
throw new Error(`Invalid transport v2 control message: unknown type "${msg.t}"`);
|
|
72
|
+
}
|
|
73
|
+
if (msg.t === "hello" || msg.t === "welcome") {
|
|
74
|
+
if (msg.protocolVersion !== TRANSPORT_V2_PROTOCOL_VERSION) {
|
|
75
|
+
throw new Error(`Invalid transport v2 ${msg.t}: protocolVersion ${msg.protocolVersion} != ${TRANSPORT_V2_PROTOCOL_VERSION}`);
|
|
76
|
+
}
|
|
77
|
+
if (!Array.isArray(msg.capabilities)) {
|
|
78
|
+
throw new Error(`Invalid transport v2 ${msg.t}: capabilities must be an array`);
|
|
79
|
+
}
|
|
416
80
|
}
|
|
417
81
|
return msg;
|
|
418
82
|
}
|
|
419
|
-
function
|
|
83
|
+
function stringifyTransportV2ControlMsg(msg) {
|
|
420
84
|
return JSON.stringify(msg);
|
|
421
85
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
return
|
|
426
|
-
}
|
|
427
|
-
function nextWsId() {
|
|
428
|
-
return ++wsIdCounter;
|
|
86
|
+
function negotiateTransportV2Capabilities(supported, advertised) {
|
|
87
|
+
const supportedSet = new Set(supported);
|
|
88
|
+
const intersection = advertised.filter((cap) => supportedSet.has(cap));
|
|
89
|
+
return [...new Set(intersection)].sort();
|
|
429
90
|
}
|
|
430
|
-
var DEFAULT_CHUNK_SIZE = 256 * 1024;
|
|
431
|
-
var HTTP_TRANSFER_THRESHOLD = 512 * 1024;
|
|
432
|
-
var DEFAULT_BRIDGE_PORT = 8686;
|
|
433
91
|
|
|
434
|
-
// src/bridge/v2/
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
if (request.body) {
|
|
444
|
-
const bytes = await request.arrayBuffer();
|
|
445
|
-
if (bytes.byteLength > threshold) {
|
|
446
|
-
throw new Error("Request body exceeds the bridge inline limit (~512 KB) and large request-body streaming is not yet supported over the local bridge. " + "Send the payload in smaller chunks or via an R2 binding for now.");
|
|
447
|
-
} else if (bytes.byteLength > 0) {
|
|
448
|
-
body = { type: "bytes", data: base64Encode(new Uint8Array(bytes)) };
|
|
449
|
-
}
|
|
92
|
+
// src/bridge/v2/body-streams.ts
|
|
93
|
+
var TRANSPORT_V2_DEFAULT_BODY_CHUNK_SIZE = 256 * 1024;
|
|
94
|
+
class TransportV2BodyReaderRegistry {
|
|
95
|
+
#streams = new Map;
|
|
96
|
+
getOrOpen(bid) {
|
|
97
|
+
const existing = this.#streams.get(bid);
|
|
98
|
+
if (existing !== undefined)
|
|
99
|
+
return existing.stream;
|
|
100
|
+
return this.open(bid);
|
|
450
101
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
method: request.method,
|
|
455
|
-
headers,
|
|
456
|
-
body,
|
|
457
|
-
redirect: request.redirect
|
|
458
|
-
},
|
|
459
|
-
streams
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
function deserializeRequest(serialized, getStream) {
|
|
463
|
-
let body = null;
|
|
464
|
-
if (serialized.body) {
|
|
465
|
-
switch (serialized.body.type) {
|
|
466
|
-
case "bytes":
|
|
467
|
-
body = base64Decode(serialized.body.data);
|
|
468
|
-
break;
|
|
469
|
-
case "stream":
|
|
470
|
-
if (getStream) {
|
|
471
|
-
body = getStream(serialized.body.sid) ?? null;
|
|
472
|
-
}
|
|
473
|
-
break;
|
|
102
|
+
open(bid) {
|
|
103
|
+
if (this.#streams.has(bid)) {
|
|
104
|
+
throw new Error(`v2 body reader already registered for bid ${bid}`);
|
|
474
105
|
}
|
|
106
|
+
const state = {
|
|
107
|
+
controller: null,
|
|
108
|
+
stream: null,
|
|
109
|
+
closed: false
|
|
110
|
+
};
|
|
111
|
+
state.stream = new ReadableStream({
|
|
112
|
+
start: (controller) => {
|
|
113
|
+
state.controller = controller;
|
|
114
|
+
},
|
|
115
|
+
cancel: () => {
|
|
116
|
+
state.closed = true;
|
|
117
|
+
this.#streams.delete(bid);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
this.#streams.set(bid, state);
|
|
121
|
+
return state.stream;
|
|
475
122
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
body,
|
|
480
|
-
redirect: serialized.redirect
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
async function serializeResponse(response, options) {
|
|
484
|
-
const streams = [];
|
|
485
|
-
const threshold = options?.httpThreshold ?? HTTP_TRANSFER_THRESHOLD;
|
|
486
|
-
const headers = [];
|
|
487
|
-
response.headers.forEach((value, key) => {
|
|
488
|
-
headers.push([key, value]);
|
|
489
|
-
});
|
|
490
|
-
let body = null;
|
|
491
|
-
if (response.body) {
|
|
492
|
-
const bytes = await response.arrayBuffer();
|
|
493
|
-
if (bytes.byteLength > threshold) {
|
|
494
|
-
const sid = nextStreamId();
|
|
495
|
-
const payload = new Uint8Array(bytes);
|
|
496
|
-
const frameSize = HTTP_TRANSFER_THRESHOLD;
|
|
497
|
-
const stream = new ReadableStream({
|
|
498
|
-
start(controller) {
|
|
499
|
-
for (let offset = 0;offset < payload.byteLength; offset += frameSize) {
|
|
500
|
-
controller.enqueue(payload.slice(offset, Math.min(offset + frameSize, payload.byteLength)));
|
|
501
|
-
}
|
|
502
|
-
controller.close();
|
|
503
|
-
}
|
|
504
|
-
});
|
|
505
|
-
streams.push({ sid, stream });
|
|
506
|
-
body = { type: "stream", sid };
|
|
507
|
-
} else if (bytes.byteLength > 0) {
|
|
508
|
-
body = { type: "bytes", data: base64Encode(new Uint8Array(bytes)) };
|
|
123
|
+
pushChunk(frame) {
|
|
124
|
+
if (frame.kind !== TransportV2BinaryKind.BodyChunk) {
|
|
125
|
+
throw new Error(`v2 body reader received non-BodyChunk frame (kind=${frame.kind})`);
|
|
509
126
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
case "stream":
|
|
529
|
-
if (getStream) {
|
|
530
|
-
body = getStream(serialized.body.sid) ?? null;
|
|
531
|
-
}
|
|
532
|
-
break;
|
|
127
|
+
const state = this.#streams.get(frame.id);
|
|
128
|
+
if (state === undefined || state.closed)
|
|
129
|
+
return;
|
|
130
|
+
const isFin = transportV2IsFin(frame.flags);
|
|
131
|
+
const isAbort = transportV2IsAbort(frame.flags);
|
|
132
|
+
if (isAbort) {
|
|
133
|
+
state.closed = true;
|
|
134
|
+
state.controller?.error(new Error(`v2 body stream ${frame.id} aborted by writer`));
|
|
135
|
+
this.#streams.delete(frame.id);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (frame.payload.byteLength > 0) {
|
|
139
|
+
state.controller?.enqueue(new Uint8Array(frame.payload));
|
|
140
|
+
}
|
|
141
|
+
if (isFin) {
|
|
142
|
+
state.closed = true;
|
|
143
|
+
state.controller?.close();
|
|
144
|
+
this.#streams.delete(frame.id);
|
|
533
145
|
}
|
|
534
146
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
const streams = [];
|
|
543
|
-
const result = await serializeValueInternal(value, streams, options);
|
|
544
|
-
return { value: result, streams };
|
|
545
|
-
}
|
|
546
|
-
async function serializeValueInternal(value, streams, options) {
|
|
547
|
-
if (value === null || value === undefined) {
|
|
548
|
-
return value;
|
|
147
|
+
end(bid) {
|
|
148
|
+
const state = this.#streams.get(bid);
|
|
149
|
+
if (state === undefined || state.closed)
|
|
150
|
+
return;
|
|
151
|
+
state.closed = true;
|
|
152
|
+
state.controller?.close();
|
|
153
|
+
this.#streams.delete(bid);
|
|
549
154
|
}
|
|
550
|
-
|
|
551
|
-
const
|
|
552
|
-
|
|
553
|
-
|
|
155
|
+
abort(bid, reason) {
|
|
156
|
+
const state = this.#streams.get(bid);
|
|
157
|
+
if (state === undefined || state.closed)
|
|
158
|
+
return;
|
|
159
|
+
state.closed = true;
|
|
160
|
+
state.controller?.error(new Error(reason ?? `v2 body stream ${bid} aborted`));
|
|
161
|
+
this.#streams.delete(bid);
|
|
554
162
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
streams.push(...resStreams);
|
|
558
|
-
return { __type: "Response", ...serialized };
|
|
163
|
+
get size() {
|
|
164
|
+
return this.#streams.size;
|
|
559
165
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/bridge/v2/codec.ts
|
|
169
|
+
class TransportV2Codec {
|
|
170
|
+
bodyReaders = new TransportV2BodyReaderRegistry;
|
|
171
|
+
#socket;
|
|
172
|
+
#capabilities;
|
|
173
|
+
#options;
|
|
174
|
+
#handshakeResolver = null;
|
|
175
|
+
#handshakePromise;
|
|
176
|
+
#sentHello = false;
|
|
177
|
+
#receivedHello = false;
|
|
178
|
+
#receivedWelcome = false;
|
|
179
|
+
#negotiated = null;
|
|
180
|
+
#pendingRpc = new Map;
|
|
181
|
+
#nextBid = 1;
|
|
182
|
+
#nextRpcId = 1;
|
|
183
|
+
#closed = false;
|
|
184
|
+
constructor(socket, options = {}) {
|
|
185
|
+
this.#socket = socket;
|
|
186
|
+
this.#capabilities = options.capabilities ?? [];
|
|
187
|
+
this.#options = options;
|
|
188
|
+
this.#handshakePromise = new Promise((resolve, reject) => {
|
|
189
|
+
this.#handshakeResolver = { resolve, reject };
|
|
190
|
+
});
|
|
191
|
+
socket.onmessage = (event) => this.#onMessage(event);
|
|
192
|
+
socket.onclose = () => this.#onClose();
|
|
193
|
+
socket.onerror = (event) => this.#onError(event.error);
|
|
564
194
|
}
|
|
565
|
-
|
|
566
|
-
return
|
|
195
|
+
allocateBid() {
|
|
196
|
+
return this.#nextBid++;
|
|
567
197
|
}
|
|
568
|
-
|
|
569
|
-
return {
|
|
198
|
+
allocateRpcId() {
|
|
199
|
+
return `v2_rpc_${this.#nextRpcId++}`;
|
|
570
200
|
}
|
|
571
|
-
|
|
572
|
-
|
|
201
|
+
sendHello() {
|
|
202
|
+
if (this.#sentHello)
|
|
203
|
+
return;
|
|
204
|
+
this.#sentHello = true;
|
|
205
|
+
const hello = {
|
|
206
|
+
t: "hello",
|
|
207
|
+
protocolVersion: TRANSPORT_V2_PROTOCOL_VERSION,
|
|
208
|
+
capabilities: [...this.#capabilities]
|
|
209
|
+
};
|
|
210
|
+
this.#socket.send(stringifyTransportV2ControlMsg(hello));
|
|
573
211
|
}
|
|
574
|
-
|
|
575
|
-
return
|
|
212
|
+
get handshake() {
|
|
213
|
+
return this.#handshakePromise;
|
|
576
214
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
__devflare: "error",
|
|
580
|
-
name: value.name,
|
|
581
|
-
message: value.message
|
|
582
|
-
};
|
|
583
|
-
if (value.stack)
|
|
584
|
-
encoded.stack = value.stack;
|
|
585
|
-
return encoded;
|
|
215
|
+
get negotiated() {
|
|
216
|
+
return this.#negotiated;
|
|
586
217
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
entries.push([
|
|
591
|
-
await serializeValueInternal(k, streams, options),
|
|
592
|
-
await serializeValueInternal(v, streams, options)
|
|
593
|
-
]);
|
|
218
|
+
sendText(message) {
|
|
219
|
+
if (this.#closed) {
|
|
220
|
+
throw new Error("cannot send on a closed v2 codec");
|
|
594
221
|
}
|
|
595
|
-
|
|
222
|
+
this.#socket.send(message);
|
|
596
223
|
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
values.push(await serializeValueInternal(v, streams, options));
|
|
224
|
+
sendBinary(frame) {
|
|
225
|
+
if (this.#closed) {
|
|
226
|
+
throw new Error("cannot send on a closed v2 codec");
|
|
601
227
|
}
|
|
602
|
-
|
|
228
|
+
this.#socket.send(frame);
|
|
603
229
|
}
|
|
604
|
-
|
|
605
|
-
|
|
230
|
+
call(method, params = []) {
|
|
231
|
+
const id = this.allocateRpcId();
|
|
232
|
+
const call = { t: "rpc.call", id, method, params };
|
|
233
|
+
const promise = new Promise((resolve, reject) => {
|
|
234
|
+
this.#pendingRpc.set(id, { resolve, reject });
|
|
235
|
+
});
|
|
236
|
+
this.sendText(JSON.stringify(call));
|
|
237
|
+
return promise;
|
|
606
238
|
}
|
|
607
|
-
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
result[k] = await serializeValueInternal(v, streams, options);
|
|
611
|
-
}
|
|
612
|
-
return result;
|
|
239
|
+
respondOk(id, result) {
|
|
240
|
+
const reply = { t: "rpc.ok", id, result };
|
|
241
|
+
this.sendText(JSON.stringify(reply));
|
|
613
242
|
}
|
|
614
|
-
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
if (value === null || value === undefined) {
|
|
618
|
-
return value;
|
|
243
|
+
respondErr(id, error) {
|
|
244
|
+
const reply = { t: "rpc.err", id, error };
|
|
245
|
+
this.sendText(JSON.stringify(reply));
|
|
619
246
|
}
|
|
620
|
-
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
set.add(deserializeValue(v, getStream));
|
|
649
|
-
}
|
|
650
|
-
return set;
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
if (obj.__type === "Request") {
|
|
655
|
-
return deserializeRequest(obj, getStream);
|
|
656
|
-
}
|
|
657
|
-
if (obj.__type === "Response") {
|
|
658
|
-
return deserializeResponse(obj, getStream);
|
|
659
|
-
}
|
|
660
|
-
if (obj.__type === "ReadableStream") {
|
|
661
|
-
const sid = obj.sid;
|
|
662
|
-
return getStream?.(sid) ?? null;
|
|
663
|
-
}
|
|
664
|
-
if (obj.__type === "Uint8Array") {
|
|
665
|
-
return base64Decode(obj.data);
|
|
666
|
-
}
|
|
667
|
-
if (obj.__type === "ArrayBuffer") {
|
|
668
|
-
return base64Decode(obj.data).buffer;
|
|
247
|
+
sendWireError(err) {
|
|
248
|
+
const frame = { t: "error", ...err };
|
|
249
|
+
this.sendText(JSON.stringify(frame));
|
|
250
|
+
}
|
|
251
|
+
openBodyReader(bid) {
|
|
252
|
+
return this.bodyReaders.getOrOpen(bid);
|
|
253
|
+
}
|
|
254
|
+
setRpcCallHandler(handler) {
|
|
255
|
+
this.#options = { ...this.#options, onRpcCall: handler };
|
|
256
|
+
}
|
|
257
|
+
close(code, reason) {
|
|
258
|
+
if (this.#closed)
|
|
259
|
+
return;
|
|
260
|
+
this.#closed = true;
|
|
261
|
+
this.#failPending(new Error("v2 transport closed"));
|
|
262
|
+
this.#socket.close(code, reason);
|
|
263
|
+
}
|
|
264
|
+
get isClosed() {
|
|
265
|
+
return this.#closed;
|
|
266
|
+
}
|
|
267
|
+
#onMessage(event) {
|
|
268
|
+
const { data } = event;
|
|
269
|
+
if (typeof data === "string") {
|
|
270
|
+
this.#onText(data);
|
|
271
|
+
} else if (data instanceof Uint8Array) {
|
|
272
|
+
this.#onBinary(data);
|
|
273
|
+
} else if (data instanceof ArrayBuffer) {
|
|
274
|
+
this.#onBinary(new Uint8Array(data));
|
|
669
275
|
}
|
|
670
|
-
|
|
671
|
-
|
|
276
|
+
}
|
|
277
|
+
#onText(data) {
|
|
278
|
+
let msg;
|
|
279
|
+
try {
|
|
280
|
+
msg = parseTransportV2ControlMsg(data);
|
|
281
|
+
} catch {
|
|
282
|
+
const rpc = tryParseRpcMsg(data);
|
|
283
|
+
if (rpc !== null) {
|
|
284
|
+
this.#onRpcMessage(rpc);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const wireErr = tryParseWireError(data);
|
|
288
|
+
if (wireErr !== null) {
|
|
289
|
+
this.#options.onWireError?.(wireErr);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
this.#options.onUnknownControl?.(data);
|
|
293
|
+
return;
|
|
672
294
|
}
|
|
673
|
-
|
|
674
|
-
|
|
295
|
+
switch (msg.t) {
|
|
296
|
+
case "hello":
|
|
297
|
+
this.#onHello(msg);
|
|
298
|
+
break;
|
|
299
|
+
case "welcome":
|
|
300
|
+
this.#onWelcome(msg);
|
|
301
|
+
break;
|
|
302
|
+
case "body.open":
|
|
303
|
+
this.bodyReaders.getOrOpen(msg.bid);
|
|
304
|
+
break;
|
|
305
|
+
case "body.end":
|
|
306
|
+
this.bodyReaders.end(msg.bid);
|
|
307
|
+
break;
|
|
308
|
+
case "body.abort":
|
|
309
|
+
this.bodyReaders.abort(msg.bid, msg.error);
|
|
310
|
+
break;
|
|
675
311
|
}
|
|
676
|
-
|
|
677
|
-
|
|
312
|
+
}
|
|
313
|
+
#onBinary(data) {
|
|
314
|
+
let frame;
|
|
315
|
+
try {
|
|
316
|
+
frame = decodeTransportV2BinaryFrame(data);
|
|
317
|
+
} catch {
|
|
318
|
+
return;
|
|
678
319
|
}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
320
|
+
if (frame.kind === TransportV2BinaryKind.BodyChunk) {
|
|
321
|
+
this.bodyReaders.pushChunk(frame);
|
|
322
|
+
return;
|
|
682
323
|
}
|
|
683
|
-
|
|
324
|
+
this.#options.onUnknownBinary?.(frame);
|
|
684
325
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
326
|
+
#onRpcMessage(msg) {
|
|
327
|
+
switch (msg.t) {
|
|
328
|
+
case "rpc.call":
|
|
329
|
+
this.#options.onRpcCall?.(msg);
|
|
330
|
+
break;
|
|
331
|
+
case "rpc.ok": {
|
|
332
|
+
const pending = this.#pendingRpc.get(msg.id);
|
|
333
|
+
if (pending !== undefined) {
|
|
334
|
+
this.#pendingRpc.delete(msg.id);
|
|
335
|
+
pending.resolve(msg.result);
|
|
336
|
+
}
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
case "rpc.err": {
|
|
340
|
+
const pending = this.#pendingRpc.get(msg.id);
|
|
341
|
+
if (pending !== undefined) {
|
|
342
|
+
this.#pendingRpc.delete(msg.id);
|
|
343
|
+
const err = new Error(msg.error.message);
|
|
344
|
+
Object.assign(err, { code: msg.error.code, details: msg.error.details });
|
|
345
|
+
pending.reject(err);
|
|
346
|
+
}
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
690
350
|
}
|
|
691
|
-
|
|
692
|
-
|
|
351
|
+
#onHello(msg) {
|
|
352
|
+
if (this.#receivedHello) {
|
|
353
|
+
this.close(TRANSPORT_V2_UNSUPPORTED_VERSION_CLOSE_CODE, "duplicate hello");
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
this.#receivedHello = true;
|
|
357
|
+
const negotiated = negotiateTransportV2Capabilities(this.#capabilities, msg.capabilities);
|
|
358
|
+
const welcome = {
|
|
359
|
+
t: "welcome",
|
|
360
|
+
protocolVersion: TRANSPORT_V2_PROTOCOL_VERSION,
|
|
361
|
+
capabilities: negotiated
|
|
362
|
+
};
|
|
363
|
+
this.#socket.send(stringifyTransportV2ControlMsg(welcome));
|
|
364
|
+
this.#completeHandshake({
|
|
365
|
+
protocolVersion: TRANSPORT_V2_PROTOCOL_VERSION,
|
|
366
|
+
capabilities: negotiated
|
|
367
|
+
});
|
|
693
368
|
}
|
|
694
|
-
|
|
695
|
-
|
|
369
|
+
#onWelcome(msg) {
|
|
370
|
+
if (this.#receivedWelcome)
|
|
371
|
+
return;
|
|
372
|
+
this.#receivedWelcome = true;
|
|
373
|
+
this.#completeHandshake({
|
|
374
|
+
protocolVersion: TRANSPORT_V2_PROTOCOL_VERSION,
|
|
375
|
+
capabilities: msg.capabilities
|
|
376
|
+
});
|
|
696
377
|
}
|
|
697
|
-
|
|
698
|
-
|
|
378
|
+
#completeHandshake(result) {
|
|
379
|
+
if (this.#negotiated !== null)
|
|
380
|
+
return;
|
|
381
|
+
this.#negotiated = result;
|
|
382
|
+
this.#handshakeResolver?.resolve(result);
|
|
383
|
+
this.#handshakeResolver = null;
|
|
699
384
|
}
|
|
700
|
-
|
|
701
|
-
|
|
385
|
+
#onClose() {
|
|
386
|
+
if (this.#closed) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
this.#closed = true;
|
|
390
|
+
this.#failPending(new Error("v2 transport closed"));
|
|
702
391
|
}
|
|
703
|
-
|
|
704
|
-
|
|
392
|
+
#onError(error) {
|
|
393
|
+
const wrapped = error instanceof Error ? error : new Error(String(error));
|
|
394
|
+
this.#failPending(wrapped);
|
|
705
395
|
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
size: serialized.size,
|
|
712
|
-
etag: serialized.etag,
|
|
713
|
-
httpEtag: serialized.httpEtag,
|
|
714
|
-
checksums: serialized.checksums,
|
|
715
|
-
uploaded: serialized.uploaded ? new Date(serialized.uploaded) : new Date,
|
|
716
|
-
httpMetadata: serialized.httpMetadata,
|
|
717
|
-
customMetadata: serialized.customMetadata,
|
|
718
|
-
range: serialized.range,
|
|
719
|
-
storageClass: serialized.storageClass,
|
|
720
|
-
writeHttpMetadata(headers) {
|
|
721
|
-
applySerializedHttpMetadata(headers, serialized.httpMetadata);
|
|
396
|
+
#failPending(error) {
|
|
397
|
+
const resolver = this.#handshakeResolver;
|
|
398
|
+
if (resolver !== null) {
|
|
399
|
+
this.#handshakeResolver = null;
|
|
400
|
+
resolver.reject(error);
|
|
722
401
|
}
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
function deserializeR2Object(obj) {
|
|
726
|
-
const serialized = obj;
|
|
727
|
-
return {
|
|
728
|
-
...createSerializedR2Metadata(serialized)
|
|
729
|
-
};
|
|
730
|
-
}
|
|
731
|
-
function deserializeR2ObjectBody(obj) {
|
|
732
|
-
const serialized = obj;
|
|
733
|
-
const bodyBytes = serialized.bodyData ? base64Decode(serialized.bodyData) : new Uint8Array(0);
|
|
734
|
-
const r2ObjectBody = {
|
|
735
|
-
...createSerializedR2Metadata(serialized),
|
|
736
|
-
body: new ReadableStream({
|
|
737
|
-
start(controller) {
|
|
738
|
-
controller.enqueue(bodyBytes);
|
|
739
|
-
controller.close();
|
|
740
|
-
}
|
|
741
|
-
}),
|
|
742
|
-
bodyUsed: false,
|
|
743
|
-
async arrayBuffer() {
|
|
744
|
-
const copy = new Uint8Array(bodyBytes.byteLength);
|
|
745
|
-
copy.set(bodyBytes);
|
|
746
|
-
return copy.buffer;
|
|
747
|
-
},
|
|
748
|
-
async text() {
|
|
749
|
-
return new TextDecoder().decode(bodyBytes);
|
|
750
|
-
},
|
|
751
|
-
async json() {
|
|
752
|
-
const text = new TextDecoder().decode(bodyBytes);
|
|
753
|
-
return JSON.parse(text);
|
|
754
|
-
},
|
|
755
|
-
async blob() {
|
|
756
|
-
const contentType = serialized.httpMetadata?.contentType || "application/octet-stream";
|
|
757
|
-
const buffer = bodyBytes.buffer.slice(bodyBytes.byteOffset, bodyBytes.byteOffset + bodyBytes.byteLength);
|
|
758
|
-
return new Blob([buffer], { type: contentType });
|
|
402
|
+
for (const pending of this.#pendingRpc.values()) {
|
|
403
|
+
pending.reject(error);
|
|
759
404
|
}
|
|
760
|
-
|
|
761
|
-
|
|
405
|
+
this.#pendingRpc.clear();
|
|
406
|
+
}
|
|
762
407
|
}
|
|
763
|
-
function
|
|
764
|
-
|
|
765
|
-
|
|
408
|
+
function tryParseRpcMsg(data) {
|
|
409
|
+
let parsed;
|
|
410
|
+
try {
|
|
411
|
+
parsed = JSON.parse(data);
|
|
412
|
+
} catch {
|
|
413
|
+
return null;
|
|
766
414
|
}
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
415
|
+
if (typeof parsed !== "object" || parsed === null || !("t" in parsed))
|
|
416
|
+
return null;
|
|
417
|
+
const t = parsed.t;
|
|
418
|
+
if (t === "rpc.call" || t === "rpc.ok" || t === "rpc.err") {
|
|
419
|
+
return parsed;
|
|
770
420
|
}
|
|
771
|
-
return
|
|
421
|
+
return null;
|
|
772
422
|
}
|
|
773
|
-
function
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
for (let i = 0;i < binary.length; i++) {
|
|
780
|
-
bytes[i] = binary.charCodeAt(i);
|
|
423
|
+
function tryParseWireError(data) {
|
|
424
|
+
let parsed;
|
|
425
|
+
try {
|
|
426
|
+
parsed = JSON.parse(data);
|
|
427
|
+
} catch {
|
|
428
|
+
return null;
|
|
781
429
|
}
|
|
782
|
-
|
|
430
|
+
if (typeof parsed !== "object" || parsed === null || !("t" in parsed))
|
|
431
|
+
return null;
|
|
432
|
+
const candidate = parsed;
|
|
433
|
+
if (candidate.t !== "error")
|
|
434
|
+
return null;
|
|
435
|
+
const scope = candidate.scope;
|
|
436
|
+
if (scope !== "transport" && scope !== "rpc" && scope !== "stream" && scope !== "ws")
|
|
437
|
+
return null;
|
|
438
|
+
const err = candidate.error;
|
|
439
|
+
if (!err || typeof err.code !== "string" || typeof err.message !== "string")
|
|
440
|
+
return null;
|
|
441
|
+
return parsed;
|
|
783
442
|
}
|
|
784
443
|
|
|
785
|
-
// src/bridge/v2/
|
|
786
|
-
var
|
|
787
|
-
var TRANSPORT_V2_UNSUPPORTED_VERSION_CLOSE_CODE = 4001;
|
|
788
|
-
var TransportV2BinaryKind = {
|
|
444
|
+
// src/bridge/v2/wire.ts
|
|
445
|
+
var BinaryKind = {
|
|
789
446
|
StreamChunk: 1,
|
|
790
|
-
WsData: 2
|
|
791
|
-
BodyChunk: 3
|
|
447
|
+
WsData: 2
|
|
792
448
|
};
|
|
793
|
-
var
|
|
449
|
+
var BinaryFlags = {
|
|
794
450
|
FIN: 1,
|
|
795
|
-
TEXT: 2
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
}
|
|
808
|
-
return {
|
|
809
|
-
kind,
|
|
810
|
-
id: view.getUint32(1, true),
|
|
811
|
-
seq: view.getUint32(5, true),
|
|
812
|
-
flags: view.getUint8(9),
|
|
813
|
-
payload: frame.subarray(TRANSPORT_V2_BINARY_HEADER_SIZE)
|
|
814
|
-
};
|
|
815
|
-
}
|
|
816
|
-
function transportV2IsFin(flags) {
|
|
817
|
-
return (flags & TransportV2BinaryFlags.FIN) !== 0;
|
|
818
|
-
}
|
|
819
|
-
function transportV2IsAbort(flags) {
|
|
820
|
-
return (flags & TransportV2BinaryFlags.ABORT) !== 0;
|
|
451
|
+
TEXT: 2
|
|
452
|
+
};
|
|
453
|
+
var BINARY_HEADER_SIZE = 10;
|
|
454
|
+
function encodeBinaryFrame(kind, id, seq, flags, payload) {
|
|
455
|
+
const frame = new Uint8Array(BINARY_HEADER_SIZE + payload.byteLength);
|
|
456
|
+
const view = new DataView(frame.buffer);
|
|
457
|
+
view.setUint8(0, kind);
|
|
458
|
+
view.setUint32(1, id, true);
|
|
459
|
+
view.setUint32(5, seq, true);
|
|
460
|
+
view.setUint8(9, flags);
|
|
461
|
+
frame.set(payload, BINARY_HEADER_SIZE);
|
|
462
|
+
return frame;
|
|
821
463
|
}
|
|
822
|
-
|
|
823
|
-
"hello",
|
|
824
|
-
"welcome",
|
|
825
|
-
"body.open",
|
|
826
|
-
"body.end",
|
|
827
|
-
"body.abort"
|
|
828
|
-
]);
|
|
829
|
-
function parseTransportV2ControlMsg(data) {
|
|
464
|
+
function parseJsonMsg(data) {
|
|
830
465
|
const msg = JSON.parse(data);
|
|
831
466
|
if (typeof msg !== "object" || msg === null || !("t" in msg)) {
|
|
832
|
-
throw new Error("Invalid
|
|
833
|
-
}
|
|
834
|
-
if (!KNOWN_V2_CONTROL_TYPES.has(msg.t)) {
|
|
835
|
-
throw new Error(`Invalid transport v2 control message: unknown type "${msg.t}"`);
|
|
836
|
-
}
|
|
837
|
-
if (msg.t === "hello" || msg.t === "welcome") {
|
|
838
|
-
if (msg.protocolVersion !== TRANSPORT_V2_PROTOCOL_VERSION) {
|
|
839
|
-
throw new Error(`Invalid transport v2 ${msg.t}: protocolVersion ${msg.protocolVersion} != ${TRANSPORT_V2_PROTOCOL_VERSION}`);
|
|
840
|
-
}
|
|
841
|
-
if (!Array.isArray(msg.capabilities)) {
|
|
842
|
-
throw new Error(`Invalid transport v2 ${msg.t}: capabilities must be an array`);
|
|
843
|
-
}
|
|
467
|
+
throw new Error("Invalid message: missing type field");
|
|
844
468
|
}
|
|
845
469
|
return msg;
|
|
846
470
|
}
|
|
847
|
-
function
|
|
471
|
+
function stringifyJsonMsg(msg) {
|
|
848
472
|
return JSON.stringify(msg);
|
|
849
473
|
}
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
return
|
|
474
|
+
var streamIdCounter = 0;
|
|
475
|
+
var wsIdCounter = 0;
|
|
476
|
+
function nextStreamId() {
|
|
477
|
+
return ++streamIdCounter;
|
|
854
478
|
}
|
|
479
|
+
function nextWsId() {
|
|
480
|
+
return ++wsIdCounter;
|
|
481
|
+
}
|
|
482
|
+
var DEFAULT_CHUNK_SIZE = 256 * 1024;
|
|
483
|
+
var HTTP_TRANSFER_THRESHOLD = 512 * 1024;
|
|
484
|
+
var DEFAULT_BRIDGE_PORT = 8686;
|
|
855
485
|
|
|
856
|
-
// src/bridge/v2/
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
if (
|
|
868
|
-
throw new Error(
|
|
869
|
-
}
|
|
870
|
-
const state = {
|
|
871
|
-
controller: null,
|
|
872
|
-
stream: null,
|
|
873
|
-
closed: false
|
|
874
|
-
};
|
|
875
|
-
state.stream = new ReadableStream({
|
|
876
|
-
start: (controller) => {
|
|
877
|
-
state.controller = controller;
|
|
878
|
-
},
|
|
879
|
-
cancel: () => {
|
|
880
|
-
state.closed = true;
|
|
881
|
-
this.#streams.delete(bid);
|
|
882
|
-
}
|
|
883
|
-
});
|
|
884
|
-
this.#streams.set(bid, state);
|
|
885
|
-
return state.stream;
|
|
886
|
-
}
|
|
887
|
-
pushChunk(frame) {
|
|
888
|
-
if (frame.kind !== TransportV2BinaryKind.BodyChunk) {
|
|
889
|
-
throw new Error(`v2 body reader received non-BodyChunk frame (kind=${frame.kind})`);
|
|
890
|
-
}
|
|
891
|
-
const state = this.#streams.get(frame.id);
|
|
892
|
-
if (state === undefined || state.closed)
|
|
893
|
-
return;
|
|
894
|
-
const isFin = transportV2IsFin(frame.flags);
|
|
895
|
-
const isAbort = transportV2IsAbort(frame.flags);
|
|
896
|
-
if (isAbort) {
|
|
897
|
-
state.closed = true;
|
|
898
|
-
state.controller?.error(new Error(`v2 body stream ${frame.id} aborted by writer`));
|
|
899
|
-
this.#streams.delete(frame.id);
|
|
900
|
-
return;
|
|
901
|
-
}
|
|
902
|
-
if (frame.payload.byteLength > 0) {
|
|
903
|
-
state.controller?.enqueue(new Uint8Array(frame.payload));
|
|
486
|
+
// src/bridge/v2/value-serialization.ts
|
|
487
|
+
async function serializeRequest(request, options) {
|
|
488
|
+
const streams = [];
|
|
489
|
+
const threshold = options?.httpThreshold ?? HTTP_TRANSFER_THRESHOLD;
|
|
490
|
+
const headers = [];
|
|
491
|
+
request.headers.forEach((value, key) => {
|
|
492
|
+
headers.push([key, value]);
|
|
493
|
+
});
|
|
494
|
+
let body = null;
|
|
495
|
+
if (request.body) {
|
|
496
|
+
const bytes = await request.arrayBuffer();
|
|
497
|
+
if (bytes.byteLength > threshold) {
|
|
498
|
+
throw new Error("Request body exceeds the bridge inline limit (~512 KB) and large request-body streaming is not yet supported over the local bridge. " + "Send the payload in smaller chunks or via an R2 binding for now.");
|
|
904
499
|
}
|
|
905
|
-
if (
|
|
906
|
-
|
|
907
|
-
state.controller?.close();
|
|
908
|
-
this.#streams.delete(frame.id);
|
|
500
|
+
if (bytes.byteLength > 0) {
|
|
501
|
+
body = { type: "bytes", data: base64Encode(new Uint8Array(bytes)) };
|
|
909
502
|
}
|
|
910
503
|
}
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
if (state === undefined || state.closed)
|
|
922
|
-
return;
|
|
923
|
-
state.closed = true;
|
|
924
|
-
state.controller?.error(new Error(reason ?? `v2 body stream ${bid} aborted`));
|
|
925
|
-
this.#streams.delete(bid);
|
|
926
|
-
}
|
|
927
|
-
get size() {
|
|
928
|
-
return this.#streams.size;
|
|
929
|
-
}
|
|
504
|
+
return {
|
|
505
|
+
serialized: {
|
|
506
|
+
url: request.url,
|
|
507
|
+
method: request.method,
|
|
508
|
+
headers,
|
|
509
|
+
body,
|
|
510
|
+
redirect: request.redirect
|
|
511
|
+
},
|
|
512
|
+
streams
|
|
513
|
+
};
|
|
930
514
|
}
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
#pendingRpc = new Map;
|
|
945
|
-
#nextBid = 1;
|
|
946
|
-
#nextRpcId = 1;
|
|
947
|
-
#closed = false;
|
|
948
|
-
constructor(socket, options = {}) {
|
|
949
|
-
this.#socket = socket;
|
|
950
|
-
this.#capabilities = options.capabilities ?? [];
|
|
951
|
-
this.#options = options;
|
|
952
|
-
this.#handshakePromise = new Promise((resolve, reject) => {
|
|
953
|
-
this.#handshakeResolver = { resolve, reject };
|
|
954
|
-
});
|
|
955
|
-
socket.onmessage = (event) => this.#onMessage(event);
|
|
956
|
-
socket.onclose = () => this.#onClose();
|
|
957
|
-
socket.onerror = (event) => this.#onError(event.error);
|
|
958
|
-
}
|
|
959
|
-
allocateBid() {
|
|
960
|
-
return this.#nextBid++;
|
|
961
|
-
}
|
|
962
|
-
allocateRpcId() {
|
|
963
|
-
return `v2_rpc_${this.#nextRpcId++}`;
|
|
964
|
-
}
|
|
965
|
-
sendHello() {
|
|
966
|
-
if (this.#sentHello)
|
|
967
|
-
return;
|
|
968
|
-
this.#sentHello = true;
|
|
969
|
-
const hello = {
|
|
970
|
-
t: "hello",
|
|
971
|
-
protocolVersion: TRANSPORT_V2_PROTOCOL_VERSION,
|
|
972
|
-
capabilities: [...this.#capabilities]
|
|
973
|
-
};
|
|
974
|
-
this.#socket.send(stringifyTransportV2ControlMsg(hello));
|
|
975
|
-
}
|
|
976
|
-
get handshake() {
|
|
977
|
-
return this.#handshakePromise;
|
|
515
|
+
function deserializeRequest(serialized, getStream) {
|
|
516
|
+
let body = null;
|
|
517
|
+
if (serialized.body) {
|
|
518
|
+
switch (serialized.body.type) {
|
|
519
|
+
case "bytes":
|
|
520
|
+
body = base64Decode(serialized.body.data);
|
|
521
|
+
break;
|
|
522
|
+
case "stream":
|
|
523
|
+
if (getStream) {
|
|
524
|
+
body = getStream(serialized.body.sid) ?? null;
|
|
525
|
+
}
|
|
526
|
+
break;
|
|
527
|
+
}
|
|
978
528
|
}
|
|
979
|
-
|
|
980
|
-
|
|
529
|
+
return new Request(serialized.url, {
|
|
530
|
+
method: serialized.method,
|
|
531
|
+
headers: serialized.headers,
|
|
532
|
+
body,
|
|
533
|
+
redirect: serialized.redirect
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
async function serializeResponse(response, options) {
|
|
537
|
+
const streams = [];
|
|
538
|
+
const threshold = options?.httpThreshold ?? HTTP_TRANSFER_THRESHOLD;
|
|
539
|
+
const headers = [];
|
|
540
|
+
response.headers.forEach((value, key) => {
|
|
541
|
+
headers.push([key, value]);
|
|
542
|
+
});
|
|
543
|
+
let body = null;
|
|
544
|
+
if (response.body) {
|
|
545
|
+
const bytes = await response.arrayBuffer();
|
|
546
|
+
if (bytes.byteLength > threshold) {
|
|
547
|
+
const sid = nextStreamId();
|
|
548
|
+
const payload = new Uint8Array(bytes);
|
|
549
|
+
const frameSize = HTTP_TRANSFER_THRESHOLD;
|
|
550
|
+
const stream = new ReadableStream({
|
|
551
|
+
start(controller) {
|
|
552
|
+
for (let offset = 0;offset < payload.byteLength; offset += frameSize) {
|
|
553
|
+
controller.enqueue(payload.slice(offset, Math.min(offset + frameSize, payload.byteLength)));
|
|
554
|
+
}
|
|
555
|
+
controller.close();
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
streams.push({ sid, stream });
|
|
559
|
+
body = { type: "stream", sid };
|
|
560
|
+
} else if (bytes.byteLength > 0) {
|
|
561
|
+
body = { type: "bytes", data: base64Encode(new Uint8Array(bytes)) };
|
|
562
|
+
}
|
|
981
563
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
564
|
+
return {
|
|
565
|
+
serialized: {
|
|
566
|
+
status: response.status,
|
|
567
|
+
statusText: response.statusText,
|
|
568
|
+
headers,
|
|
569
|
+
body
|
|
570
|
+
},
|
|
571
|
+
streams
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
function deserializeResponse(serialized, getStream) {
|
|
575
|
+
let body = null;
|
|
576
|
+
if (serialized.body) {
|
|
577
|
+
switch (serialized.body.type) {
|
|
578
|
+
case "bytes":
|
|
579
|
+
body = base64Decode(serialized.body.data);
|
|
580
|
+
break;
|
|
581
|
+
case "stream":
|
|
582
|
+
if (getStream) {
|
|
583
|
+
body = getStream(serialized.body.sid) ?? null;
|
|
584
|
+
}
|
|
585
|
+
break;
|
|
985
586
|
}
|
|
986
|
-
this.#socket.send(message);
|
|
987
587
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
588
|
+
return new Response(body, {
|
|
589
|
+
status: serialized.status,
|
|
590
|
+
statusText: serialized.statusText,
|
|
591
|
+
headers: serialized.headers
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
async function serializeValue(value, options) {
|
|
595
|
+
const streams = [];
|
|
596
|
+
const result = await serializeValueInternal(value, streams, options);
|
|
597
|
+
return { value: result, streams };
|
|
598
|
+
}
|
|
599
|
+
async function serializeValueInternal(value, streams, options) {
|
|
600
|
+
if (value === null || value === undefined) {
|
|
601
|
+
return value;
|
|
993
602
|
}
|
|
994
|
-
|
|
995
|
-
const
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
this.#pendingRpc.set(id, { resolve, reject });
|
|
999
|
-
});
|
|
1000
|
-
this.sendText(JSON.stringify(call));
|
|
1001
|
-
return promise;
|
|
603
|
+
if (value instanceof Request) {
|
|
604
|
+
const { serialized, streams: reqStreams } = await serializeRequest(value, options);
|
|
605
|
+
streams.push(...reqStreams);
|
|
606
|
+
return { __type: "Request", ...serialized };
|
|
1002
607
|
}
|
|
1003
|
-
|
|
1004
|
-
const
|
|
1005
|
-
|
|
608
|
+
if (value instanceof Response) {
|
|
609
|
+
const { serialized, streams: resStreams } = await serializeResponse(value, options);
|
|
610
|
+
streams.push(...resStreams);
|
|
611
|
+
return { __type: "Response", ...serialized };
|
|
1006
612
|
}
|
|
1007
|
-
|
|
1008
|
-
const
|
|
1009
|
-
|
|
613
|
+
if (value instanceof ReadableStream) {
|
|
614
|
+
const sid = nextStreamId();
|
|
615
|
+
streams.push({ sid, stream: value });
|
|
616
|
+
return { __type: "ReadableStream", sid };
|
|
1010
617
|
}
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
this.sendText(JSON.stringify(frame));
|
|
618
|
+
if (value instanceof Uint8Array) {
|
|
619
|
+
return { __type: "Uint8Array", data: base64Encode(value) };
|
|
1014
620
|
}
|
|
1015
|
-
|
|
1016
|
-
return
|
|
621
|
+
if (value instanceof ArrayBuffer) {
|
|
622
|
+
return { __type: "ArrayBuffer", data: base64Encode(new Uint8Array(value)) };
|
|
1017
623
|
}
|
|
1018
|
-
|
|
1019
|
-
|
|
624
|
+
if (value instanceof Date) {
|
|
625
|
+
return { __devflare: "date", iso: value.toISOString() };
|
|
1020
626
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
return;
|
|
1024
|
-
this.#closed = true;
|
|
1025
|
-
this.#failPending(new Error("v2 transport closed"));
|
|
1026
|
-
this.#socket.close(code, reason);
|
|
627
|
+
if (value instanceof URL) {
|
|
628
|
+
return { __devflare: "url", href: value.href };
|
|
1027
629
|
}
|
|
1028
|
-
|
|
1029
|
-
|
|
630
|
+
if (value instanceof Error) {
|
|
631
|
+
const encoded = {
|
|
632
|
+
__devflare: "error",
|
|
633
|
+
name: value.name,
|
|
634
|
+
message: value.message
|
|
635
|
+
};
|
|
636
|
+
if (value.stack)
|
|
637
|
+
encoded.stack = value.stack;
|
|
638
|
+
return encoded;
|
|
1030
639
|
}
|
|
1031
|
-
|
|
1032
|
-
const
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
this.#onBinary(new Uint8Array(data));
|
|
640
|
+
if (value instanceof Map) {
|
|
641
|
+
const entries = [];
|
|
642
|
+
for (const [k, v] of value.entries()) {
|
|
643
|
+
entries.push([
|
|
644
|
+
await serializeValueInternal(k, streams, options),
|
|
645
|
+
await serializeValueInternal(v, streams, options)
|
|
646
|
+
]);
|
|
1039
647
|
}
|
|
648
|
+
return { __devflare: "map", entries };
|
|
1040
649
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
} catch {
|
|
1046
|
-
const rpc = tryParseRpcMsg(data);
|
|
1047
|
-
if (rpc !== null) {
|
|
1048
|
-
this.#onRpcMessage(rpc);
|
|
1049
|
-
return;
|
|
1050
|
-
}
|
|
1051
|
-
const wireErr = tryParseWireError(data);
|
|
1052
|
-
if (wireErr !== null) {
|
|
1053
|
-
this.#options.onWireError?.(wireErr);
|
|
1054
|
-
return;
|
|
1055
|
-
}
|
|
1056
|
-
this.#options.onUnknownControl?.(data);
|
|
1057
|
-
return;
|
|
1058
|
-
}
|
|
1059
|
-
switch (msg.t) {
|
|
1060
|
-
case "hello":
|
|
1061
|
-
this.#onHello(msg);
|
|
1062
|
-
break;
|
|
1063
|
-
case "welcome":
|
|
1064
|
-
this.#onWelcome(msg);
|
|
1065
|
-
break;
|
|
1066
|
-
case "body.open":
|
|
1067
|
-
this.bodyReaders.getOrOpen(msg.bid);
|
|
1068
|
-
break;
|
|
1069
|
-
case "body.end":
|
|
1070
|
-
this.bodyReaders.end(msg.bid);
|
|
1071
|
-
break;
|
|
1072
|
-
case "body.abort":
|
|
1073
|
-
this.bodyReaders.abort(msg.bid, msg.error);
|
|
1074
|
-
break;
|
|
650
|
+
if (value instanceof Set) {
|
|
651
|
+
const values = [];
|
|
652
|
+
for (const v of value.values()) {
|
|
653
|
+
values.push(await serializeValueInternal(v, streams, options));
|
|
1075
654
|
}
|
|
655
|
+
return { __devflare: "set", values };
|
|
1076
656
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
if (frame.kind === TransportV2BinaryKind.BodyChunk) {
|
|
1085
|
-
this.bodyReaders.pushChunk(frame);
|
|
1086
|
-
return;
|
|
657
|
+
if (Array.isArray(value)) {
|
|
658
|
+
return Promise.all(value.map((v) => serializeValueInternal(v, streams, options)));
|
|
659
|
+
}
|
|
660
|
+
if (typeof value === "object") {
|
|
661
|
+
const result = {};
|
|
662
|
+
for (const [k, v] of Object.entries(value)) {
|
|
663
|
+
result[k] = await serializeValueInternal(v, streams, options);
|
|
1087
664
|
}
|
|
1088
|
-
|
|
665
|
+
return result;
|
|
1089
666
|
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
667
|
+
return value;
|
|
668
|
+
}
|
|
669
|
+
function deserializeValue(value, getStream) {
|
|
670
|
+
if (value === null || value === undefined) {
|
|
671
|
+
return value;
|
|
672
|
+
}
|
|
673
|
+
if (typeof value === "object" && value !== null) {
|
|
674
|
+
const obj = value;
|
|
675
|
+
if (typeof obj.__devflare === "string") {
|
|
676
|
+
switch (obj.__devflare) {
|
|
677
|
+
case "date":
|
|
678
|
+
return new Date(obj.iso);
|
|
679
|
+
case "url":
|
|
680
|
+
return new URL(obj.href);
|
|
681
|
+
case "error": {
|
|
682
|
+
const err = new Error(obj.message);
|
|
683
|
+
if (typeof obj.name === "string")
|
|
684
|
+
err.name = obj.name;
|
|
685
|
+
if (typeof obj.stack === "string")
|
|
686
|
+
err.stack = obj.stack;
|
|
687
|
+
return err;
|
|
1100
688
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
689
|
+
case "map": {
|
|
690
|
+
const entries = obj.entries ?? [];
|
|
691
|
+
const map = new Map;
|
|
692
|
+
for (const [k, v] of entries) {
|
|
693
|
+
map.set(deserializeValue(k, getStream), deserializeValue(v, getStream));
|
|
694
|
+
}
|
|
695
|
+
return map;
|
|
696
|
+
}
|
|
697
|
+
case "set": {
|
|
698
|
+
const values = obj.values ?? [];
|
|
699
|
+
const set = new Set;
|
|
700
|
+
for (const v of values) {
|
|
701
|
+
set.add(deserializeValue(v, getStream));
|
|
702
|
+
}
|
|
703
|
+
return set;
|
|
1110
704
|
}
|
|
1111
|
-
break;
|
|
1112
705
|
}
|
|
1113
706
|
}
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
if (this.#receivedHello) {
|
|
1117
|
-
this.close(TRANSPORT_V2_UNSUPPORTED_VERSION_CLOSE_CODE, "duplicate hello");
|
|
1118
|
-
return;
|
|
707
|
+
if (obj.__type === "Request") {
|
|
708
|
+
return deserializeRequest(obj, getStream);
|
|
1119
709
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
|
|
710
|
+
if (obj.__type === "Response") {
|
|
711
|
+
return deserializeResponse(obj, getStream);
|
|
712
|
+
}
|
|
713
|
+
if (obj.__type === "ReadableStream") {
|
|
714
|
+
const sid = obj.sid;
|
|
715
|
+
return getStream?.(sid) ?? null;
|
|
716
|
+
}
|
|
717
|
+
if (obj.__type === "Uint8Array") {
|
|
718
|
+
return base64Decode(obj.data);
|
|
719
|
+
}
|
|
720
|
+
if (obj.__type === "ArrayBuffer") {
|
|
721
|
+
return base64Decode(obj.data).buffer;
|
|
722
|
+
}
|
|
723
|
+
if (obj.__type === "R2Object") {
|
|
724
|
+
return deserializeR2Object(obj);
|
|
725
|
+
}
|
|
726
|
+
if (obj.__type === "R2ObjectBody") {
|
|
727
|
+
return deserializeR2ObjectBody(obj);
|
|
728
|
+
}
|
|
729
|
+
if (Array.isArray(value)) {
|
|
730
|
+
return value.map((v) => deserializeValue(v, getStream));
|
|
731
|
+
}
|
|
732
|
+
const result = {};
|
|
733
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
734
|
+
result[k] = deserializeValue(v, getStream);
|
|
735
|
+
}
|
|
736
|
+
return result;
|
|
737
|
+
}
|
|
738
|
+
return value;
|
|
739
|
+
}
|
|
740
|
+
function applySerializedHttpMetadata(headers, httpMetadata) {
|
|
741
|
+
if (httpMetadata?.contentType) {
|
|
742
|
+
headers.set("Content-Type", httpMetadata.contentType);
|
|
1129
743
|
}
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
return;
|
|
1133
|
-
this.#receivedWelcome = true;
|
|
1134
|
-
this.#completeHandshake({
|
|
1135
|
-
protocolVersion: TRANSPORT_V2_PROTOCOL_VERSION,
|
|
1136
|
-
capabilities: msg.capabilities
|
|
1137
|
-
});
|
|
744
|
+
if (httpMetadata?.contentLanguage) {
|
|
745
|
+
headers.set("Content-Language", httpMetadata.contentLanguage);
|
|
1138
746
|
}
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
return;
|
|
1142
|
-
this.#negotiated = result;
|
|
1143
|
-
this.#handshakeResolver?.resolve(result);
|
|
1144
|
-
this.#handshakeResolver = null;
|
|
747
|
+
if (httpMetadata?.contentDisposition) {
|
|
748
|
+
headers.set("Content-Disposition", httpMetadata.contentDisposition);
|
|
1145
749
|
}
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
return;
|
|
1149
|
-
}
|
|
1150
|
-
this.#closed = true;
|
|
1151
|
-
this.#failPending(new Error("v2 transport closed"));
|
|
750
|
+
if (httpMetadata?.contentEncoding) {
|
|
751
|
+
headers.set("Content-Encoding", httpMetadata.contentEncoding);
|
|
1152
752
|
}
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
this.#failPending(wrapped);
|
|
753
|
+
if (httpMetadata?.cacheControl) {
|
|
754
|
+
headers.set("Cache-Control", httpMetadata.cacheControl);
|
|
1156
755
|
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
756
|
+
if (httpMetadata?.cacheExpiry) {
|
|
757
|
+
headers.set("Expires", new Date(httpMetadata.cacheExpiry).toUTCString());
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
function createSerializedR2Metadata(serialized) {
|
|
761
|
+
return {
|
|
762
|
+
key: serialized.key,
|
|
763
|
+
version: serialized.version,
|
|
764
|
+
size: serialized.size,
|
|
765
|
+
etag: serialized.etag,
|
|
766
|
+
httpEtag: serialized.httpEtag,
|
|
767
|
+
checksums: serialized.checksums,
|
|
768
|
+
uploaded: serialized.uploaded ? new Date(serialized.uploaded) : new Date,
|
|
769
|
+
httpMetadata: serialized.httpMetadata,
|
|
770
|
+
customMetadata: serialized.customMetadata,
|
|
771
|
+
range: serialized.range,
|
|
772
|
+
storageClass: serialized.storageClass,
|
|
773
|
+
writeHttpMetadata(headers) {
|
|
774
|
+
applySerializedHttpMetadata(headers, serialized.httpMetadata);
|
|
1162
775
|
}
|
|
1163
|
-
|
|
1164
|
-
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
function deserializeR2Object(obj) {
|
|
779
|
+
const serialized = obj;
|
|
780
|
+
return {
|
|
781
|
+
...createSerializedR2Metadata(serialized)
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
function deserializeR2ObjectBody(obj) {
|
|
785
|
+
const serialized = obj;
|
|
786
|
+
const bodyBytes = serialized.bodyData ? base64Decode(serialized.bodyData) : new Uint8Array(0);
|
|
787
|
+
const r2ObjectBody = {
|
|
788
|
+
...createSerializedR2Metadata(serialized),
|
|
789
|
+
body: new ReadableStream({
|
|
790
|
+
start(controller) {
|
|
791
|
+
controller.enqueue(bodyBytes);
|
|
792
|
+
controller.close();
|
|
793
|
+
}
|
|
794
|
+
}),
|
|
795
|
+
bodyUsed: false,
|
|
796
|
+
async arrayBuffer() {
|
|
797
|
+
const copy = new Uint8Array(bodyBytes.byteLength);
|
|
798
|
+
copy.set(bodyBytes);
|
|
799
|
+
return copy.buffer;
|
|
800
|
+
},
|
|
801
|
+
async text() {
|
|
802
|
+
return new TextDecoder().decode(bodyBytes);
|
|
803
|
+
},
|
|
804
|
+
async json() {
|
|
805
|
+
const text = new TextDecoder().decode(bodyBytes);
|
|
806
|
+
return JSON.parse(text);
|
|
807
|
+
},
|
|
808
|
+
async blob() {
|
|
809
|
+
const contentType = serialized.httpMetadata?.contentType || "application/octet-stream";
|
|
810
|
+
const buffer = bodyBytes.buffer.slice(bodyBytes.byteOffset, bodyBytes.byteOffset + bodyBytes.byteLength);
|
|
811
|
+
return new Blob([buffer], { type: contentType });
|
|
1165
812
|
}
|
|
1166
|
-
|
|
1167
|
-
|
|
813
|
+
};
|
|
814
|
+
return r2ObjectBody;
|
|
1168
815
|
}
|
|
1169
|
-
function
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
parsed = JSON.parse(data);
|
|
1173
|
-
} catch {
|
|
1174
|
-
return null;
|
|
1175
|
-
}
|
|
1176
|
-
if (typeof parsed !== "object" || parsed === null || !("t" in parsed))
|
|
1177
|
-
return null;
|
|
1178
|
-
const t = parsed.t;
|
|
1179
|
-
if (t === "rpc.call" || t === "rpc.ok" || t === "rpc.err") {
|
|
1180
|
-
return parsed;
|
|
816
|
+
function base64Encode(bytes) {
|
|
817
|
+
if (typeof Buffer !== "undefined") {
|
|
818
|
+
return Buffer.from(bytes).toString("base64");
|
|
1181
819
|
}
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
let parsed;
|
|
1186
|
-
try {
|
|
1187
|
-
parsed = JSON.parse(data);
|
|
1188
|
-
} catch {
|
|
1189
|
-
return null;
|
|
820
|
+
let binary = "";
|
|
821
|
+
for (let i = 0;i < bytes.byteLength; i++) {
|
|
822
|
+
binary += String.fromCharCode(bytes[i]);
|
|
1190
823
|
}
|
|
1191
|
-
|
|
1192
|
-
return null;
|
|
1193
|
-
const candidate = parsed;
|
|
1194
|
-
if (candidate.t !== "error")
|
|
1195
|
-
return null;
|
|
1196
|
-
const scope = candidate.scope;
|
|
1197
|
-
if (scope !== "transport" && scope !== "rpc" && scope !== "stream" && scope !== "ws")
|
|
1198
|
-
return null;
|
|
1199
|
-
const err = candidate.error;
|
|
1200
|
-
if (!err || typeof err.code !== "string" || typeof err.message !== "string")
|
|
1201
|
-
return null;
|
|
1202
|
-
return parsed;
|
|
824
|
+
return btoa(binary);
|
|
1203
825
|
}
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
try {
|
|
1208
|
-
const env = globalThis.process?.env;
|
|
1209
|
-
return Boolean(env?.DEVFLARE_DEBUG_BRIDGE);
|
|
1210
|
-
} catch {
|
|
1211
|
-
return false;
|
|
826
|
+
function base64Decode(str) {
|
|
827
|
+
if (typeof Buffer !== "undefined") {
|
|
828
|
+
return new Uint8Array(Buffer.from(str, "base64"));
|
|
1212
829
|
}
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
return;
|
|
1218
|
-
console.warn(`[devflare:bridge] ${message}`, error);
|
|
1219
|
-
},
|
|
1220
|
-
debug(message, error) {
|
|
1221
|
-
if (!isDebugEnabled())
|
|
1222
|
-
return;
|
|
1223
|
-
console.debug(`[devflare:bridge] ${message}`, error);
|
|
830
|
+
const binary = atob(str);
|
|
831
|
+
const bytes = new Uint8Array(binary.length);
|
|
832
|
+
for (let i = 0;i < binary.length; i++) {
|
|
833
|
+
bytes[i] = binary.charCodeAt(i);
|
|
1224
834
|
}
|
|
1225
|
-
|
|
835
|
+
return bytes;
|
|
836
|
+
}
|
|
1226
837
|
|
|
1227
838
|
// src/bridge/client.ts
|
|
1228
839
|
class BridgeWsAdapter {
|
|
@@ -1796,10 +1407,16 @@ function createR2Proxy(client, bindingName) {
|
|
|
1796
1407
|
return client.call(`${bindingName}.r2.list`, [options]);
|
|
1797
1408
|
},
|
|
1798
1409
|
async createMultipartUpload(key, options) {
|
|
1799
|
-
return client.call(`${bindingName}.r2.createMultipartUpload`, [
|
|
1410
|
+
return client.call(`${bindingName}.r2.createMultipartUpload`, [
|
|
1411
|
+
key,
|
|
1412
|
+
options
|
|
1413
|
+
]);
|
|
1800
1414
|
},
|
|
1801
1415
|
async resumeMultipartUpload(key, uploadId) {
|
|
1802
|
-
return client.call(`${bindingName}.r2.resumeMultipartUpload`, [
|
|
1416
|
+
return client.call(`${bindingName}.r2.resumeMultipartUpload`, [
|
|
1417
|
+
key,
|
|
1418
|
+
uploadId
|
|
1419
|
+
]);
|
|
1803
1420
|
}
|
|
1804
1421
|
};
|
|
1805
1422
|
}
|
|
@@ -1813,7 +1430,7 @@ function getValueSize(value) {
|
|
|
1813
1430
|
if (typeof value === "string")
|
|
1814
1431
|
return new TextEncoder().encode(value).byteLength;
|
|
1815
1432
|
if (value instanceof ReadableStream)
|
|
1816
|
-
return
|
|
1433
|
+
return Number.POSITIVE_INFINITY;
|
|
1817
1434
|
return 0;
|
|
1818
1435
|
}
|
|
1819
1436
|
function createD1Proxy(client, bindingName) {
|
|
@@ -1861,14 +1478,27 @@ function createD1StatementProxy(client, bindingName, sql, bindings) {
|
|
|
1861
1478
|
function createDOProxy(client, bindingName, proxyOptions = {}) {
|
|
1862
1479
|
return {
|
|
1863
1480
|
idFromName(name) {
|
|
1864
|
-
return createDOIdProxy(client, bindingName, {
|
|
1481
|
+
return createDOIdProxy(client, bindingName, {
|
|
1482
|
+
type: "name",
|
|
1483
|
+
value: name,
|
|
1484
|
+
jurisdiction: proxyOptions.jurisdiction
|
|
1485
|
+
});
|
|
1865
1486
|
},
|
|
1866
1487
|
idFromString(hexId) {
|
|
1867
|
-
return createDOIdProxy(client, bindingName, {
|
|
1488
|
+
return createDOIdProxy(client, bindingName, {
|
|
1489
|
+
type: "hex",
|
|
1490
|
+
value: hexId,
|
|
1491
|
+
jurisdiction: proxyOptions.jurisdiction
|
|
1492
|
+
});
|
|
1868
1493
|
},
|
|
1869
1494
|
newUniqueId(options) {
|
|
1870
1495
|
const tempId = crypto.randomUUID().replace(/-/g, "");
|
|
1871
|
-
return createDOIdProxy(client, bindingName, {
|
|
1496
|
+
return createDOIdProxy(client, bindingName, {
|
|
1497
|
+
type: "unique",
|
|
1498
|
+
value: tempId,
|
|
1499
|
+
options,
|
|
1500
|
+
jurisdiction: proxyOptions.jurisdiction
|
|
1501
|
+
});
|
|
1872
1502
|
},
|
|
1873
1503
|
get(id) {
|
|
1874
1504
|
const idProxy = id;
|
|
@@ -1904,13 +1534,19 @@ function createDOStubProxy(client, bindingName, idInfo, proxyOptions = {}) {
|
|
|
1904
1534
|
return resolvedId;
|
|
1905
1535
|
switch (idInfo.type) {
|
|
1906
1536
|
case "name":
|
|
1907
|
-
resolvedId = await client.call(`${bindingName}.do.idFromName`, [
|
|
1537
|
+
resolvedId = await client.call(`${bindingName}.do.idFromName`, [
|
|
1538
|
+
idInfo.value,
|
|
1539
|
+
idInfo.jurisdiction
|
|
1540
|
+
]);
|
|
1908
1541
|
break;
|
|
1909
1542
|
case "hex":
|
|
1910
1543
|
resolvedId = { __type: "DOId", hex: idInfo.value };
|
|
1911
1544
|
break;
|
|
1912
1545
|
case "unique":
|
|
1913
|
-
resolvedId = await client.call(`${bindingName}.do.newUniqueId`, [
|
|
1546
|
+
resolvedId = await client.call(`${bindingName}.do.newUniqueId`, [
|
|
1547
|
+
idInfo.options,
|
|
1548
|
+
idInfo.jurisdiction
|
|
1549
|
+
]);
|
|
1914
1550
|
break;
|
|
1915
1551
|
}
|
|
1916
1552
|
return resolvedId;
|
|
@@ -1987,298 +1623,677 @@ function createDOStubProxy(client, bindingName, idInfo, proxyOptions = {}) {
|
|
|
1987
1623
|
}
|
|
1988
1624
|
};
|
|
1989
1625
|
},
|
|
1990
|
-
get id() {
|
|
1991
|
-
return createDOIdProxy(client, bindingName, idInfo);
|
|
1626
|
+
get id() {
|
|
1627
|
+
return createDOIdProxy(client, bindingName, idInfo);
|
|
1628
|
+
},
|
|
1629
|
+
get name() {
|
|
1630
|
+
return idInfo.type === "name" ? idInfo.value : undefined;
|
|
1631
|
+
}
|
|
1632
|
+
};
|
|
1633
|
+
return new Proxy(stubBase, {
|
|
1634
|
+
get(target, prop) {
|
|
1635
|
+
if (prop in target) {
|
|
1636
|
+
return target[prop];
|
|
1637
|
+
}
|
|
1638
|
+
if (typeof prop === "symbol") {
|
|
1639
|
+
return;
|
|
1640
|
+
}
|
|
1641
|
+
if (prop === "then" || prop === "catch" || prop === "finally") {
|
|
1642
|
+
return;
|
|
1643
|
+
}
|
|
1644
|
+
return async (...args) => {
|
|
1645
|
+
const id = await resolveId();
|
|
1646
|
+
let result = await client.call(`${bindingName}.do.rpc`, [bindingName, id, prop, args]);
|
|
1647
|
+
if (transformResult) {
|
|
1648
|
+
result = transformResult(result);
|
|
1649
|
+
}
|
|
1650
|
+
return result;
|
|
1651
|
+
};
|
|
1652
|
+
}
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1655
|
+
function isResponseLike(value) {
|
|
1656
|
+
return value instanceof Response;
|
|
1657
|
+
}
|
|
1658
|
+
function createServiceProxy(client, bindingName, proxyOptions = {}) {
|
|
1659
|
+
const { transformResult } = proxyOptions;
|
|
1660
|
+
const serviceBase = {
|
|
1661
|
+
async fetch(input, init) {
|
|
1662
|
+
const request = input instanceof Request ? input : new Request(input, init);
|
|
1663
|
+
const { serialized } = await serializeRequest(request);
|
|
1664
|
+
const result = await client.call(`${bindingName}.service.fetch`, [serialized]);
|
|
1665
|
+
if (isResponseLike(result)) {
|
|
1666
|
+
return result;
|
|
1667
|
+
}
|
|
1668
|
+
return deserializeResponse(result);
|
|
1669
|
+
}
|
|
1670
|
+
};
|
|
1671
|
+
return new Proxy(serviceBase, {
|
|
1672
|
+
get(target, prop) {
|
|
1673
|
+
if (typeof prop !== "string") {
|
|
1674
|
+
return;
|
|
1675
|
+
}
|
|
1676
|
+
if (prop in target) {
|
|
1677
|
+
return target[prop];
|
|
1678
|
+
}
|
|
1679
|
+
if (prop === "then" || prop === "catch" || prop === "finally") {
|
|
1680
|
+
return;
|
|
1681
|
+
}
|
|
1682
|
+
if (prop === "toString") {
|
|
1683
|
+
return () => `[DevflareServiceBinding ${bindingName}]`;
|
|
1684
|
+
}
|
|
1685
|
+
return async (...args) => {
|
|
1686
|
+
let result = await client.call(`${bindingName}.service.rpc`, [prop, args]);
|
|
1687
|
+
if (transformResult) {
|
|
1688
|
+
result = transformResult(result);
|
|
1689
|
+
}
|
|
1690
|
+
return result;
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
});
|
|
1694
|
+
}
|
|
1695
|
+
var EMPTY_QUEUE_METRICS = {
|
|
1696
|
+
backlogCount: 0,
|
|
1697
|
+
backlogBytes: 0
|
|
1698
|
+
};
|
|
1699
|
+
function createQueueResponse() {
|
|
1700
|
+
return { metadata: { metrics: EMPTY_QUEUE_METRICS } };
|
|
1701
|
+
}
|
|
1702
|
+
function createQueueProxy(client, bindingName) {
|
|
1703
|
+
return {
|
|
1704
|
+
async metrics() {
|
|
1705
|
+
return EMPTY_QUEUE_METRICS;
|
|
1706
|
+
},
|
|
1707
|
+
async send(message, options) {
|
|
1708
|
+
await client.call(`${bindingName}.queue.send`, [message, options]);
|
|
1709
|
+
return createQueueResponse();
|
|
1710
|
+
},
|
|
1711
|
+
async sendBatch(messages, options) {
|
|
1712
|
+
await client.call(`${bindingName}.queue.sendBatch`, [messages, options]);
|
|
1713
|
+
return createQueueResponse();
|
|
1714
|
+
}
|
|
1715
|
+
};
|
|
1716
|
+
}
|
|
1717
|
+
function createAIProxy(client, bindingName) {
|
|
1718
|
+
return {
|
|
1719
|
+
async run(model, inputs, options) {
|
|
1720
|
+
return client.call(`${bindingName}.ai.run`, [model, inputs, options]);
|
|
1721
|
+
}
|
|
1722
|
+
};
|
|
1723
|
+
}
|
|
1724
|
+
function createSendEmailProxy(client, bindingName) {
|
|
1725
|
+
return {
|
|
1726
|
+
async send(message) {
|
|
1727
|
+
return client.call(`${bindingName}.email.send`, [message]);
|
|
1728
|
+
}
|
|
1729
|
+
};
|
|
1730
|
+
}
|
|
1731
|
+
function createWorkflowInstanceProxy(client, bindingName, id) {
|
|
1732
|
+
return {
|
|
1733
|
+
id,
|
|
1734
|
+
async pause() {
|
|
1735
|
+
await client.call(`${bindingName}.workflow.pause`, [id]);
|
|
1992
1736
|
},
|
|
1993
|
-
|
|
1994
|
-
|
|
1737
|
+
async resume() {
|
|
1738
|
+
await client.call(`${bindingName}.workflow.resume`, [id]);
|
|
1739
|
+
},
|
|
1740
|
+
async terminate() {
|
|
1741
|
+
await client.call(`${bindingName}.workflow.terminate`, [id]);
|
|
1742
|
+
},
|
|
1743
|
+
async restart() {
|
|
1744
|
+
await client.call(`${bindingName}.workflow.restart`, [id]);
|
|
1745
|
+
},
|
|
1746
|
+
async status() {
|
|
1747
|
+
return client.call(`${bindingName}.workflow.status`, [id]);
|
|
1748
|
+
},
|
|
1749
|
+
async sendEvent(event) {
|
|
1750
|
+
await client.call(`${bindingName}.workflow.sendEvent`, [id, event]);
|
|
1995
1751
|
}
|
|
1996
1752
|
};
|
|
1997
|
-
|
|
1753
|
+
}
|
|
1754
|
+
function createWorkflowProxy(client, bindingName) {
|
|
1755
|
+
const toInstance = (value) => {
|
|
1756
|
+
const id = value?.id;
|
|
1757
|
+
if (typeof id !== "string") {
|
|
1758
|
+
throw new Error(`Workflow ${bindingName} returned an instance without a string id.`);
|
|
1759
|
+
}
|
|
1760
|
+
return createWorkflowInstanceProxy(client, bindingName, id);
|
|
1761
|
+
};
|
|
1762
|
+
return {
|
|
1763
|
+
async create(options) {
|
|
1764
|
+
return toInstance(await client.call(`${bindingName}.workflow.create`, [options]));
|
|
1765
|
+
},
|
|
1766
|
+
async get(id) {
|
|
1767
|
+
return toInstance(await client.call(`${bindingName}.workflow.get`, [id]));
|
|
1768
|
+
}
|
|
1769
|
+
};
|
|
1770
|
+
}
|
|
1771
|
+
var globalBindingHints = {};
|
|
1772
|
+
function createEnvProxy(options = {}) {
|
|
1773
|
+
const client = options.client ?? getClient();
|
|
1774
|
+
const bindingProxies = new Map;
|
|
1775
|
+
const doProxyOptions = { transformResult: options.transformResult };
|
|
1776
|
+
const serviceProxyOptions = { transformResult: options.transformResult };
|
|
1777
|
+
const strict = options.strict === true;
|
|
1778
|
+
const hints = { ...globalBindingHints, ...options.hints };
|
|
1779
|
+
return new Proxy({}, {
|
|
1998
1780
|
get(target, prop) {
|
|
1999
|
-
if (prop
|
|
2000
|
-
return
|
|
1781
|
+
if (typeof prop !== "string")
|
|
1782
|
+
return;
|
|
1783
|
+
if (bindingProxies.has(prop)) {
|
|
1784
|
+
return bindingProxies.get(prop);
|
|
2001
1785
|
}
|
|
2002
|
-
|
|
1786
|
+
const hint = hints[prop];
|
|
1787
|
+
if (!hint && strict) {
|
|
2003
1788
|
return;
|
|
2004
1789
|
}
|
|
2005
|
-
|
|
1790
|
+
let proxy;
|
|
1791
|
+
switch (hint) {
|
|
1792
|
+
case "kv":
|
|
1793
|
+
proxy = createKVProxy(client, prop);
|
|
1794
|
+
break;
|
|
1795
|
+
case "r2":
|
|
1796
|
+
proxy = createR2Proxy(client, prop);
|
|
1797
|
+
break;
|
|
1798
|
+
case "d1":
|
|
1799
|
+
proxy = createD1Proxy(client, prop);
|
|
1800
|
+
break;
|
|
1801
|
+
case "do":
|
|
1802
|
+
proxy = createDOProxy(client, prop, doProxyOptions);
|
|
1803
|
+
break;
|
|
1804
|
+
case "queue":
|
|
1805
|
+
proxy = createQueueProxy(client, prop);
|
|
1806
|
+
break;
|
|
1807
|
+
case "ai":
|
|
1808
|
+
proxy = createAIProxy(client, prop);
|
|
1809
|
+
break;
|
|
1810
|
+
case "service":
|
|
1811
|
+
proxy = createServiceProxy(client, prop, serviceProxyOptions);
|
|
1812
|
+
break;
|
|
1813
|
+
case "sendEmail":
|
|
1814
|
+
proxy = createSendEmailProxy(client, prop);
|
|
1815
|
+
break;
|
|
1816
|
+
case "workflow":
|
|
1817
|
+
proxy = createWorkflowProxy(client, prop);
|
|
1818
|
+
break;
|
|
1819
|
+
case "secret":
|
|
1820
|
+
case "var":
|
|
1821
|
+
proxy = createSimpleBindingProxy(client, prop);
|
|
1822
|
+
break;
|
|
1823
|
+
default:
|
|
1824
|
+
proxy = createGenericBindingProxy(client, prop);
|
|
1825
|
+
}
|
|
1826
|
+
bindingProxies.set(prop, proxy);
|
|
1827
|
+
return proxy;
|
|
1828
|
+
},
|
|
1829
|
+
has(target, prop) {
|
|
1830
|
+
return typeof prop === "string" && (!strict || (prop in hints));
|
|
1831
|
+
},
|
|
1832
|
+
ownKeys() {
|
|
1833
|
+
return Object.keys(hints);
|
|
1834
|
+
},
|
|
1835
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
1836
|
+
if (typeof prop === "string" && (!strict || (prop in hints))) {
|
|
1837
|
+
return { configurable: true, enumerable: true, writable: false };
|
|
1838
|
+
}
|
|
1839
|
+
return;
|
|
1840
|
+
}
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
function createGenericBindingProxy(client, bindingName) {
|
|
1844
|
+
return new Proxy({}, {
|
|
1845
|
+
get(target, prop) {
|
|
1846
|
+
if (typeof prop !== "string")
|
|
2006
1847
|
return;
|
|
1848
|
+
if (["get", "put", "delete", "list", "getWithMetadata"].includes(prop)) {
|
|
1849
|
+
return createKVProxy(client, bindingName)[prop];
|
|
1850
|
+
}
|
|
1851
|
+
if (["idFromName", "idFromString", "newUniqueId", "get"].includes(prop)) {
|
|
1852
|
+
return createDOProxy(client, bindingName)[prop];
|
|
1853
|
+
}
|
|
1854
|
+
if (["prepare", "batch", "exec", "dump"].includes(prop)) {
|
|
1855
|
+
return createD1Proxy(client, bindingName)[prop];
|
|
1856
|
+
}
|
|
1857
|
+
if (["head"].includes(prop)) {
|
|
1858
|
+
return createR2Proxy(client, bindingName)[prop];
|
|
2007
1859
|
}
|
|
2008
1860
|
return async (...args) => {
|
|
2009
|
-
|
|
2010
|
-
let result = await client.call(`${bindingName}.do.rpc`, [
|
|
2011
|
-
bindingName,
|
|
2012
|
-
id,
|
|
2013
|
-
prop,
|
|
2014
|
-
args
|
|
2015
|
-
]);
|
|
2016
|
-
if (transformResult) {
|
|
2017
|
-
result = transformResult(result);
|
|
2018
|
-
}
|
|
2019
|
-
return result;
|
|
1861
|
+
return client.call(`${bindingName}.${prop}`, args);
|
|
2020
1862
|
};
|
|
2021
1863
|
}
|
|
2022
1864
|
});
|
|
2023
1865
|
}
|
|
2024
|
-
function
|
|
2025
|
-
|
|
1866
|
+
function createSimpleBindingProxy(client, bindingName) {
|
|
1867
|
+
let cachedValue;
|
|
1868
|
+
let fetched = false;
|
|
1869
|
+
let pendingValue = null;
|
|
1870
|
+
const loadValue = () => {
|
|
1871
|
+
if (fetched) {
|
|
1872
|
+
return Promise.resolve(cachedValue);
|
|
1873
|
+
}
|
|
1874
|
+
if (!pendingValue) {
|
|
1875
|
+
pendingValue = client.call(`${bindingName}.var.value`, []).then((value) => {
|
|
1876
|
+
cachedValue = value;
|
|
1877
|
+
fetched = true;
|
|
1878
|
+
return value;
|
|
1879
|
+
}).catch((error) => {
|
|
1880
|
+
pendingValue = null;
|
|
1881
|
+
throw error;
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
return pendingValue;
|
|
1885
|
+
};
|
|
1886
|
+
return {
|
|
1887
|
+
then(resolve, reject) {
|
|
1888
|
+
return loadValue().then(resolve ?? undefined, reject ?? undefined);
|
|
1889
|
+
},
|
|
1890
|
+
toString() {
|
|
1891
|
+
if (!fetched)
|
|
1892
|
+
throw new Error(`Binding ${bindingName} not yet fetched. Use await.`);
|
|
1893
|
+
return String(cachedValue);
|
|
1894
|
+
}
|
|
1895
|
+
};
|
|
2026
1896
|
}
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
const { serialized } = await serializeRequest(request);
|
|
2033
|
-
const result = await client.call(`${bindingName}.service.fetch`, [serialized]);
|
|
2034
|
-
if (isResponseLike(result)) {
|
|
2035
|
-
return result;
|
|
2036
|
-
}
|
|
2037
|
-
return deserializeResponse(result);
|
|
1897
|
+
var globalEnvProxy = null;
|
|
1898
|
+
var bridgeEnv = new Proxy({}, {
|
|
1899
|
+
get(target, prop) {
|
|
1900
|
+
if (!globalEnvProxy) {
|
|
1901
|
+
globalEnvProxy = createEnvProxy({ lazy: true });
|
|
2038
1902
|
}
|
|
1903
|
+
return globalEnvProxy[prop];
|
|
1904
|
+
}
|
|
1905
|
+
});
|
|
1906
|
+
function initEnv(options = {}) {
|
|
1907
|
+
globalEnvProxy = createEnvProxy(options);
|
|
1908
|
+
return globalEnvProxy;
|
|
1909
|
+
}
|
|
1910
|
+
function setBindingHints(hints) {
|
|
1911
|
+
globalBindingHints = { ...globalBindingHints, ...hints };
|
|
1912
|
+
globalEnvProxy = null;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
// src/runtime/context-events.ts
|
|
1916
|
+
function createLocals(locals) {
|
|
1917
|
+
return locals ?? {};
|
|
1918
|
+
}
|
|
1919
|
+
function prepareEventShell(env, options = {}) {
|
|
1920
|
+
return {
|
|
1921
|
+
env: wrapEnvSendEmailBindings(env),
|
|
1922
|
+
locals: createLocals(options.locals)
|
|
2039
1923
|
};
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
return target[prop];
|
|
2047
|
-
}
|
|
2048
|
-
if (prop === "then" || prop === "catch" || prop === "finally") {
|
|
2049
|
-
return;
|
|
1924
|
+
}
|
|
1925
|
+
function createAugmentedTarget(target, extra) {
|
|
1926
|
+
return new Proxy(target, {
|
|
1927
|
+
get(target2, prop) {
|
|
1928
|
+
if (prop in extra) {
|
|
1929
|
+
return extra[prop];
|
|
2050
1930
|
}
|
|
2051
|
-
|
|
2052
|
-
|
|
1931
|
+
const value = Reflect.get(target2, prop, target2);
|
|
1932
|
+
return typeof value === "function" ? value.bind(target2) : value;
|
|
1933
|
+
},
|
|
1934
|
+
has(target2, prop) {
|
|
1935
|
+
return prop in extra || prop in target2;
|
|
1936
|
+
},
|
|
1937
|
+
ownKeys(target2) {
|
|
1938
|
+
return Array.from(new Set([...Reflect.ownKeys(target2), ...Reflect.ownKeys(extra)]));
|
|
1939
|
+
},
|
|
1940
|
+
getOwnPropertyDescriptor(target2, prop) {
|
|
1941
|
+
if (prop in extra) {
|
|
1942
|
+
return {
|
|
1943
|
+
configurable: true,
|
|
1944
|
+
enumerable: true,
|
|
1945
|
+
writable: false,
|
|
1946
|
+
value: extra[prop]
|
|
1947
|
+
};
|
|
2053
1948
|
}
|
|
2054
|
-
return
|
|
2055
|
-
let result = await client.call(`${bindingName}.service.rpc`, [prop, args]);
|
|
2056
|
-
if (transformResult) {
|
|
2057
|
-
result = transformResult(result);
|
|
2058
|
-
}
|
|
2059
|
-
return result;
|
|
2060
|
-
};
|
|
1949
|
+
return Reflect.getOwnPropertyDescriptor(target2, prop);
|
|
2061
1950
|
}
|
|
2062
1951
|
});
|
|
2063
1952
|
}
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
backlogBytes: 0
|
|
2067
|
-
};
|
|
2068
|
-
function createQueueResponse() {
|
|
2069
|
-
return { metadata: { metrics: EMPTY_QUEUE_METRICS } };
|
|
2070
|
-
}
|
|
2071
|
-
function createQueueProxy(client, bindingName) {
|
|
1953
|
+
function createBaseEvent(type, env, ctx, options = {}) {
|
|
1954
|
+
const shell = prepareEventShell(env, { locals: options.locals });
|
|
2072
1955
|
return {
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
return createQueueResponse();
|
|
2079
|
-
},
|
|
2080
|
-
async sendBatch(messages, options) {
|
|
2081
|
-
await client.call(`${bindingName}.queue.sendBatch`, [messages, options]);
|
|
2082
|
-
return createQueueResponse();
|
|
2083
|
-
}
|
|
1956
|
+
type,
|
|
1957
|
+
ctx,
|
|
1958
|
+
...shell,
|
|
1959
|
+
request: options.request ?? null,
|
|
1960
|
+
params: options.params
|
|
2084
1961
|
};
|
|
2085
1962
|
}
|
|
2086
|
-
function
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
1963
|
+
function createFetchEvent(request, env, ctx, options = {}) {
|
|
1964
|
+
const shell = prepareEventShell(env, { locals: options.locals });
|
|
1965
|
+
return createAugmentedTarget(request, {
|
|
1966
|
+
type: "fetch",
|
|
1967
|
+
ctx,
|
|
1968
|
+
...shell,
|
|
1969
|
+
url: new URL(request.url),
|
|
1970
|
+
request,
|
|
1971
|
+
params: options.params ?? {}
|
|
1972
|
+
});
|
|
2092
1973
|
}
|
|
2093
|
-
function
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
1974
|
+
function createQueueEvent(batch, env, ctx, options = {}) {
|
|
1975
|
+
const shell = prepareEventShell(env, { locals: options.locals });
|
|
1976
|
+
return createAugmentedTarget(batch, {
|
|
1977
|
+
type: "queue",
|
|
1978
|
+
ctx,
|
|
1979
|
+
...shell,
|
|
1980
|
+
batch
|
|
1981
|
+
});
|
|
2099
1982
|
}
|
|
2100
|
-
function
|
|
1983
|
+
function createScheduledEvent(controller, env, ctx, options = {}) {
|
|
1984
|
+
const shell = prepareEventShell(env, { locals: options.locals });
|
|
1985
|
+
return createAugmentedTarget(controller, {
|
|
1986
|
+
type: "scheduled",
|
|
1987
|
+
ctx,
|
|
1988
|
+
...shell,
|
|
1989
|
+
controller
|
|
1990
|
+
});
|
|
1991
|
+
}
|
|
1992
|
+
function createEmailEvent(message, env, ctx, options = {}) {
|
|
1993
|
+
const shell = prepareEventShell(env, { locals: options.locals });
|
|
1994
|
+
return createAugmentedTarget(message, {
|
|
1995
|
+
type: "email",
|
|
1996
|
+
ctx,
|
|
1997
|
+
...shell,
|
|
1998
|
+
message
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
function createTailEvent(events, env, ctx, options = {}) {
|
|
2002
|
+
const shell = prepareEventShell(env, { locals: options.locals });
|
|
2003
|
+
return createAugmentedTarget(events, {
|
|
2004
|
+
type: "tail",
|
|
2005
|
+
ctx,
|
|
2006
|
+
...shell,
|
|
2007
|
+
events
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
function createDurableObjectFetchEvent(request, env, state, options = {}) {
|
|
2011
|
+
const shell = prepareEventShell(env, { locals: options.locals });
|
|
2012
|
+
return createAugmentedTarget(request, {
|
|
2013
|
+
type: "durable-object-fetch",
|
|
2014
|
+
ctx: state,
|
|
2015
|
+
state,
|
|
2016
|
+
...shell,
|
|
2017
|
+
request
|
|
2018
|
+
});
|
|
2019
|
+
}
|
|
2020
|
+
function createDurableObjectAlarmEvent(env, state, options = {}) {
|
|
2021
|
+
const shell = prepareEventShell(env, { locals: options.locals });
|
|
2101
2022
|
return {
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
async resume() {
|
|
2107
|
-
await client.call(`${bindingName}.workflow.resume`, [id]);
|
|
2108
|
-
},
|
|
2109
|
-
async terminate() {
|
|
2110
|
-
await client.call(`${bindingName}.workflow.terminate`, [id]);
|
|
2111
|
-
},
|
|
2112
|
-
async restart() {
|
|
2113
|
-
await client.call(`${bindingName}.workflow.restart`, [id]);
|
|
2114
|
-
},
|
|
2115
|
-
async status() {
|
|
2116
|
-
return client.call(`${bindingName}.workflow.status`, [id]);
|
|
2117
|
-
},
|
|
2118
|
-
async sendEvent(event) {
|
|
2119
|
-
await client.call(`${bindingName}.workflow.sendEvent`, [id, event]);
|
|
2120
|
-
}
|
|
2023
|
+
type: "durable-object-alarm",
|
|
2024
|
+
ctx: state,
|
|
2025
|
+
state,
|
|
2026
|
+
...shell
|
|
2121
2027
|
};
|
|
2122
2028
|
}
|
|
2123
|
-
function
|
|
2124
|
-
const
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2029
|
+
function createDurableObjectWebSocketMessageEvent(ws, message, env, state, options = {}) {
|
|
2030
|
+
const shell = prepareEventShell(env, { locals: options.locals });
|
|
2031
|
+
return createAugmentedTarget(ws, {
|
|
2032
|
+
type: "durable-object-websocket-message",
|
|
2033
|
+
ctx: state,
|
|
2034
|
+
state,
|
|
2035
|
+
...shell,
|
|
2036
|
+
ws,
|
|
2037
|
+
message
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2040
|
+
function createDurableObjectWebSocketCloseEvent(ws, code, reason, wasClean, env, state, options = {}) {
|
|
2041
|
+
const shell = prepareEventShell(env, { locals: options.locals });
|
|
2042
|
+
return createAugmentedTarget(ws, {
|
|
2043
|
+
type: "durable-object-websocket-close",
|
|
2044
|
+
ctx: state,
|
|
2045
|
+
state,
|
|
2046
|
+
...shell,
|
|
2047
|
+
ws,
|
|
2048
|
+
code,
|
|
2049
|
+
reason,
|
|
2050
|
+
wasClean
|
|
2051
|
+
});
|
|
2052
|
+
}
|
|
2053
|
+
function createDurableObjectWebSocketErrorEvent(ws, error, env, state, options = {}) {
|
|
2054
|
+
const shell = prepareEventShell(env, { locals: options.locals });
|
|
2055
|
+
return createAugmentedTarget(ws, {
|
|
2056
|
+
type: "durable-object-websocket-error",
|
|
2057
|
+
ctx: state,
|
|
2058
|
+
state,
|
|
2059
|
+
...shell,
|
|
2060
|
+
ws,
|
|
2061
|
+
error
|
|
2062
|
+
});
|
|
2063
|
+
}
|
|
2064
|
+
function createDefaultEvent(env, ctx, request, type, locals) {
|
|
2065
|
+
switch (type) {
|
|
2066
|
+
case "fetch": {
|
|
2067
|
+
if (request && ctx) {
|
|
2068
|
+
return createFetchEvent(request, env, ctx, { locals });
|
|
2069
|
+
}
|
|
2070
|
+
return createBaseEvent(type, env, ctx, { locals, request });
|
|
2128
2071
|
}
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
return
|
|
2134
|
-
},
|
|
2135
|
-
async get(id) {
|
|
2136
|
-
return toInstance(await client.call(`${bindingName}.workflow.get`, [id]));
|
|
2072
|
+
case "durable-object-fetch": {
|
|
2073
|
+
if (request && ctx) {
|
|
2074
|
+
return createDurableObjectFetchEvent(request, env, ctx, { locals });
|
|
2075
|
+
}
|
|
2076
|
+
return createBaseEvent(type, env, ctx, { locals, request });
|
|
2137
2077
|
}
|
|
2138
|
-
|
|
2078
|
+
case "durable-object-alarm": {
|
|
2079
|
+
if (ctx) {
|
|
2080
|
+
return createDurableObjectAlarmEvent(env, ctx, { locals });
|
|
2081
|
+
}
|
|
2082
|
+
return createBaseEvent(type, env, ctx, { locals });
|
|
2083
|
+
}
|
|
2084
|
+
case "queue":
|
|
2085
|
+
case "scheduled":
|
|
2086
|
+
case "email":
|
|
2087
|
+
case "tail":
|
|
2088
|
+
case "durable-object-websocket-message":
|
|
2089
|
+
case "durable-object-websocket-close":
|
|
2090
|
+
case "durable-object-websocket-error":
|
|
2091
|
+
return createBaseEvent(type, env, ctx, { locals, request });
|
|
2092
|
+
default: {
|
|
2093
|
+
const exhaustive = type;
|
|
2094
|
+
throw new Error(`createDefaultEvent: unknown event type ${String(exhaustive)}`);
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2139
2097
|
}
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2098
|
+
|
|
2099
|
+
// src/runtime/validation.ts
|
|
2100
|
+
class ContextAccessError extends Error {
|
|
2101
|
+
contextName;
|
|
2102
|
+
propertyName;
|
|
2103
|
+
constructor(contextName, propertyName, message) {
|
|
2104
|
+
super(message ?? `Cannot access ${contextName}.${propertyName} outside of an active Devflare handler trail.
|
|
2105
|
+
|
|
2106
|
+
` + `This typically happens when:
|
|
2107
|
+
` + ` 1. Accessing ${contextName} at module top-level (during import)
|
|
2108
|
+
` + ` 2. Accessing ${contextName} in a callback that runs after the handler ends
|
|
2109
|
+
` + ` 3. Accessing ${contextName} in a setTimeout/setInterval callback
|
|
2110
|
+
|
|
2111
|
+
` + `Move the access inside your handler function or middleware.`);
|
|
2112
|
+
this.name = "ContextAccessError";
|
|
2113
|
+
this.contextName = contextName;
|
|
2114
|
+
this.propertyName = propertyName;
|
|
2115
|
+
}
|
|
2116
|
+
static contextUnavailable(message) {
|
|
2117
|
+
return new ContextAccessError("context", "<unavailable>", message ?? `Context not available. Devflare uses AsyncLocalStorage to carry the active event through fetch, queue, scheduled, email, tail, and Durable Object handler call chains.
|
|
2118
|
+
|
|
2119
|
+
` + `This usually means one of:
|
|
2120
|
+
|
|
2121
|
+
` + `1. Accessing context at module top-level (runs at cold start, not per-request)
|
|
2122
|
+
` + `2. Accessing context in setTimeout/setInterval callbacks
|
|
2123
|
+
` + `3. Missing 'nodejs_compat' compatibility flag in your worker config
|
|
2124
|
+
|
|
2125
|
+
` + `Fix: Move the access inside your handler, middleware, or a helper called from that handler trail.
|
|
2126
|
+
` + `Learn more: https://devflare.dev/docs/context-errors`);
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
function createContextProxy(getter, name, options = {}) {
|
|
2130
|
+
const mutable = options.mutable ?? true;
|
|
2131
|
+
return new Proxy({}, {
|
|
2132
|
+
get(_target, prop) {
|
|
2133
|
+
const ctx = getter();
|
|
2134
|
+
if (ctx === undefined || ctx === null) {
|
|
2135
|
+
throw new ContextAccessError(name, String(prop));
|
|
2154
2136
|
}
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2137
|
+
return ctx[prop];
|
|
2138
|
+
},
|
|
2139
|
+
set(_target, prop, value) {
|
|
2140
|
+
if (!mutable) {
|
|
2141
|
+
throw new TypeError(`Cannot assign to '${String(prop)}' on '${name}' because it is read-only.
|
|
2142
|
+
` + `Use 'locals' for mutable request-scoped data.`);
|
|
2158
2143
|
}
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
proxy = createKVProxy(client, prop);
|
|
2163
|
-
break;
|
|
2164
|
-
case "r2":
|
|
2165
|
-
proxy = createR2Proxy(client, prop);
|
|
2166
|
-
break;
|
|
2167
|
-
case "d1":
|
|
2168
|
-
proxy = createD1Proxy(client, prop);
|
|
2169
|
-
break;
|
|
2170
|
-
case "do":
|
|
2171
|
-
proxy = createDOProxy(client, prop, doProxyOptions);
|
|
2172
|
-
break;
|
|
2173
|
-
case "queue":
|
|
2174
|
-
proxy = createQueueProxy(client, prop);
|
|
2175
|
-
break;
|
|
2176
|
-
case "ai":
|
|
2177
|
-
proxy = createAIProxy(client, prop);
|
|
2178
|
-
break;
|
|
2179
|
-
case "service":
|
|
2180
|
-
proxy = createServiceProxy(client, prop, serviceProxyOptions);
|
|
2181
|
-
break;
|
|
2182
|
-
case "sendEmail":
|
|
2183
|
-
proxy = createSendEmailProxy(client, prop);
|
|
2184
|
-
break;
|
|
2185
|
-
case "workflow":
|
|
2186
|
-
proxy = createWorkflowProxy(client, prop);
|
|
2187
|
-
break;
|
|
2188
|
-
case "secret":
|
|
2189
|
-
case "var":
|
|
2190
|
-
proxy = createSimpleBindingProxy(client, prop);
|
|
2191
|
-
break;
|
|
2192
|
-
default:
|
|
2193
|
-
proxy = createGenericBindingProxy(client, prop);
|
|
2144
|
+
const ctx = getter();
|
|
2145
|
+
if (ctx === undefined || ctx === null) {
|
|
2146
|
+
throw new ContextAccessError(name, String(prop));
|
|
2194
2147
|
}
|
|
2195
|
-
|
|
2196
|
-
return
|
|
2148
|
+
ctx[prop] = value;
|
|
2149
|
+
return true;
|
|
2197
2150
|
},
|
|
2198
|
-
|
|
2199
|
-
|
|
2151
|
+
deleteProperty(_target, prop) {
|
|
2152
|
+
if (!mutable) {
|
|
2153
|
+
throw new TypeError(`Cannot delete property '${String(prop)}' from '${name}' because it is read-only.`);
|
|
2154
|
+
}
|
|
2155
|
+
const ctx = getter();
|
|
2156
|
+
if (ctx === undefined || ctx === null) {
|
|
2157
|
+
return true;
|
|
2158
|
+
}
|
|
2159
|
+
return Reflect.deleteProperty(ctx, prop);
|
|
2200
2160
|
},
|
|
2201
|
-
|
|
2202
|
-
|
|
2161
|
+
has(_target, prop) {
|
|
2162
|
+
const ctx = getter();
|
|
2163
|
+
if (ctx === undefined || ctx === null) {
|
|
2164
|
+
return false;
|
|
2165
|
+
}
|
|
2166
|
+
return prop in ctx;
|
|
2203
2167
|
},
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2168
|
+
ownKeys(_target) {
|
|
2169
|
+
const ctx = getter();
|
|
2170
|
+
if (ctx === undefined || ctx === null) {
|
|
2171
|
+
return [];
|
|
2207
2172
|
}
|
|
2208
|
-
return;
|
|
2209
|
-
}
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
return new Proxy({}, {
|
|
2214
|
-
get(target, prop) {
|
|
2215
|
-
if (typeof prop !== "string")
|
|
2173
|
+
return Reflect.ownKeys(ctx);
|
|
2174
|
+
},
|
|
2175
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
2176
|
+
const ctx = getter();
|
|
2177
|
+
if (ctx === undefined || ctx === null) {
|
|
2216
2178
|
return;
|
|
2217
|
-
if (["get", "put", "delete", "list", "getWithMetadata"].includes(prop)) {
|
|
2218
|
-
return createKVProxy(client, bindingName)[prop];
|
|
2219
|
-
}
|
|
2220
|
-
if (["idFromName", "idFromString", "newUniqueId", "get"].includes(prop)) {
|
|
2221
|
-
return createDOProxy(client, bindingName)[prop];
|
|
2222
2179
|
}
|
|
2223
|
-
|
|
2224
|
-
|
|
2180
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(ctx, prop);
|
|
2181
|
+
if (!descriptor) {
|
|
2182
|
+
return;
|
|
2225
2183
|
}
|
|
2226
|
-
if (
|
|
2227
|
-
return
|
|
2184
|
+
if (!mutable) {
|
|
2185
|
+
return { ...descriptor, writable: false };
|
|
2228
2186
|
}
|
|
2229
|
-
return
|
|
2230
|
-
return client.call(`${bindingName}.${prop}`, args);
|
|
2231
|
-
};
|
|
2187
|
+
return descriptor;
|
|
2232
2188
|
}
|
|
2233
2189
|
});
|
|
2234
2190
|
}
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2191
|
+
|
|
2192
|
+
// src/runtime/context.ts
|
|
2193
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2194
|
+
var storage = new AsyncLocalStorage;
|
|
2195
|
+
function createLocals2() {
|
|
2196
|
+
return {};
|
|
2197
|
+
}
|
|
2198
|
+
function runWithContext(env, ctx, request, fn, type = "fetch") {
|
|
2199
|
+
const locals = createLocals2();
|
|
2200
|
+
const event = createDefaultEvent(env, ctx, request, type, locals);
|
|
2201
|
+
return runWithEventContext(event, fn);
|
|
2202
|
+
}
|
|
2203
|
+
function runWithEventContext(event, fn) {
|
|
2204
|
+
const context = {
|
|
2205
|
+
env: event.env,
|
|
2206
|
+
ctx: event.ctx,
|
|
2207
|
+
request: event.request ?? null,
|
|
2208
|
+
locals: event.locals,
|
|
2209
|
+
type: event.type,
|
|
2210
|
+
event
|
|
2211
|
+
};
|
|
2212
|
+
return storage.run(context, fn);
|
|
2213
|
+
}
|
|
2214
|
+
function getContext() {
|
|
2215
|
+
const context = storage.getStore();
|
|
2216
|
+
if (!context) {
|
|
2217
|
+
throw ContextAccessError.contextUnavailable();
|
|
2218
|
+
}
|
|
2219
|
+
return context;
|
|
2220
|
+
}
|
|
2221
|
+
function getContextOrNull() {
|
|
2222
|
+
const context = storage.getStore();
|
|
2223
|
+
return context ?? null;
|
|
2224
|
+
}
|
|
2225
|
+
function getEventContext() {
|
|
2226
|
+
return getContext().event;
|
|
2227
|
+
}
|
|
2228
|
+
function getEventContextOrNull() {
|
|
2229
|
+
return getContextOrNull()?.event ?? null;
|
|
2230
|
+
}
|
|
2231
|
+
function hasContext() {
|
|
2232
|
+
return storage.getStore() !== undefined;
|
|
2233
|
+
}
|
|
2234
|
+
function createEventAccessor(name, matcher) {
|
|
2235
|
+
const accessor = () => {
|
|
2236
|
+
const currentEvent = getEventContextOrNull();
|
|
2237
|
+
if (!currentEvent) {
|
|
2238
|
+
throw ContextAccessError.contextUnavailable();
|
|
2242
2239
|
}
|
|
2243
|
-
if (!
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
}).catch((error) => {
|
|
2249
|
-
pendingValue = null;
|
|
2250
|
-
throw error;
|
|
2251
|
-
});
|
|
2240
|
+
if (!matcher(currentEvent)) {
|
|
2241
|
+
throw ContextAccessError.contextUnavailable(`${name} is not available in the current '${currentEvent.type}' context.
|
|
2242
|
+
|
|
2243
|
+
Devflare stores event objects in AsyncLocalStorage so helpers called within a handler can reach the active event.
|
|
2244
|
+
Use ${name}.safe() to return null instead of throwing, or call the getter that matches the active surface.`);
|
|
2252
2245
|
}
|
|
2253
|
-
return
|
|
2246
|
+
return currentEvent;
|
|
2254
2247
|
};
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
},
|
|
2259
|
-
toString() {
|
|
2260
|
-
if (!fetched)
|
|
2261
|
-
throw new Error(`Binding ${bindingName} not yet fetched. Use await.`);
|
|
2262
|
-
return String(cachedValue);
|
|
2263
|
-
}
|
|
2248
|
+
accessor.safe = () => {
|
|
2249
|
+
const currentEvent = getEventContextOrNull();
|
|
2250
|
+
return currentEvent && matcher(currentEvent) ? currentEvent : null;
|
|
2264
2251
|
};
|
|
2252
|
+
return accessor;
|
|
2265
2253
|
}
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
get(target, prop) {
|
|
2269
|
-
if (!globalEnvProxy) {
|
|
2270
|
-
globalEnvProxy = createEnvProxy({ lazy: true });
|
|
2271
|
-
}
|
|
2272
|
-
return globalEnvProxy[prop];
|
|
2273
|
-
}
|
|
2274
|
-
});
|
|
2275
|
-
function initEnv(options = {}) {
|
|
2276
|
-
globalEnvProxy = createEnvProxy(options);
|
|
2277
|
-
return globalEnvProxy;
|
|
2254
|
+
function isFetchEvent(event) {
|
|
2255
|
+
return event.type === "fetch" && event.request instanceof Request;
|
|
2278
2256
|
}
|
|
2279
|
-
function
|
|
2280
|
-
|
|
2281
|
-
|
|
2257
|
+
function isQueueEvent(event) {
|
|
2258
|
+
return event.type === "queue" && "batch" in event;
|
|
2259
|
+
}
|
|
2260
|
+
function isScheduledEvent(event) {
|
|
2261
|
+
return event.type === "scheduled" && "controller" in event;
|
|
2262
|
+
}
|
|
2263
|
+
function isEmailEvent(event) {
|
|
2264
|
+
return event.type === "email" && "message" in event;
|
|
2282
2265
|
}
|
|
2266
|
+
function isTailEvent(event) {
|
|
2267
|
+
return event.type === "tail" && Array.isArray(event) && "events" in event;
|
|
2268
|
+
}
|
|
2269
|
+
function isDurableObjectEvent(event) {
|
|
2270
|
+
return event.type.startsWith("durable-object-") && "state" in event;
|
|
2271
|
+
}
|
|
2272
|
+
function isDurableObjectFetchEvent(event) {
|
|
2273
|
+
return event.type === "durable-object-fetch" && event.request instanceof Request;
|
|
2274
|
+
}
|
|
2275
|
+
function isDurableObjectAlarmEvent(event) {
|
|
2276
|
+
return event.type === "durable-object-alarm" && "state" in event;
|
|
2277
|
+
}
|
|
2278
|
+
function isDurableObjectWebSocketMessageEvent(event) {
|
|
2279
|
+
return event.type === "durable-object-websocket-message" && "ws" in event && "message" in event;
|
|
2280
|
+
}
|
|
2281
|
+
function isDurableObjectWebSocketCloseEvent(event) {
|
|
2282
|
+
return event.type === "durable-object-websocket-close" && "ws" in event && "code" in event;
|
|
2283
|
+
}
|
|
2284
|
+
function isDurableObjectWebSocketErrorEvent(event) {
|
|
2285
|
+
return event.type === "durable-object-websocket-error" && "ws" in event && "error" in event;
|
|
2286
|
+
}
|
|
2287
|
+
var getFetchEvent = createEventAccessor("getFetchEvent()", isFetchEvent);
|
|
2288
|
+
var getQueueEvent = createEventAccessor("getQueueEvent()", isQueueEvent);
|
|
2289
|
+
var getScheduledEvent = createEventAccessor("getScheduledEvent()", isScheduledEvent);
|
|
2290
|
+
var getEmailEvent = createEventAccessor("getEmailEvent()", isEmailEvent);
|
|
2291
|
+
var getTailEvent = createEventAccessor("getTailEvent()", isTailEvent);
|
|
2292
|
+
var getDurableObjectEvent = createEventAccessor("getDurableObjectEvent()", isDurableObjectEvent);
|
|
2293
|
+
var getDurableObjectFetchEvent = createEventAccessor("getDurableObjectFetchEvent()", isDurableObjectFetchEvent);
|
|
2294
|
+
var getDurableObjectAlarmEvent = createEventAccessor("getDurableObjectAlarmEvent()", isDurableObjectAlarmEvent);
|
|
2295
|
+
var getDurableObjectWebSocketMessageEvent = createEventAccessor("getDurableObjectWebSocketMessageEvent()", isDurableObjectWebSocketMessageEvent);
|
|
2296
|
+
var getDurableObjectWebSocketCloseEvent = createEventAccessor("getDurableObjectWebSocketCloseEvent()", isDurableObjectWebSocketCloseEvent);
|
|
2297
|
+
var getDurableObjectWebSocketErrorEvent = createEventAccessor("getDurableObjectWebSocketErrorEvent()", isDurableObjectWebSocketErrorEvent);
|
|
2283
2298
|
|
|
2284
|
-
export {
|
|
2299
|
+
export { BridgeClient, getClient, createEnvProxy, bridgeEnv, initEnv, setBindingHints, createFetchEvent, createQueueEvent, createScheduledEvent, createEmailEvent, createTailEvent, createDurableObjectFetchEvent, createDurableObjectAlarmEvent, createDurableObjectWebSocketMessageEvent, createDurableObjectWebSocketCloseEvent, createDurableObjectWebSocketErrorEvent, ContextAccessError, createContextProxy, runWithContext, runWithEventContext, getContext, getContextOrNull, getEventContext, getEventContextOrNull, hasContext, getFetchEvent, getQueueEvent, getScheduledEvent, getEmailEvent, getTailEvent, getDurableObjectEvent, getDurableObjectFetchEvent, getDurableObjectAlarmEvent, getDurableObjectWebSocketMessageEvent, getDurableObjectWebSocketCloseEvent, getDurableObjectWebSocketErrorEvent };
|