devflare 1.0.0-next.5 → 1.0.0-next.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/LLM.md +17312 -2139
- package/README.md +394 -605
- package/bin/devflare.js +30 -14
- package/dist/_chunks/account-BI3WZMDy.js +462 -0
- package/dist/_chunks/account-resources-CsmVowJp.js +159 -0
- package/dist/_chunks/ai-CBEuLdoP.js +322 -0
- package/dist/_chunks/api-TzdliH-6.js +568 -0
- package/dist/_chunks/build-artifacts-DU5V0J0Z.js +483 -0
- package/dist/_chunks/build-e0KR38-4.js +24 -0
- package/dist/_chunks/cli-DuUz10Mn.js +1163 -0
- package/dist/_chunks/cloudflare-BaloqI3H.js +157 -0
- package/dist/_chunks/colors-DiK6wPJ5.js +13 -0
- package/dist/_chunks/command-utils-DA0Qx9_K.js +45 -0
- package/dist/_chunks/compiler-Zw16C9Pi.js +489 -0
- package/dist/_chunks/config-Brju62xy.js +78 -0
- package/dist/_chunks/config-path-DaL1ylZ_.js +42 -0
- package/dist/_chunks/context-CX50Y2Kb.js +2250 -0
- package/dist/_chunks/decorators-QmV57ixr.js +19 -0
- package/dist/_chunks/dependencies-C2oxFjU_.js +57 -0
- package/dist/_chunks/deploy-B-Kku1Vk.js +1032 -0
- package/dist/_chunks/dev-D4e_RRZn.js +3471 -0
- package/dist/_chunks/doctor-jm_K4dxL.js +219 -0
- package/dist/_chunks/durable-object-DMtH0XYX.js +234 -0
- package/dist/_chunks/env-S0_nMVz1.js +125 -0
- package/dist/_chunks/family-_9-mGSfO.js +143 -0
- package/dist/_chunks/generated-artifacts-dMJY4KAt.js +32 -0
- package/dist/_chunks/glob-CmQOvunB.js +56 -0
- package/dist/_chunks/init-DnkJOmpW.js +165 -0
- package/dist/_chunks/loader-Cr0_OWPy.js +1288 -0
- package/dist/_chunks/local-dev-vars-CTSa-wvF.js +81 -0
- package/dist/_chunks/local-hyperdrive-CJ90j46O.js +119 -0
- package/dist/_chunks/local-media-bindings-DsAW4AMF.js +335 -0
- package/dist/_chunks/local-secrets-DMPkmOn3.js +123 -0
- package/dist/_chunks/local-workflow-entrypoints-Cq_WJajd.js +90 -0
- package/dist/_chunks/login-FjTAAQbi.js +51 -0
- package/dist/_chunks/package-metadata-DjHBLB-z.js +39 -0
- package/dist/_chunks/preferences-BKp_7XJx.js +241 -0
- package/dist/_chunks/preview-C3Cdr8an.js +462 -0
- package/dist/_chunks/preview-registry-ClAbLTHH.js +1186 -0
- package/dist/_chunks/preview-resources-CGMBjsYB.js +359 -0
- package/dist/_chunks/previews-C7hs9-BT.js +1134 -0
- package/dist/_chunks/productions-T9Als4fE.js +411 -0
- package/dist/_chunks/ref-CYJNAAe_.js +178 -0
- package/dist/_chunks/remote-CZnP-HLJ.js +79 -0
- package/dist/_chunks/remote-config-D39BY9ji.js +132 -0
- package/dist/_chunks/resolve-package-qizBfCIm.js +152 -0
- package/dist/_chunks/rolldown-runtime-CvQ6eiug.js +14 -0
- package/dist/_chunks/routes-BFYCqHb-.js +833 -0
- package/dist/_chunks/runtime-DL-Nz3k8.js +550 -0
- package/dist/_chunks/schema-normalization-BCwTLTGp.js +660 -0
- package/dist/_chunks/secrets-DIpJGe6C.js +95 -0
- package/dist/_chunks/tail-IY-ijYmv.js +239 -0
- package/dist/_chunks/token-Dmi0KXyX.js +333 -0
- package/dist/_chunks/tokens-iVcgNXi-.js +221 -0
- package/dist/_chunks/types-DoKsMYfm.js +484 -0
- package/dist/_chunks/ui-BUoZApvE.js +103 -0
- package/dist/_chunks/usage-BBTGzjon.js +272 -0
- package/dist/_chunks/vite-CGtVNf5E.js +1267 -0
- package/dist/_chunks/vite-utils-OVLMV605.js +183 -0
- package/dist/_chunks/worker-BEZI4od1.js +410 -0
- package/dist/_chunks/worker-bundler-dTTnYU3n.js +458 -0
- package/dist/_chunks/worker-entrypoint-CQW77lG8.js +247 -0
- package/dist/_chunks/workerName-CFJsLZA-.js +23 -0
- package/dist/bridge/client.d.ts +49 -7
- package/dist/bridge/client.d.ts.map +1 -1
- package/dist/bridge/gateway-runtime.d.ts +8 -0
- package/dist/bridge/gateway-runtime.d.ts.map +1 -0
- package/dist/bridge/index.d.ts +6 -6
- package/dist/bridge/index.d.ts.map +1 -1
- package/dist/bridge/log.d.ts +5 -0
- package/dist/bridge/log.d.ts.map +1 -0
- package/dist/bridge/miniflare.d.ts +82 -2
- package/dist/bridge/miniflare.d.ts.map +1 -1
- package/dist/bridge/proxy.d.ts +12 -11
- package/dist/bridge/proxy.d.ts.map +1 -1
- package/dist/bridge/server.d.ts +2 -1
- package/dist/bridge/server.d.ts.map +1 -1
- package/dist/bridge/v2/body-streams.d.ts +53 -0
- package/dist/bridge/v2/body-streams.d.ts.map +1 -0
- package/dist/bridge/v2/codec.d.ts +106 -0
- package/dist/bridge/v2/codec.d.ts.map +1 -0
- package/dist/bridge/v2/control-messages.d.ts +46 -0
- package/dist/bridge/v2/control-messages.d.ts.map +1 -0
- package/dist/bridge/v2/frames.d.ts +109 -0
- package/dist/bridge/v2/frames.d.ts.map +1 -0
- package/dist/bridge/v2/index.d.ts +11 -0
- package/dist/bridge/v2/index.d.ts.map +1 -0
- package/dist/bridge/v2/serialization.d.ts +48 -0
- package/dist/bridge/v2/serialization.d.ts.map +1 -0
- package/dist/bridge/v2/transport.d.ts +31 -0
- package/dist/bridge/v2/transport.d.ts.map +1 -0
- package/dist/bridge/v2/value-codec.d.ts +61 -0
- package/dist/bridge/v2/value-codec.d.ts.map +1 -0
- package/dist/bridge/{serialization.d.ts → v2/value-serialization.d.ts} +40 -18
- package/dist/bridge/v2/value-serialization.d.ts.map +1 -0
- package/dist/bridge/{protocol.d.ts → v2/wire.d.ts} +32 -8
- package/dist/bridge/v2/wire.d.ts.map +1 -0
- package/dist/bridge/v2/ws-relay.d.ts +53 -0
- package/dist/bridge/v2/ws-relay.d.ts.map +1 -0
- package/dist/browser-shim/handler.d.ts +2 -2
- package/dist/browser-shim/handler.d.ts.map +1 -1
- package/dist/browser-shim/index.d.ts +2 -2
- package/dist/browser-shim/server.d.ts +63 -0
- package/dist/browser-shim/server.d.ts.map +1 -1
- package/dist/browser.d.ts +5411 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +80 -0
- package/dist/bundler/defaults.d.ts +23 -0
- package/dist/bundler/defaults.d.ts.map +1 -0
- package/dist/bundler/do-bundler.d.ts +7 -0
- package/dist/bundler/do-bundler.d.ts.map +1 -1
- package/dist/bundler/index.d.ts +3 -1
- package/dist/bundler/index.d.ts.map +1 -1
- package/dist/bundler/rolldown-shared.d.ts +53 -0
- package/dist/bundler/rolldown-shared.d.ts.map +1 -0
- package/dist/bundler/worker-bundler.d.ts +13 -0
- package/dist/bundler/worker-bundler.d.ts.map +1 -0
- package/dist/bundler/worker-compat.d.ts +4 -0
- package/dist/bundler/worker-compat.d.ts.map +1 -0
- package/dist/cli/build-manifest.d.ts +66 -0
- package/dist/cli/build-manifest.d.ts.map +1 -0
- package/dist/cli/command-utils.d.ts +18 -0
- package/dist/cli/command-utils.d.ts.map +1 -0
- package/dist/cli/commands/account.d.ts +2 -2
- package/dist/cli/commands/account.d.ts.map +1 -1
- package/dist/cli/commands/ai.d.ts +1 -1
- package/dist/cli/commands/ai.d.ts.map +1 -1
- package/dist/cli/commands/build-artifacts.d.ts +40 -0
- package/dist/cli/commands/build-artifacts.d.ts.map +1 -0
- 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 +4 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/deploy/metadata.d.ts +18 -0
- package/dist/cli/commands/deploy/metadata.d.ts.map +1 -0
- package/dist/cli/commands/deploy/prepare.d.ts +23 -0
- package/dist/cli/commands/deploy/prepare.d.ts.map +1 -0
- package/dist/cli/commands/deploy/runtime.d.ts +4 -0
- package/dist/cli/commands/deploy/runtime.d.ts.map +1 -0
- package/dist/cli/commands/deploy/verification.d.ts +36 -0
- package/dist/cli/commands/deploy/verification.d.ts.map +1 -0
- package/dist/cli/commands/deploy.d.ts +2 -2
- package/dist/cli/commands/deploy.d.ts.map +1 -1
- package/dist/cli/commands/dev.d.ts +9 -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 +4 -0
- package/dist/cli/commands/login.d.ts.map +1 -0
- package/dist/cli/commands/previews-support/cleanup.d.ts +9 -0
- package/dist/cli/commands/previews-support/cleanup.d.ts.map +1 -0
- package/dist/cli/commands/previews-support/family.d.ts +10 -0
- package/dist/cli/commands/previews-support/family.d.ts.map +1 -0
- package/dist/cli/commands/previews-support/render.d.ts +8 -0
- package/dist/cli/commands/previews-support/render.d.ts.map +1 -0
- package/dist/cli/commands/previews-support/theme.d.ts +10 -0
- package/dist/cli/commands/previews-support/theme.d.ts.map +1 -0
- package/dist/cli/commands/previews-support/types.d.ts +70 -0
- package/dist/cli/commands/previews-support/types.d.ts.map +1 -0
- package/dist/cli/commands/previews.d.ts +4 -0
- package/dist/cli/commands/previews.d.ts.map +1 -0
- package/dist/cli/commands/productions.d.ts +4 -0
- package/dist/cli/commands/productions.d.ts.map +1 -0
- 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 +4 -0
- package/dist/cli/commands/secrets.d.ts.map +1 -0
- package/dist/cli/commands/tail.d.ts +44 -0
- package/dist/cli/commands/tail.d.ts.map +1 -0
- package/dist/cli/commands/token.d.ts +4 -0
- package/dist/cli/commands/token.d.ts.map +1 -0
- package/dist/cli/commands/type-generation/discovery.d.ts +7 -0
- package/dist/cli/commands/type-generation/discovery.d.ts.map +1 -0
- package/dist/cli/commands/type-generation/generator.d.ts +121 -0
- package/dist/cli/commands/type-generation/generator.d.ts.map +1 -0
- package/dist/cli/commands/type-generation/models.d.ts +27 -0
- package/dist/cli/commands/type-generation/models.d.ts.map +1 -0
- 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 +4 -0
- package/dist/cli/commands/worker.d.ts.map +1 -0
- package/dist/cli/config-path.d.ts +6 -0
- package/dist/cli/config-path.d.ts.map +1 -0
- package/dist/cli/dependencies.d.ts +2 -1
- package/dist/cli/dependencies.d.ts.map +1 -1
- package/dist/cli/deploy-strategy.d.ts +17 -0
- package/dist/cli/deploy-strategy.d.ts.map +1 -0
- package/dist/cli/deploy-target.d.ts +17 -0
- package/dist/cli/deploy-target.d.ts.map +1 -0
- package/dist/cli/generated-artifacts.d.ts +12 -0
- package/dist/cli/generated-artifacts.d.ts.map +1 -0
- package/dist/cli/gradual-deploy.d.ts +49 -0
- package/dist/cli/gradual-deploy.d.ts.map +1 -0
- package/dist/cli/help-pages/pages/account.d.ts +3 -0
- package/dist/cli/help-pages/pages/account.d.ts.map +1 -0
- package/dist/cli/help-pages/pages/core.d.ts +4 -0
- package/dist/cli/help-pages/pages/core.d.ts.map +1 -0
- package/dist/cli/help-pages/pages/index.d.ts +3 -0
- package/dist/cli/help-pages/pages/index.d.ts.map +1 -0
- package/dist/cli/help-pages/pages/misc.d.ts +3 -0
- package/dist/cli/help-pages/pages/misc.d.ts.map +1 -0
- package/dist/cli/help-pages/pages/previews.d.ts +3 -0
- package/dist/cli/help-pages/pages/previews.d.ts.map +1 -0
- package/dist/cli/help-pages/pages/productions.d.ts +3 -0
- package/dist/cli/help-pages/pages/productions.d.ts.map +1 -0
- package/dist/cli/help-pages/render.d.ts +12 -0
- package/dist/cli/help-pages/render.d.ts.map +1 -0
- package/dist/cli/help-pages/shared.d.ts +15 -0
- package/dist/cli/help-pages/shared.d.ts.map +1 -0
- package/dist/cli/help-pages/types.d.ts +23 -0
- package/dist/cli/help-pages/types.d.ts.map +1 -0
- package/dist/cli/help.d.ts +6 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/package-metadata.d.ts +16 -0
- package/dist/cli/package-metadata.d.ts.map +1 -0
- package/dist/cli/preview-bindings.d.ts +49 -0
- package/dist/cli/preview-bindings.d.ts.map +1 -0
- package/dist/cli/preview.d.ts +10 -0
- package/dist/cli/preview.d.ts.map +1 -0
- package/dist/cli/ui.d.ts +37 -0
- package/dist/cli/ui.d.ts.map +1 -0
- package/dist/cli/workspace-build-guard.d.ts +14 -0
- package/dist/cli/workspace-build-guard.d.ts.map +1 -0
- package/dist/cli/wrangler-auth.d.ts +1 -1
- package/dist/cloudflare/account-core.d.ts +6 -0
- package/dist/cloudflare/account-core.d.ts.map +1 -0
- package/dist/cloudflare/account-resources.d.ts +40 -0
- package/dist/cloudflare/account-resources.d.ts.map +1 -0
- package/dist/cloudflare/account-status.d.ts +11 -0
- package/dist/cloudflare/account-status.d.ts.map +1 -0
- package/dist/cloudflare/account-workers.d.ts +14 -0
- package/dist/cloudflare/account-workers.d.ts.map +1 -0
- package/dist/cloudflare/account.d.ts +7 -64
- package/dist/cloudflare/account.d.ts.map +1 -1
- package/dist/cloudflare/api.d.ts +71 -3
- package/dist/cloudflare/api.d.ts.map +1 -1
- package/dist/cloudflare/auth.d.ts +1 -1
- package/dist/cloudflare/auth.d.ts.map +1 -1
- package/dist/cloudflare/index.d.ts +61 -6
- package/dist/cloudflare/index.d.ts.map +1 -1
- package/dist/cloudflare/index.js +4 -13
- package/dist/cloudflare/known-permission-group-ids.generated.d.ts +10 -0
- package/dist/cloudflare/known-permission-group-ids.generated.d.ts.map +1 -0
- package/dist/cloudflare/kv-namespace.d.ts +4 -0
- package/dist/cloudflare/kv-namespace.d.ts.map +1 -0
- package/dist/cloudflare/preferences.d.ts +7 -0
- package/dist/cloudflare/preferences.d.ts.map +1 -1
- package/dist/cloudflare/preview-registry-cache.d.ts +6 -0
- package/dist/cloudflare/preview-registry-cache.d.ts.map +1 -0
- package/dist/cloudflare/preview-registry-inference.d.ts +14 -0
- package/dist/cloudflare/preview-registry-inference.d.ts.map +1 -0
- package/dist/cloudflare/preview-registry-records.d.ts +4 -0
- package/dist/cloudflare/preview-registry-records.d.ts.map +1 -0
- package/dist/cloudflare/preview-registry-shape.d.ts +47 -0
- package/dist/cloudflare/preview-registry-shape.d.ts.map +1 -0
- package/dist/cloudflare/preview-registry-store.d.ts +14 -0
- package/dist/cloudflare/preview-registry-store.d.ts.map +1 -0
- package/dist/cloudflare/preview-registry-transport.d.ts +4 -0
- package/dist/cloudflare/preview-registry-transport.d.ts.map +1 -0
- package/dist/cloudflare/preview-registry-types.d.ts +103 -0
- package/dist/cloudflare/preview-registry-types.d.ts.map +1 -0
- package/dist/cloudflare/preview-registry.d.ts +42 -0
- package/dist/cloudflare/preview-registry.d.ts.map +1 -0
- package/dist/cloudflare/preview-urls.d.ts +3 -0
- package/dist/cloudflare/preview-urls.d.ts.map +1 -0
- package/dist/cloudflare/registry-schema.d.ts +253 -0
- package/dist/cloudflare/registry-schema.d.ts.map +1 -0
- package/dist/cloudflare/remote-config.d.ts.map +1 -1
- package/dist/cloudflare/tokens.d.ts +44 -0
- package/dist/cloudflare/tokens.d.ts.map +1 -0
- package/dist/cloudflare/types.d.ts +124 -7
- package/dist/cloudflare/types.d.ts.map +1 -1
- package/dist/cloudflare/usage.d.ts +31 -3
- package/dist/cloudflare/usage.d.ts.map +1 -1
- package/dist/config/binding-resolution-helpers.d.ts +41 -0
- package/dist/config/binding-resolution-helpers.d.ts.map +1 -0
- package/dist/config/compatibility.d.ts +3 -0
- package/dist/config/compatibility.d.ts.map +1 -0
- package/dist/config/compiler/bindings.d.ts +14 -0
- package/dist/config/compiler/bindings.d.ts.map +1 -0
- package/dist/config/compiler/core-helpers.d.ts +6 -0
- package/dist/config/compiler/core-helpers.d.ts.map +1 -0
- package/dist/config/compiler/do-workers.d.ts +34 -0
- package/dist/config/compiler/do-workers.d.ts.map +1 -0
- package/dist/config/compiler/paths.d.ts +18 -0
- package/dist/config/compiler/paths.d.ts.map +1 -0
- package/dist/config/compiler/types.d.ts +298 -0
- package/dist/config/compiler/types.d.ts.map +1 -0
- package/dist/config/compiler.d.ts +22 -134
- package/dist/config/compiler.d.ts.map +1 -1
- package/dist/config/cron.d.ts +19 -0
- package/dist/config/cron.d.ts.map +1 -0
- package/dist/config/define.d.ts +8 -5
- package/dist/config/define.d.ts.map +1 -1
- package/dist/config/deploy-resources.d.ts +58 -0
- package/dist/config/deploy-resources.d.ts.map +1 -0
- package/dist/config/env-vars.d.ts +309 -0
- package/dist/config/env-vars.d.ts.map +1 -0
- package/dist/config/framework-providers.d.ts +9 -0
- package/dist/config/framework-providers.d.ts.map +1 -0
- package/dist/config/index.d.ts +12 -5
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/loader.d.ts +2 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/local-dev-vars.d.ts +15 -0
- package/dist/config/local-dev-vars.d.ts.map +1 -0
- package/dist/config/preview-resources.d.ts +83 -0
- package/dist/config/preview-resources.d.ts.map +1 -0
- package/dist/config/preview.d.ts +29 -0
- package/dist/config/preview.d.ts.map +1 -0
- package/dist/config/ref.d.ts +16 -25
- package/dist/config/ref.d.ts.map +1 -1
- package/dist/config/resolve-phased.d.ts +72 -0
- package/dist/config/resolve-phased.d.ts.map +1 -0
- package/dist/config/resolve.d.ts +11 -0
- package/dist/config/resolve.d.ts.map +1 -0
- package/dist/config/resource-resolution.d.ts +80 -0
- package/dist/config/resource-resolution.d.ts.map +1 -0
- package/dist/config/schema-bindings.d.ts +2025 -0
- package/dist/config/schema-bindings.d.ts.map +1 -0
- package/dist/config/schema-build.d.ts +67 -0
- package/dist/config/schema-build.d.ts.map +1 -0
- package/dist/config/schema-env.d.ts +3579 -0
- package/dist/config/schema-env.d.ts.map +1 -0
- package/dist/config/schema-normalization.d.ts +265 -0
- package/dist/config/schema-normalization.d.ts.map +1 -0
- package/dist/config/schema-runtime.d.ts +508 -0
- package/dist/config/schema-runtime.d.ts.map +1 -0
- package/dist/config/schema-types-bindings-platform.d.ts +508 -0
- package/dist/config/schema-types-bindings-platform.d.ts.map +1 -0
- package/dist/config/schema-types-bindings-resources.d.ts +767 -0
- package/dist/config/schema-types-bindings-resources.d.ts.map +1 -0
- package/dist/config/schema-types-bindings.d.ts +293 -0
- package/dist/config/schema-types-bindings.d.ts.map +1 -0
- package/dist/config/schema-types-build.d.ts +86 -0
- package/dist/config/schema-types-build.d.ts.map +1 -0
- package/dist/config/schema-types-runtime.d.ts +917 -0
- package/dist/config/schema-types-runtime.d.ts.map +1 -0
- package/dist/config/schema-types.d.ts +424 -0
- package/dist/config/schema-types.d.ts.map +1 -0
- package/dist/config/schema.d.ts +5324 -2011
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/service-bindings-validation.d.ts +36 -0
- package/dist/config/service-bindings-validation.d.ts.map +1 -0
- package/dist/config-entry.d.ts +7 -0
- package/dist/config-entry.d.ts.map +1 -0
- package/dist/config-entry.js +3 -0
- package/dist/decorators/durable-object.d.ts.map +1 -1
- package/dist/decorators/index.d.ts +2 -2
- package/dist/decorators/index.js +2 -9
- package/dist/dev-server/d1-migrations.d.ts +36 -0
- package/dist/dev-server/d1-migrations.d.ts.map +1 -0
- package/dist/dev-server/dev-server-state.d.ts +59 -0
- package/dist/dev-server/dev-server-state.d.ts.map +1 -0
- package/dist/dev-server/gateway-script.d.ts +21 -0
- package/dist/dev-server/gateway-script.d.ts.map +1 -0
- package/dist/dev-server/index.d.ts +1 -1
- package/dist/dev-server/miniflare-bindings.d.ts +81 -0
- package/dist/dev-server/miniflare-bindings.d.ts.map +1 -0
- package/dist/dev-server/miniflare-dev-config.d.ts +36 -0
- package/dist/dev-server/miniflare-dev-config.d.ts.map +1 -0
- package/dist/dev-server/miniflare-log.d.ts +20 -0
- package/dist/dev-server/miniflare-log.d.ts.map +1 -0
- package/dist/dev-server/miniflare-worker-config.d.ts +82 -0
- package/dist/dev-server/miniflare-worker-config.d.ts.map +1 -0
- package/dist/dev-server/reload-queue.d.ts +13 -0
- package/dist/dev-server/reload-queue.d.ts.map +1 -0
- package/dist/dev-server/runtime-stdio.d.ts +8 -0
- package/dist/dev-server/runtime-stdio.d.ts.map +1 -0
- package/dist/dev-server/server-startup-helpers.d.ts +84 -0
- package/dist/dev-server/server-startup-helpers.d.ts.map +1 -0
- package/dist/dev-server/server.d.ts +2 -0
- package/dist/dev-server/server.d.ts.map +1 -1
- package/dist/dev-server/vite-process.d.ts +15 -0
- package/dist/dev-server/vite-process.d.ts.map +1 -0
- package/dist/dev-server/vite-utils.d.ts +19 -1
- package/dist/dev-server/vite-utils.d.ts.map +1 -1
- package/dist/dev-server/worker-source-watcher.d.ts +17 -0
- package/dist/dev-server/worker-source-watcher.d.ts.map +1 -0
- package/dist/dev-server/worker-surface-paths.d.ts +6 -0
- package/dist/dev-server/worker-surface-paths.d.ts.map +1 -0
- package/dist/env.d.ts +10 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/index.d.ts +8 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -298
- package/dist/runtime/context-events.d.ts +13 -0
- package/dist/runtime/context-events.d.ts.map +1 -0
- package/dist/runtime/context-types.d.ts +82 -0
- package/dist/runtime/context-types.d.ts.map +1 -0
- package/dist/runtime/context.d.ts +20 -44
- package/dist/runtime/context.d.ts.map +1 -1
- package/dist/runtime/exports.d.ts +70 -55
- package/dist/runtime/exports.d.ts.map +1 -1
- package/dist/runtime/index.d.ts +10 -3
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +5 -111
- package/dist/runtime/middleware.d.ts +119 -67
- package/dist/runtime/middleware.d.ts.map +1 -1
- package/dist/runtime/router/index.d.ts +7 -0
- package/dist/runtime/router/index.d.ts.map +1 -0
- package/dist/runtime/router/types.d.ts +24 -0
- package/dist/runtime/router/types.d.ts.map +1 -0
- package/dist/runtime/validation.d.ts +18 -4
- package/dist/runtime/validation.d.ts.map +1 -1
- package/dist/secrets/local-secrets.d.ts +46 -0
- package/dist/secrets/local-secrets.d.ts.map +1 -0
- package/dist/shims/local-hyperdrive.d.ts +12 -0
- package/dist/shims/local-hyperdrive.d.ts.map +1 -0
- package/dist/shims/local-media-bindings.d.ts +19 -0
- package/dist/shims/local-media-bindings.d.ts.map +1 -0
- package/dist/shims/local-worker-loader.d.ts +3 -0
- package/dist/shims/local-worker-loader.d.ts.map +1 -0
- package/dist/sveltekit/index.d.ts +1 -1
- package/dist/sveltekit/index.d.ts.map +1 -1
- package/dist/sveltekit/index.js +313 -167
- package/dist/sveltekit/local-bindings.d.ts +4 -0
- package/dist/sveltekit/local-bindings.d.ts.map +1 -0
- package/dist/sveltekit/platform.d.ts +20 -2
- package/dist/sveltekit/platform.d.ts.map +1 -1
- package/dist/test/ai-search.d.ts +39 -0
- package/dist/test/ai-search.d.ts.map +1 -0
- package/dist/test/alarm.d.ts +55 -0
- package/dist/test/alarm.d.ts.map +1 -0
- package/dist/test/binding-hints.d.ts +10 -0
- package/dist/test/binding-hints.d.ts.map +1 -0
- package/dist/test/cf.d.ts +71 -35
- package/dist/test/cf.d.ts.map +1 -1
- package/dist/test/containers.d.ts +87 -0
- package/dist/test/containers.d.ts.map +1 -0
- package/dist/test/email.d.ts +16 -7
- package/dist/test/email.d.ts.map +1 -1
- package/dist/test/index.d.ts +20 -21
- package/dist/test/index.d.ts.map +1 -1
- package/dist/test/index.js +4971 -70
- package/dist/test/offline-bindings.d.ts +115 -0
- package/dist/test/offline-bindings.d.ts.map +1 -0
- 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 +13 -0
- package/dist/test/remote-cloudflare.d.ts.map +1 -0
- package/dist/test/remote-vectorize.d.ts.map +1 -1
- package/dist/test/resolve-service-bindings.d.ts +64 -4
- package/dist/test/resolve-service-bindings.d.ts.map +1 -1
- package/dist/test/scheduled.d.ts.map +1 -1
- package/dist/test/should-skip.d.ts +14 -18
- package/dist/test/should-skip.d.ts.map +1 -1
- package/dist/test/simple-context-bindings.d.ts +13 -0
- package/dist/test/simple-context-bindings.d.ts.map +1 -0
- package/dist/test/simple-context-durable-objects.d.ts +6 -0
- package/dist/test/simple-context-durable-objects.d.ts.map +1 -0
- package/dist/test/simple-context-env.d.ts +35 -0
- package/dist/test/simple-context-env.d.ts.map +1 -0
- package/dist/test/simple-context-gateway-script.d.ts +2 -0
- package/dist/test/simple-context-gateway-script.d.ts.map +1 -0
- package/dist/test/simple-context-handlers.d.ts +12 -0
- package/dist/test/simple-context-handlers.d.ts.map +1 -0
- package/dist/test/simple-context-lifecycle.d.ts +32 -0
- package/dist/test/simple-context-lifecycle.d.ts.map +1 -0
- package/dist/test/simple-context-mfconfig.d.ts +10 -0
- package/dist/test/simple-context-mfconfig.d.ts.map +1 -0
- package/dist/test/simple-context-multi-worker.d.ts +16 -0
- package/dist/test/simple-context-multi-worker.d.ts.map +1 -0
- package/dist/test/simple-context-paths.d.ts +40 -0
- package/dist/test/simple-context-paths.d.ts.map +1 -0
- package/dist/test/simple-context-runtime.d.ts +19 -0
- package/dist/test/simple-context-runtime.d.ts.map +1 -0
- package/dist/test/simple-context-startup.d.ts +11 -0
- package/dist/test/simple-context-startup.d.ts.map +1 -0
- package/dist/test/simple-context-transport.d.ts +14 -0
- package/dist/test/simple-context-transport.d.ts.map +1 -0
- package/dist/test/simple-context.d.ts +8 -27
- package/dist/test/simple-context.d.ts.map +1 -1
- package/dist/test/tail.d.ts +3 -2
- package/dist/test/tail.d.ts.map +1 -1
- package/dist/test/utilities/analytics-engine.d.ts +22 -0
- package/dist/test/utilities/analytics-engine.d.ts.map +1 -0
- package/dist/test/utilities/artifacts.d.ts +11 -0
- package/dist/test/utilities/artifacts.d.ts.map +1 -0
- package/dist/test/utilities/context.d.ts +39 -0
- package/dist/test/utilities/context.d.ts.map +1 -0
- package/dist/test/utilities/d1.d.ts +21 -0
- package/dist/test/utilities/d1.d.ts.map +1 -0
- package/dist/test/utilities/env.d.ts +43 -0
- package/dist/test/utilities/env.d.ts.map +1 -0
- package/dist/test/utilities/kv.d.ts +11 -0
- package/dist/test/utilities/kv.d.ts.map +1 -0
- package/dist/test/utilities/media.d.ts +16 -0
- package/dist/test/utilities/media.d.ts.map +1 -0
- package/dist/test/utilities/platform.d.ts +41 -0
- package/dist/test/utilities/platform.d.ts.map +1 -0
- package/dist/test/utilities/queue.d.ts +5 -0
- package/dist/test/utilities/queue.d.ts.map +1 -0
- package/dist/test/utilities/r2.d.ts +2 -0
- package/dist/test/utilities/r2.d.ts.map +1 -0
- package/dist/test/utilities/stream-flagship.d.ts +27 -0
- package/dist/test/utilities/stream-flagship.d.ts.map +1 -0
- package/dist/test/utilities/vectorize.d.ts +38 -0
- package/dist/test/utilities/vectorize.d.ts.map +1 -0
- package/dist/test/utilities/workflows.d.ts +26 -0
- package/dist/test/utilities/workflows.d.ts.map +1 -0
- package/dist/test/utilities.d.ts +13 -98
- package/dist/test/utilities.d.ts.map +1 -1
- package/dist/test/worker.d.ts +6 -0
- package/dist/test/worker.d.ts.map +1 -1
- package/dist/transform/durable-object.d.ts.map +1 -1
- package/dist/transform/index.d.ts +2 -2
- package/dist/transform/worker-entrypoint.d.ts +5 -0
- package/dist/transform/worker-entrypoint.d.ts.map +1 -1
- package/dist/utils/entrypoint-discovery.d.ts +6 -3
- package/dist/utils/entrypoint-discovery.d.ts.map +1 -1
- 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 +15 -0
- package/dist/utils/send-email.d.ts.map +1 -0
- package/dist/utils/send-email.js +163 -0
- package/dist/vite/config-file.d.ts +25 -0
- package/dist/vite/config-file.d.ts.map +1 -0
- package/dist/vite/index.d.ts +3 -2
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +2 -339
- package/dist/vite/plugin-config-hook.d.ts +28 -0
- package/dist/vite/plugin-config-hook.d.ts.map +1 -0
- package/dist/vite/plugin-context.d.ts +27 -0
- package/dist/vite/plugin-context.d.ts.map +1 -0
- package/dist/vite/plugin-durable-objects.d.ts +18 -0
- package/dist/vite/plugin-durable-objects.d.ts.map +1 -0
- package/dist/vite/plugin-programmatic.d.ts +44 -0
- package/dist/vite/plugin-programmatic.d.ts.map +1 -0
- package/dist/vite/plugin-service-bindings.d.ts +13 -0
- package/dist/vite/plugin-service-bindings.d.ts.map +1 -0
- package/dist/vite/plugin-transform.d.ts +41 -0
- package/dist/vite/plugin-transform.d.ts.map +1 -0
- package/dist/vite/plugin.d.ts +10 -41
- package/dist/vite/plugin.d.ts.map +1 -1
- package/dist/worker-entry/composed-worker.d.ts +7 -0
- package/dist/worker-entry/composed-worker.d.ts.map +1 -0
- package/dist/worker-entry/durable-object-discovery.d.ts +20 -0
- package/dist/worker-entry/durable-object-discovery.d.ts.map +1 -0
- package/dist/worker-entry/extensions.d.ts +5 -0
- package/dist/worker-entry/extensions.d.ts.map +1 -0
- package/dist/worker-entry/routes.d.ts +22 -0
- package/dist/worker-entry/routes.d.ts.map +1 -0
- package/dist/worker-entry/surface-paths.d.ts +26 -0
- package/dist/worker-entry/surface-paths.d.ts.map +1 -0
- package/dist/worker-entry/validate-fetch-style.d.ts +12 -0
- package/dist/worker-entry/validate-fetch-style.d.ts.map +1 -0
- package/dist/workflows/local-workflow-entrypoints.d.ts +7 -0
- package/dist/workflows/local-workflow-entrypoints.d.ts.map +1 -0
- package/package.json +159 -116
- package/R2.md +0 -170
- package/dist/account-rvrj687w.js +0 -397
- package/dist/ai-dx4fr9jh.js +0 -107
- package/dist/bridge/protocol.d.ts.map +0 -1
- package/dist/bridge/serialization.d.ts.map +0 -1
- package/dist/browser-shim/worker.d.ts +0 -14
- package/dist/browser-shim/worker.d.ts.map +0 -1
- package/dist/build-mnf6v8gd.js +0 -53
- package/dist/deploy-nhceck39.js +0 -70
- package/dist/dev-b9dmrj7b.js +0 -2417
- package/dist/doctor-fmgb3d28.js +0 -190
- package/dist/durable-object-t4kbb0yt.js +0 -13
- package/dist/index-07q6yxyc.js +0 -168
- package/dist/index-18hvb6gb.js +0 -194
- package/dist/index-1xpj0m4r.js +0 -57
- package/dist/index-37x76zdn.js +0 -4
- package/dist/index-3t6rypgc.js +0 -13
- package/dist/index-67qcae0f.js +0 -183
- package/dist/index-a855bdsx.js +0 -18
- package/dist/index-d8bdkx2h.js +0 -109
- package/dist/index-ep3445yc.js +0 -2225
- package/dist/index-gz1gndna.js +0 -307
- package/dist/index-hcex3rgh.js +0 -266
- package/dist/index-m2q41jwa.js +0 -462
- package/dist/index-n7rs26ft.js +0 -77
- package/dist/index-pf5s73n9.js +0 -1413
- package/dist/index-rbht7m9r.js +0 -36
- package/dist/index-tfyxa77h.js +0 -850
- package/dist/index-tk6ej9dj.js +0 -94
- package/dist/index-z14anrqp.js +0 -226
- package/dist/init-f9mgmew3.js +0 -186
- package/dist/remote-q59qk463.js +0 -97
- package/dist/test/bridge-context.d.ts +0 -76
- package/dist/test/bridge-context.d.ts.map +0 -1
- package/dist/test/multi-worker-context.d.ts +0 -114
- package/dist/test/multi-worker-context.d.ts.map +0 -1
- package/dist/types-5nyrz1sz.js +0 -454
- package/dist/worker-entrypoint-m9th0rg0.js +0 -13
|
@@ -0,0 +1,2250 @@
|
|
|
1
|
+
import { wrapEnvSendEmailBindings } from "../utils/send-email.js";
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
//#region src/bridge/log.ts
|
|
4
|
+
const isDebugEnabled = () => {
|
|
5
|
+
try {
|
|
6
|
+
const env = globalThis.process?.env;
|
|
7
|
+
return Boolean(env?.DEVFLARE_DEBUG_BRIDGE);
|
|
8
|
+
} catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const bridgeLog = {
|
|
13
|
+
warn(message, error) {
|
|
14
|
+
if (!isDebugEnabled()) return;
|
|
15
|
+
console.warn(`[devflare:bridge] ${message}`, error);
|
|
16
|
+
},
|
|
17
|
+
debug(message, error) {
|
|
18
|
+
if (!isDebugEnabled()) return;
|
|
19
|
+
console.debug(`[devflare:bridge] ${message}`, error);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
/** WebSocket close code used when v2 ↔ v1 mismatch is detected at handshake. */
|
|
23
|
+
const TRANSPORT_V2_UNSUPPORTED_VERSION_CLOSE_CODE = 4001;
|
|
24
|
+
/**
|
|
25
|
+
* Binary frame kinds for v2. Values 1 (StreamChunk) and 2 (WsData) are
|
|
26
|
+
* deliberately stable with v1 so a future shared decoder can route either
|
|
27
|
+
* version's frames. Value 3 (BodyChunk) is new in v2 for HTTP body streams.
|
|
28
|
+
*/
|
|
29
|
+
const TransportV2BinaryKind = {
|
|
30
|
+
StreamChunk: 1,
|
|
31
|
+
WsData: 2,
|
|
32
|
+
BodyChunk: 3
|
|
33
|
+
};
|
|
34
|
+
/** Binary frame flags for v2. */
|
|
35
|
+
const TransportV2BinaryFlags = {
|
|
36
|
+
FIN: 1,
|
|
37
|
+
TEXT: 2,
|
|
38
|
+
ABORT: 4
|
|
39
|
+
};
|
|
40
|
+
/** Decode a v2 binary frame. Pure; returns a view that aliases the input bytes. */
|
|
41
|
+
function decodeTransportV2BinaryFrame(frame) {
|
|
42
|
+
if (frame.byteLength < 10) throw new Error(`Invalid transport v2 binary frame: too short (${frame.byteLength} bytes, need at least 10)`);
|
|
43
|
+
const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
|
|
44
|
+
const kind = view.getUint8(0);
|
|
45
|
+
if (kind !== TransportV2BinaryKind.StreamChunk && kind !== TransportV2BinaryKind.WsData && kind !== TransportV2BinaryKind.BodyChunk) throw new Error(`Invalid transport v2 binary frame: unknown kind ${kind}`);
|
|
46
|
+
return {
|
|
47
|
+
kind,
|
|
48
|
+
id: view.getUint32(1, true),
|
|
49
|
+
seq: view.getUint32(5, true),
|
|
50
|
+
flags: view.getUint8(9),
|
|
51
|
+
payload: frame.subarray(10)
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** True when the FIN flag is set on a v2 binary frame. */
|
|
55
|
+
function transportV2IsFin(flags) {
|
|
56
|
+
return (flags & TransportV2BinaryFlags.FIN) !== 0;
|
|
57
|
+
}
|
|
58
|
+
/** True when the ABORT flag is set on a v2 binary frame. */
|
|
59
|
+
function transportV2IsAbort(flags) {
|
|
60
|
+
return (flags & TransportV2BinaryFlags.ABORT) !== 0;
|
|
61
|
+
}
|
|
62
|
+
const KNOWN_V2_CONTROL_TYPES = new Set([
|
|
63
|
+
"hello",
|
|
64
|
+
"welcome",
|
|
65
|
+
"body.open",
|
|
66
|
+
"body.end",
|
|
67
|
+
"body.abort"
|
|
68
|
+
]);
|
|
69
|
+
/**
|
|
70
|
+
* Parse a JSON string as a v2-specific control message. Returns the typed
|
|
71
|
+
* message or throws if the payload is not a recognised v2 control type.
|
|
72
|
+
*
|
|
73
|
+
* Callers that need to multiplex v1 `JsonMsg` and v2 control messages should
|
|
74
|
+
* inspect the `t` field first and dispatch accordingly; this helper is
|
|
75
|
+
* deliberately strict so that v2-only code paths never silently accept v1
|
|
76
|
+
* payloads.
|
|
77
|
+
*/
|
|
78
|
+
function parseTransportV2ControlMsg(data) {
|
|
79
|
+
const msg = JSON.parse(data);
|
|
80
|
+
if (typeof msg !== "object" || msg === null || !("t" in msg)) throw new Error("Invalid transport v2 control message: missing type field");
|
|
81
|
+
if (!KNOWN_V2_CONTROL_TYPES.has(msg.t)) throw new Error(`Invalid transport v2 control message: unknown type "${msg.t}"`);
|
|
82
|
+
if (msg.t === "hello" || msg.t === "welcome") {
|
|
83
|
+
if (msg.protocolVersion !== 2) throw new Error(`Invalid transport v2 ${msg.t}: protocolVersion ${msg.protocolVersion} != 2`);
|
|
84
|
+
if (!Array.isArray(msg.capabilities)) throw new Error(`Invalid transport v2 ${msg.t}: capabilities must be an array`);
|
|
85
|
+
}
|
|
86
|
+
return msg;
|
|
87
|
+
}
|
|
88
|
+
/** Stringify a v2 control message. Pure. */
|
|
89
|
+
function stringifyTransportV2ControlMsg(msg) {
|
|
90
|
+
return JSON.stringify(msg);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Compute the capability intersection a server should announce in its
|
|
94
|
+
* `welcome` reply, given its own supported set and the client's `hello`
|
|
95
|
+
* advertisement. Order is deterministic (sorted) so the wire output is
|
|
96
|
+
* reproducible across runs.
|
|
97
|
+
*/
|
|
98
|
+
function negotiateTransportV2Capabilities(supported, advertised) {
|
|
99
|
+
const supportedSet = new Set(supported);
|
|
100
|
+
const intersection = advertised.filter((cap) => supportedSet.has(cap));
|
|
101
|
+
return [...new Set(intersection)].sort();
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/bridge/v2/body-streams.ts
|
|
105
|
+
/**
|
|
106
|
+
* Tracks in-flight v2 body streams on the reader side. The codec routes
|
|
107
|
+
* incoming `body.open` / `body.end` / `body.abort` control messages and
|
|
108
|
+
* `BodyChunk` binary frames here; consumers of v2 RPC results obtain a
|
|
109
|
+
* `ReadableStream<Uint8Array>` to attach to a `Request` / `Response`.
|
|
110
|
+
*/
|
|
111
|
+
var TransportV2BodyReaderRegistry = class {
|
|
112
|
+
#streams = /* @__PURE__ */ new Map();
|
|
113
|
+
/** Register a new body stream and return the reader-side `ReadableStream`. Idempotent: returns the existing stream if `bid` is already registered. */
|
|
114
|
+
getOrOpen(bid) {
|
|
115
|
+
const existing = this.#streams.get(bid);
|
|
116
|
+
if (existing !== void 0) return existing.stream;
|
|
117
|
+
return this.open(bid);
|
|
118
|
+
}
|
|
119
|
+
/** Register a new body stream and return the reader-side `ReadableStream`. Throws if `bid` is already registered. */
|
|
120
|
+
open(bid) {
|
|
121
|
+
if (this.#streams.has(bid)) throw new Error(`v2 body reader already registered for bid ${bid}`);
|
|
122
|
+
const state = {
|
|
123
|
+
controller: null,
|
|
124
|
+
stream: null,
|
|
125
|
+
closed: false
|
|
126
|
+
};
|
|
127
|
+
state.stream = new ReadableStream({
|
|
128
|
+
start: (controller) => {
|
|
129
|
+
state.controller = controller;
|
|
130
|
+
},
|
|
131
|
+
cancel: () => {
|
|
132
|
+
state.closed = true;
|
|
133
|
+
this.#streams.delete(bid);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
this.#streams.set(bid, state);
|
|
137
|
+
return state.stream;
|
|
138
|
+
}
|
|
139
|
+
/** Push a decoded BodyChunk frame to the matching reader. */
|
|
140
|
+
pushChunk(frame) {
|
|
141
|
+
if (frame.kind !== TransportV2BinaryKind.BodyChunk) throw new Error(`v2 body reader received non-BodyChunk frame (kind=${frame.kind})`);
|
|
142
|
+
const state = this.#streams.get(frame.id);
|
|
143
|
+
if (state === void 0 || state.closed) return;
|
|
144
|
+
const isFin = transportV2IsFin(frame.flags);
|
|
145
|
+
if (transportV2IsAbort(frame.flags)) {
|
|
146
|
+
state.closed = true;
|
|
147
|
+
state.controller?.error(/* @__PURE__ */ new Error(`v2 body stream ${frame.id} aborted by writer`));
|
|
148
|
+
this.#streams.delete(frame.id);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (frame.payload.byteLength > 0) state.controller?.enqueue(new Uint8Array(frame.payload));
|
|
152
|
+
if (isFin) {
|
|
153
|
+
state.closed = true;
|
|
154
|
+
state.controller?.close();
|
|
155
|
+
this.#streams.delete(frame.id);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/** Handle a `body.end` control message (writer signalled clean end). */
|
|
159
|
+
end(bid) {
|
|
160
|
+
const state = this.#streams.get(bid);
|
|
161
|
+
if (state === void 0 || state.closed) return;
|
|
162
|
+
state.closed = true;
|
|
163
|
+
state.controller?.close();
|
|
164
|
+
this.#streams.delete(bid);
|
|
165
|
+
}
|
|
166
|
+
/** Handle a `body.abort` control message. */
|
|
167
|
+
abort(bid, reason) {
|
|
168
|
+
const state = this.#streams.get(bid);
|
|
169
|
+
if (state === void 0 || state.closed) return;
|
|
170
|
+
state.closed = true;
|
|
171
|
+
state.controller?.error(new Error(reason ?? `v2 body stream ${bid} aborted`));
|
|
172
|
+
this.#streams.delete(bid);
|
|
173
|
+
}
|
|
174
|
+
/** Number of currently open reader-side body streams (for tests/diagnostics). */
|
|
175
|
+
get size() {
|
|
176
|
+
return this.#streams.size;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
//#endregion
|
|
180
|
+
//#region src/bridge/v2/codec.ts
|
|
181
|
+
/**
|
|
182
|
+
* v2 codec attached to a single `WebSocketLike`. Owns handshake state, the
|
|
183
|
+
* frame demultiplexer, RPC pending-call table, and the body-stream registry.
|
|
184
|
+
*/
|
|
185
|
+
var TransportV2Codec = class {
|
|
186
|
+
bodyReaders = new TransportV2BodyReaderRegistry();
|
|
187
|
+
#socket;
|
|
188
|
+
#capabilities;
|
|
189
|
+
#options;
|
|
190
|
+
#handshakeResolver = null;
|
|
191
|
+
#handshakePromise;
|
|
192
|
+
#sentHello = false;
|
|
193
|
+
#receivedHello = false;
|
|
194
|
+
#receivedWelcome = false;
|
|
195
|
+
#negotiated = null;
|
|
196
|
+
#pendingRpc = /* @__PURE__ */ new Map();
|
|
197
|
+
#nextBid = 1;
|
|
198
|
+
#nextRpcId = 1;
|
|
199
|
+
#closed = false;
|
|
200
|
+
constructor(socket, options = {}) {
|
|
201
|
+
this.#socket = socket;
|
|
202
|
+
this.#capabilities = options.capabilities ?? [];
|
|
203
|
+
this.#options = options;
|
|
204
|
+
this.#handshakePromise = new Promise((resolve, reject) => {
|
|
205
|
+
this.#handshakeResolver = {
|
|
206
|
+
resolve,
|
|
207
|
+
reject
|
|
208
|
+
};
|
|
209
|
+
});
|
|
210
|
+
socket.onmessage = (event) => this.#onMessage(event);
|
|
211
|
+
socket.onclose = () => this.#onClose();
|
|
212
|
+
socket.onerror = (event) => this.#onError(event.error);
|
|
213
|
+
}
|
|
214
|
+
/** Allocate a fresh body id (writer side). */
|
|
215
|
+
allocateBid() {
|
|
216
|
+
return this.#nextBid++;
|
|
217
|
+
}
|
|
218
|
+
/** Allocate a fresh RPC id (caller side). */
|
|
219
|
+
allocateRpcId() {
|
|
220
|
+
return `v2_rpc_${this.#nextRpcId++}`;
|
|
221
|
+
}
|
|
222
|
+
/** Send the `hello` frame. Called once by the side that initiates the handshake. */
|
|
223
|
+
sendHello() {
|
|
224
|
+
if (this.#sentHello) return;
|
|
225
|
+
this.#sentHello = true;
|
|
226
|
+
const hello = {
|
|
227
|
+
t: "hello",
|
|
228
|
+
protocolVersion: 2,
|
|
229
|
+
capabilities: [...this.#capabilities]
|
|
230
|
+
};
|
|
231
|
+
this.#socket.send(stringifyTransportV2ControlMsg(hello));
|
|
232
|
+
}
|
|
233
|
+
/** Promise that resolves once the handshake completes. */
|
|
234
|
+
get handshake() {
|
|
235
|
+
return this.#handshakePromise;
|
|
236
|
+
}
|
|
237
|
+
/** Negotiated capabilities once the handshake completes. */
|
|
238
|
+
get negotiated() {
|
|
239
|
+
return this.#negotiated;
|
|
240
|
+
}
|
|
241
|
+
sendText(message) {
|
|
242
|
+
if (this.#closed) throw new Error("cannot send on a closed v2 codec");
|
|
243
|
+
this.#socket.send(message);
|
|
244
|
+
}
|
|
245
|
+
sendBinary(frame) {
|
|
246
|
+
if (this.#closed) throw new Error("cannot send on a closed v2 codec");
|
|
247
|
+
this.#socket.send(frame);
|
|
248
|
+
}
|
|
249
|
+
/** Send a typed RPC call and resolve with the peer's `rpc.ok` result. */
|
|
250
|
+
call(method, params = []) {
|
|
251
|
+
const id = this.allocateRpcId();
|
|
252
|
+
const call = {
|
|
253
|
+
t: "rpc.call",
|
|
254
|
+
id,
|
|
255
|
+
method,
|
|
256
|
+
params
|
|
257
|
+
};
|
|
258
|
+
const promise = new Promise((resolve, reject) => {
|
|
259
|
+
this.#pendingRpc.set(id, {
|
|
260
|
+
resolve,
|
|
261
|
+
reject
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
this.sendText(JSON.stringify(call));
|
|
265
|
+
return promise;
|
|
266
|
+
}
|
|
267
|
+
/** Send an `rpc.ok` reply for a previously-received call. */
|
|
268
|
+
respondOk(id, result) {
|
|
269
|
+
const reply = {
|
|
270
|
+
t: "rpc.ok",
|
|
271
|
+
id,
|
|
272
|
+
result
|
|
273
|
+
};
|
|
274
|
+
this.sendText(JSON.stringify(reply));
|
|
275
|
+
}
|
|
276
|
+
/** Send an `rpc.err` reply for a previously-received call. */
|
|
277
|
+
respondErr(id, error) {
|
|
278
|
+
const reply = {
|
|
279
|
+
t: "rpc.err",
|
|
280
|
+
id,
|
|
281
|
+
error
|
|
282
|
+
};
|
|
283
|
+
this.sendText(JSON.stringify(reply));
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Send an out-of-band structured `error` frame (B5-frame). Use for
|
|
287
|
+
* failures that are not scoped to a single RPC call id — e.g. malformed
|
|
288
|
+
* incoming frames, stream/ws aborts that need a typed cause, or gateway
|
|
289
|
+
* bookkeeping errors. Replaces silent `catch {}` fallthroughs.
|
|
290
|
+
*/
|
|
291
|
+
sendWireError(err) {
|
|
292
|
+
const frame = {
|
|
293
|
+
t: "error",
|
|
294
|
+
...err
|
|
295
|
+
};
|
|
296
|
+
this.sendText(JSON.stringify(frame));
|
|
297
|
+
}
|
|
298
|
+
/** Register a reader-side body stream. Returns the `ReadableStream`. Idempotent across the codec's `body.open` arrival. */
|
|
299
|
+
openBodyReader(bid) {
|
|
300
|
+
return this.bodyReaders.getOrOpen(bid);
|
|
301
|
+
}
|
|
302
|
+
/** Replace the `onRpcCall` handler after construction. Useful for one-shot tests and for higher RPC layers that build the handler lazily. */
|
|
303
|
+
setRpcCallHandler(handler) {
|
|
304
|
+
this.#options = {
|
|
305
|
+
...this.#options,
|
|
306
|
+
onRpcCall: handler
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
/** Close the underlying transport with an optional code/reason. */
|
|
310
|
+
close(code, reason) {
|
|
311
|
+
if (this.#closed) return;
|
|
312
|
+
this.#closed = true;
|
|
313
|
+
this.#failPending(/* @__PURE__ */ new Error("v2 transport closed"));
|
|
314
|
+
this.#socket.close(code, reason);
|
|
315
|
+
}
|
|
316
|
+
get isClosed() {
|
|
317
|
+
return this.#closed;
|
|
318
|
+
}
|
|
319
|
+
#onMessage(event) {
|
|
320
|
+
const { data } = event;
|
|
321
|
+
if (typeof data === "string") this.#onText(data);
|
|
322
|
+
else if (data instanceof Uint8Array) this.#onBinary(data);
|
|
323
|
+
else if (data instanceof ArrayBuffer) this.#onBinary(new Uint8Array(data));
|
|
324
|
+
}
|
|
325
|
+
#onText(data) {
|
|
326
|
+
let msg;
|
|
327
|
+
try {
|
|
328
|
+
msg = parseTransportV2ControlMsg(data);
|
|
329
|
+
} catch {
|
|
330
|
+
const rpc = tryParseRpcMsg(data);
|
|
331
|
+
if (rpc !== null) {
|
|
332
|
+
this.#onRpcMessage(rpc);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const wireErr = tryParseWireError(data);
|
|
336
|
+
if (wireErr !== null) {
|
|
337
|
+
this.#options.onWireError?.(wireErr);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
this.#options.onUnknownControl?.(data);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
switch (msg.t) {
|
|
344
|
+
case "hello":
|
|
345
|
+
this.#onHello(msg);
|
|
346
|
+
break;
|
|
347
|
+
case "welcome":
|
|
348
|
+
this.#onWelcome(msg);
|
|
349
|
+
break;
|
|
350
|
+
case "body.open":
|
|
351
|
+
this.bodyReaders.getOrOpen(msg.bid);
|
|
352
|
+
break;
|
|
353
|
+
case "body.end":
|
|
354
|
+
this.bodyReaders.end(msg.bid);
|
|
355
|
+
break;
|
|
356
|
+
case "body.abort":
|
|
357
|
+
this.bodyReaders.abort(msg.bid, msg.error);
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
#onBinary(data) {
|
|
362
|
+
let frame;
|
|
363
|
+
try {
|
|
364
|
+
frame = decodeTransportV2BinaryFrame(data);
|
|
365
|
+
} catch {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
if (frame.kind === TransportV2BinaryKind.BodyChunk) {
|
|
369
|
+
this.bodyReaders.pushChunk(frame);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
this.#options.onUnknownBinary?.(frame);
|
|
373
|
+
}
|
|
374
|
+
#onRpcMessage(msg) {
|
|
375
|
+
switch (msg.t) {
|
|
376
|
+
case "rpc.call":
|
|
377
|
+
this.#options.onRpcCall?.(msg);
|
|
378
|
+
break;
|
|
379
|
+
case "rpc.ok": {
|
|
380
|
+
const pending = this.#pendingRpc.get(msg.id);
|
|
381
|
+
if (pending !== void 0) {
|
|
382
|
+
this.#pendingRpc.delete(msg.id);
|
|
383
|
+
pending.resolve(msg.result);
|
|
384
|
+
}
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
case "rpc.err": {
|
|
388
|
+
const pending = this.#pendingRpc.get(msg.id);
|
|
389
|
+
if (pending !== void 0) {
|
|
390
|
+
this.#pendingRpc.delete(msg.id);
|
|
391
|
+
const err = new Error(msg.error.message);
|
|
392
|
+
Object.assign(err, {
|
|
393
|
+
code: msg.error.code,
|
|
394
|
+
details: msg.error.details
|
|
395
|
+
});
|
|
396
|
+
pending.reject(err);
|
|
397
|
+
}
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
#onHello(msg) {
|
|
403
|
+
if (this.#receivedHello) {
|
|
404
|
+
this.close(TRANSPORT_V2_UNSUPPORTED_VERSION_CLOSE_CODE, "duplicate hello");
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
this.#receivedHello = true;
|
|
408
|
+
const negotiated = negotiateTransportV2Capabilities(this.#capabilities, msg.capabilities);
|
|
409
|
+
const welcome = {
|
|
410
|
+
t: "welcome",
|
|
411
|
+
protocolVersion: 2,
|
|
412
|
+
capabilities: negotiated
|
|
413
|
+
};
|
|
414
|
+
this.#socket.send(stringifyTransportV2ControlMsg(welcome));
|
|
415
|
+
this.#completeHandshake({
|
|
416
|
+
protocolVersion: 2,
|
|
417
|
+
capabilities: negotiated
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
#onWelcome(msg) {
|
|
421
|
+
if (this.#receivedWelcome) return;
|
|
422
|
+
this.#receivedWelcome = true;
|
|
423
|
+
this.#completeHandshake({
|
|
424
|
+
protocolVersion: 2,
|
|
425
|
+
capabilities: msg.capabilities
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
#completeHandshake(result) {
|
|
429
|
+
if (this.#negotiated !== null) return;
|
|
430
|
+
this.#negotiated = result;
|
|
431
|
+
this.#handshakeResolver?.resolve(result);
|
|
432
|
+
this.#handshakeResolver = null;
|
|
433
|
+
}
|
|
434
|
+
#onClose() {
|
|
435
|
+
if (this.#closed) return;
|
|
436
|
+
this.#closed = true;
|
|
437
|
+
this.#failPending(/* @__PURE__ */ new Error("v2 transport closed"));
|
|
438
|
+
}
|
|
439
|
+
#onError(error) {
|
|
440
|
+
const wrapped = error instanceof Error ? error : new Error(String(error));
|
|
441
|
+
this.#failPending(wrapped);
|
|
442
|
+
}
|
|
443
|
+
#failPending(error) {
|
|
444
|
+
const resolver = this.#handshakeResolver;
|
|
445
|
+
if (resolver !== null) {
|
|
446
|
+
this.#handshakeResolver = null;
|
|
447
|
+
resolver.reject(error);
|
|
448
|
+
}
|
|
449
|
+
for (const pending of this.#pendingRpc.values()) pending.reject(error);
|
|
450
|
+
this.#pendingRpc.clear();
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
function tryParseRpcMsg(data) {
|
|
454
|
+
let parsed;
|
|
455
|
+
try {
|
|
456
|
+
parsed = JSON.parse(data);
|
|
457
|
+
} catch {
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
if (typeof parsed !== "object" || parsed === null || !("t" in parsed)) return null;
|
|
461
|
+
const t = parsed.t;
|
|
462
|
+
if (t === "rpc.call" || t === "rpc.ok" || t === "rpc.err") return parsed;
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
function tryParseWireError(data) {
|
|
466
|
+
let parsed;
|
|
467
|
+
try {
|
|
468
|
+
parsed = JSON.parse(data);
|
|
469
|
+
} catch {
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
if (typeof parsed !== "object" || parsed === null || !("t" in parsed)) return null;
|
|
473
|
+
const candidate = parsed;
|
|
474
|
+
if (candidate.t !== "error") return null;
|
|
475
|
+
const scope = candidate.scope;
|
|
476
|
+
if (scope !== "transport" && scope !== "rpc" && scope !== "stream" && scope !== "ws") return null;
|
|
477
|
+
const err = candidate.error;
|
|
478
|
+
if (!err || typeof err.code !== "string" || typeof err.message !== "string") return null;
|
|
479
|
+
return parsed;
|
|
480
|
+
}
|
|
481
|
+
//#endregion
|
|
482
|
+
//#region src/bridge/v2/wire.ts
|
|
483
|
+
/** Binary frame kinds */
|
|
484
|
+
const BinaryKind = {
|
|
485
|
+
StreamChunk: 1,
|
|
486
|
+
WsData: 2
|
|
487
|
+
};
|
|
488
|
+
/** Binary frame flags */
|
|
489
|
+
const BinaryFlags = {
|
|
490
|
+
FIN: 1,
|
|
491
|
+
TEXT: 2
|
|
492
|
+
};
|
|
493
|
+
/** Encode a binary frame */
|
|
494
|
+
function encodeBinaryFrame(kind, id, seq, flags, payload) {
|
|
495
|
+
const frame = new Uint8Array(10 + payload.byteLength);
|
|
496
|
+
const view = new DataView(frame.buffer);
|
|
497
|
+
view.setUint8(0, kind);
|
|
498
|
+
view.setUint32(1, id, true);
|
|
499
|
+
view.setUint32(5, seq, true);
|
|
500
|
+
view.setUint8(9, flags);
|
|
501
|
+
frame.set(payload, 10);
|
|
502
|
+
return frame;
|
|
503
|
+
}
|
|
504
|
+
/** Parse a JSON message from string */
|
|
505
|
+
function parseJsonMsg(data) {
|
|
506
|
+
const msg = JSON.parse(data);
|
|
507
|
+
if (typeof msg !== "object" || msg === null || !("t" in msg)) throw new Error("Invalid message: missing type field");
|
|
508
|
+
return msg;
|
|
509
|
+
}
|
|
510
|
+
/** Stringify a JSON message */
|
|
511
|
+
function stringifyJsonMsg(msg) {
|
|
512
|
+
return JSON.stringify(msg);
|
|
513
|
+
}
|
|
514
|
+
let streamIdCounter = 0;
|
|
515
|
+
let wsIdCounter = 0;
|
|
516
|
+
/** Generate unique stream ID */
|
|
517
|
+
function nextStreamId() {
|
|
518
|
+
return ++streamIdCounter;
|
|
519
|
+
}
|
|
520
|
+
/** Generate unique WebSocket proxy ID */
|
|
521
|
+
function nextWsId() {
|
|
522
|
+
return ++wsIdCounter;
|
|
523
|
+
}
|
|
524
|
+
/** Default chunk size for streaming (256 KB) */
|
|
525
|
+
const DEFAULT_CHUNK_SIZE = 256 * 1024;
|
|
526
|
+
/** Threshold for switching to HTTP transfer (512 KB — workerd ~1MB WS message limit). */
|
|
527
|
+
const HTTP_TRANSFER_THRESHOLD = 512 * 1024;
|
|
528
|
+
//#endregion
|
|
529
|
+
//#region src/bridge/v2/value-serialization.ts
|
|
530
|
+
/** Serialize a Request to a POJO */
|
|
531
|
+
async function serializeRequest(request, options) {
|
|
532
|
+
const streams = [];
|
|
533
|
+
const threshold = options?.httpThreshold ?? 524288;
|
|
534
|
+
const headers = [];
|
|
535
|
+
request.headers.forEach((value, key) => {
|
|
536
|
+
headers.push([key, value]);
|
|
537
|
+
});
|
|
538
|
+
let body = null;
|
|
539
|
+
if (request.body) {
|
|
540
|
+
const bytes = await request.arrayBuffer();
|
|
541
|
+
if (bytes.byteLength > threshold) 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.");
|
|
542
|
+
if (bytes.byteLength > 0) body = {
|
|
543
|
+
type: "bytes",
|
|
544
|
+
data: base64Encode(new Uint8Array(bytes))
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
return {
|
|
548
|
+
serialized: {
|
|
549
|
+
url: request.url,
|
|
550
|
+
method: request.method,
|
|
551
|
+
headers,
|
|
552
|
+
body,
|
|
553
|
+
redirect: request.redirect
|
|
554
|
+
},
|
|
555
|
+
streams
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
/** Deserialize a Request from a POJO */
|
|
559
|
+
function deserializeRequest(serialized, getStream) {
|
|
560
|
+
let body = null;
|
|
561
|
+
if (serialized.body) switch (serialized.body.type) {
|
|
562
|
+
case "bytes":
|
|
563
|
+
body = base64Decode(serialized.body.data);
|
|
564
|
+
break;
|
|
565
|
+
case "stream":
|
|
566
|
+
if (getStream) body = getStream(serialized.body.sid) ?? null;
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
569
|
+
return new Request(serialized.url, {
|
|
570
|
+
method: serialized.method,
|
|
571
|
+
headers: serialized.headers,
|
|
572
|
+
body,
|
|
573
|
+
redirect: serialized.redirect
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
/** Serialize a Response to a POJO */
|
|
577
|
+
async function serializeResponse(response, options) {
|
|
578
|
+
const streams = [];
|
|
579
|
+
const threshold = options?.httpThreshold ?? 524288;
|
|
580
|
+
const headers = [];
|
|
581
|
+
response.headers.forEach((value, key) => {
|
|
582
|
+
headers.push([key, value]);
|
|
583
|
+
});
|
|
584
|
+
let body = null;
|
|
585
|
+
if (response.body) {
|
|
586
|
+
const bytes = await response.arrayBuffer();
|
|
587
|
+
if (bytes.byteLength > threshold) {
|
|
588
|
+
const sid = nextStreamId();
|
|
589
|
+
const payload = new Uint8Array(bytes);
|
|
590
|
+
const frameSize = HTTP_TRANSFER_THRESHOLD;
|
|
591
|
+
const stream = new ReadableStream({ start(controller) {
|
|
592
|
+
for (let offset = 0; offset < payload.byteLength; offset += frameSize) controller.enqueue(payload.slice(offset, Math.min(offset + frameSize, payload.byteLength)));
|
|
593
|
+
controller.close();
|
|
594
|
+
} });
|
|
595
|
+
streams.push({
|
|
596
|
+
sid,
|
|
597
|
+
stream
|
|
598
|
+
});
|
|
599
|
+
body = {
|
|
600
|
+
type: "stream",
|
|
601
|
+
sid
|
|
602
|
+
};
|
|
603
|
+
} else if (bytes.byteLength > 0) body = {
|
|
604
|
+
type: "bytes",
|
|
605
|
+
data: base64Encode(new Uint8Array(bytes))
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
return {
|
|
609
|
+
serialized: {
|
|
610
|
+
status: response.status,
|
|
611
|
+
statusText: response.statusText,
|
|
612
|
+
headers,
|
|
613
|
+
body
|
|
614
|
+
},
|
|
615
|
+
streams
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
/** Deserialize a Response from a POJO */
|
|
619
|
+
function deserializeResponse(serialized, getStream) {
|
|
620
|
+
let body = null;
|
|
621
|
+
if (serialized.body) switch (serialized.body.type) {
|
|
622
|
+
case "bytes":
|
|
623
|
+
body = base64Decode(serialized.body.data);
|
|
624
|
+
break;
|
|
625
|
+
case "stream":
|
|
626
|
+
if (getStream) body = getStream(serialized.body.sid) ?? null;
|
|
627
|
+
break;
|
|
628
|
+
}
|
|
629
|
+
return new Response(body, {
|
|
630
|
+
status: serialized.status,
|
|
631
|
+
statusText: serialized.statusText,
|
|
632
|
+
headers: serialized.headers
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
/** Serialize a value that may contain special types */
|
|
636
|
+
async function serializeValue(value, options) {
|
|
637
|
+
const streams = [];
|
|
638
|
+
return {
|
|
639
|
+
value: await serializeValueInternal(value, streams, options),
|
|
640
|
+
streams
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
async function serializeValueInternal(value, streams, options) {
|
|
644
|
+
if (value === null || value === void 0) return value;
|
|
645
|
+
if (value instanceof Request) {
|
|
646
|
+
const { serialized, streams: reqStreams } = await serializeRequest(value, options);
|
|
647
|
+
streams.push(...reqStreams);
|
|
648
|
+
return {
|
|
649
|
+
__type: "Request",
|
|
650
|
+
...serialized
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
if (value instanceof Response) {
|
|
654
|
+
const { serialized, streams: resStreams } = await serializeResponse(value, options);
|
|
655
|
+
streams.push(...resStreams);
|
|
656
|
+
return {
|
|
657
|
+
__type: "Response",
|
|
658
|
+
...serialized
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
if (value instanceof ReadableStream) {
|
|
662
|
+
const sid = nextStreamId();
|
|
663
|
+
streams.push({
|
|
664
|
+
sid,
|
|
665
|
+
stream: value
|
|
666
|
+
});
|
|
667
|
+
return {
|
|
668
|
+
__type: "ReadableStream",
|
|
669
|
+
sid
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
if (value instanceof Uint8Array) return {
|
|
673
|
+
__type: "Uint8Array",
|
|
674
|
+
data: base64Encode(value)
|
|
675
|
+
};
|
|
676
|
+
if (value instanceof ArrayBuffer) return {
|
|
677
|
+
__type: "ArrayBuffer",
|
|
678
|
+
data: base64Encode(new Uint8Array(value))
|
|
679
|
+
};
|
|
680
|
+
if (value instanceof Date) return {
|
|
681
|
+
__devflare: "date",
|
|
682
|
+
iso: value.toISOString()
|
|
683
|
+
};
|
|
684
|
+
if (value instanceof URL) return {
|
|
685
|
+
__devflare: "url",
|
|
686
|
+
href: value.href
|
|
687
|
+
};
|
|
688
|
+
if (value instanceof Error) {
|
|
689
|
+
const encoded = {
|
|
690
|
+
__devflare: "error",
|
|
691
|
+
name: value.name,
|
|
692
|
+
message: value.message
|
|
693
|
+
};
|
|
694
|
+
if (value.stack) encoded.stack = value.stack;
|
|
695
|
+
return encoded;
|
|
696
|
+
}
|
|
697
|
+
if (value instanceof Map) {
|
|
698
|
+
const entries = [];
|
|
699
|
+
for (const [k, v] of value.entries()) entries.push([await serializeValueInternal(k, streams, options), await serializeValueInternal(v, streams, options)]);
|
|
700
|
+
return {
|
|
701
|
+
__devflare: "map",
|
|
702
|
+
entries
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
if (value instanceof Set) {
|
|
706
|
+
const values = [];
|
|
707
|
+
for (const v of value.values()) values.push(await serializeValueInternal(v, streams, options));
|
|
708
|
+
return {
|
|
709
|
+
__devflare: "set",
|
|
710
|
+
values
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
if (Array.isArray(value)) return Promise.all(value.map((v) => serializeValueInternal(v, streams, options)));
|
|
714
|
+
if (typeof value === "object") {
|
|
715
|
+
const result = {};
|
|
716
|
+
for (const [k, v] of Object.entries(value)) result[k] = await serializeValueInternal(v, streams, options);
|
|
717
|
+
return result;
|
|
718
|
+
}
|
|
719
|
+
return value;
|
|
720
|
+
}
|
|
721
|
+
/** Deserialize a value that may contain special types */
|
|
722
|
+
function deserializeValue(value, getStream) {
|
|
723
|
+
if (value === null || value === void 0) return value;
|
|
724
|
+
if (typeof value === "object" && value !== null) {
|
|
725
|
+
const obj = value;
|
|
726
|
+
if (typeof obj.__devflare === "string") switch (obj.__devflare) {
|
|
727
|
+
case "date": return new Date(obj.iso);
|
|
728
|
+
case "url": return new URL(obj.href);
|
|
729
|
+
case "error": {
|
|
730
|
+
const err = new Error(obj.message);
|
|
731
|
+
if (typeof obj.name === "string") err.name = obj.name;
|
|
732
|
+
if (typeof obj.stack === "string") err.stack = obj.stack;
|
|
733
|
+
return err;
|
|
734
|
+
}
|
|
735
|
+
case "map": {
|
|
736
|
+
const entries = obj.entries ?? [];
|
|
737
|
+
const map = /* @__PURE__ */ new Map();
|
|
738
|
+
for (const [k, v] of entries) map.set(deserializeValue(k, getStream), deserializeValue(v, getStream));
|
|
739
|
+
return map;
|
|
740
|
+
}
|
|
741
|
+
case "set": {
|
|
742
|
+
const values = obj.values ?? [];
|
|
743
|
+
const set = /* @__PURE__ */ new Set();
|
|
744
|
+
for (const v of values) set.add(deserializeValue(v, getStream));
|
|
745
|
+
return set;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
if (obj.__type === "Request") return deserializeRequest(obj, getStream);
|
|
749
|
+
if (obj.__type === "Response") return deserializeResponse(obj, getStream);
|
|
750
|
+
if (obj.__type === "ReadableStream") {
|
|
751
|
+
const sid = obj.sid;
|
|
752
|
+
return getStream?.(sid) ?? null;
|
|
753
|
+
}
|
|
754
|
+
if (obj.__type === "Uint8Array") return base64Decode(obj.data);
|
|
755
|
+
if (obj.__type === "ArrayBuffer") return base64Decode(obj.data).buffer;
|
|
756
|
+
if (obj.__type === "R2Object") return deserializeR2Object(obj);
|
|
757
|
+
if (obj.__type === "R2ObjectBody") return deserializeR2ObjectBody(obj);
|
|
758
|
+
if (Array.isArray(value)) return value.map((v) => deserializeValue(v, getStream));
|
|
759
|
+
const result = {};
|
|
760
|
+
for (const [k, v] of Object.entries(obj)) result[k] = deserializeValue(v, getStream);
|
|
761
|
+
return result;
|
|
762
|
+
}
|
|
763
|
+
return value;
|
|
764
|
+
}
|
|
765
|
+
function applySerializedHttpMetadata(headers, httpMetadata) {
|
|
766
|
+
if (httpMetadata?.contentType) headers.set("Content-Type", httpMetadata.contentType);
|
|
767
|
+
if (httpMetadata?.contentLanguage) headers.set("Content-Language", httpMetadata.contentLanguage);
|
|
768
|
+
if (httpMetadata?.contentDisposition) headers.set("Content-Disposition", httpMetadata.contentDisposition);
|
|
769
|
+
if (httpMetadata?.contentEncoding) headers.set("Content-Encoding", httpMetadata.contentEncoding);
|
|
770
|
+
if (httpMetadata?.cacheControl) headers.set("Cache-Control", httpMetadata.cacheControl);
|
|
771
|
+
if (httpMetadata?.cacheExpiry) headers.set("Expires", new Date(httpMetadata.cacheExpiry).toUTCString());
|
|
772
|
+
}
|
|
773
|
+
function createSerializedR2Metadata(serialized) {
|
|
774
|
+
return {
|
|
775
|
+
key: serialized.key,
|
|
776
|
+
version: serialized.version,
|
|
777
|
+
size: serialized.size,
|
|
778
|
+
etag: serialized.etag,
|
|
779
|
+
httpEtag: serialized.httpEtag,
|
|
780
|
+
checksums: serialized.checksums,
|
|
781
|
+
uploaded: serialized.uploaded ? new Date(serialized.uploaded) : /* @__PURE__ */ new Date(),
|
|
782
|
+
httpMetadata: serialized.httpMetadata,
|
|
783
|
+
customMetadata: serialized.customMetadata,
|
|
784
|
+
range: serialized.range,
|
|
785
|
+
storageClass: serialized.storageClass,
|
|
786
|
+
writeHttpMetadata(headers) {
|
|
787
|
+
applySerializedHttpMetadata(headers, serialized.httpMetadata);
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
/** Deserialize R2Object (metadata only) */
|
|
792
|
+
function deserializeR2Object(obj) {
|
|
793
|
+
return { ...createSerializedR2Metadata(obj) };
|
|
794
|
+
}
|
|
795
|
+
/** Deserialize R2ObjectBody (with body data) */
|
|
796
|
+
function deserializeR2ObjectBody(obj) {
|
|
797
|
+
const serialized = obj;
|
|
798
|
+
const bodyBytes = serialized.bodyData ? base64Decode(serialized.bodyData) : new Uint8Array(0);
|
|
799
|
+
return {
|
|
800
|
+
...createSerializedR2Metadata(serialized),
|
|
801
|
+
body: new ReadableStream({ start(controller) {
|
|
802
|
+
controller.enqueue(bodyBytes);
|
|
803
|
+
controller.close();
|
|
804
|
+
} }),
|
|
805
|
+
bodyUsed: false,
|
|
806
|
+
async arrayBuffer() {
|
|
807
|
+
const copy = new Uint8Array(bodyBytes.byteLength);
|
|
808
|
+
copy.set(bodyBytes);
|
|
809
|
+
return copy.buffer;
|
|
810
|
+
},
|
|
811
|
+
async text() {
|
|
812
|
+
return new TextDecoder().decode(bodyBytes);
|
|
813
|
+
},
|
|
814
|
+
async json() {
|
|
815
|
+
const text = new TextDecoder().decode(bodyBytes);
|
|
816
|
+
return JSON.parse(text);
|
|
817
|
+
},
|
|
818
|
+
async blob() {
|
|
819
|
+
const contentType = serialized.httpMetadata?.contentType || "application/octet-stream";
|
|
820
|
+
const buffer = bodyBytes.buffer.slice(bodyBytes.byteOffset, bodyBytes.byteOffset + bodyBytes.byteLength);
|
|
821
|
+
return new Blob([buffer], { type: contentType });
|
|
822
|
+
}
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
/** Encode Uint8Array to base64 string */
|
|
826
|
+
function base64Encode(bytes) {
|
|
827
|
+
if (typeof Buffer !== "undefined") return Buffer.from(bytes).toString("base64");
|
|
828
|
+
let binary = "";
|
|
829
|
+
for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);
|
|
830
|
+
return btoa(binary);
|
|
831
|
+
}
|
|
832
|
+
/** Decode base64 string to Uint8Array */
|
|
833
|
+
function base64Decode(str) {
|
|
834
|
+
if (typeof Buffer !== "undefined") return new Uint8Array(Buffer.from(str, "base64"));
|
|
835
|
+
const binary = atob(str);
|
|
836
|
+
const bytes = new Uint8Array(binary.length);
|
|
837
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
838
|
+
return bytes;
|
|
839
|
+
}
|
|
840
|
+
//#endregion
|
|
841
|
+
//#region src/bridge/client.ts
|
|
842
|
+
var BridgeWsAdapter = class {
|
|
843
|
+
onmessage = null;
|
|
844
|
+
onclose = null;
|
|
845
|
+
onerror = null;
|
|
846
|
+
#ws;
|
|
847
|
+
constructor(ws) {
|
|
848
|
+
this.#ws = ws;
|
|
849
|
+
}
|
|
850
|
+
send(data) {
|
|
851
|
+
this.#ws.send(data);
|
|
852
|
+
}
|
|
853
|
+
close(code, reason) {
|
|
854
|
+
this.#ws.close(code, reason);
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
const BRIDGE_CLIENT_CAPABILITIES = [
|
|
858
|
+
"streams",
|
|
859
|
+
"ws-relay",
|
|
860
|
+
"http-transfer"
|
|
861
|
+
];
|
|
862
|
+
let wsPackageConstructorPromise = null;
|
|
863
|
+
async function importWsPackageConstructor() {
|
|
864
|
+
if (!wsPackageConstructorPromise) wsPackageConstructorPromise = (async () => {
|
|
865
|
+
const wsModule = await new Function("specifier", [
|
|
866
|
+
"return ",
|
|
867
|
+
"import",
|
|
868
|
+
"(specifier)"
|
|
869
|
+
].join(""))("ws");
|
|
870
|
+
const defaultExport = wsModule.default;
|
|
871
|
+
const wsConstructor = wsModule.WebSocket ?? (typeof defaultExport === "object" && defaultExport !== null ? defaultExport.WebSocket : void 0) ?? defaultExport;
|
|
872
|
+
if (typeof wsConstructor !== "function") throw new Error("Could not load a WebSocket client implementation from the ws package");
|
|
873
|
+
return wsConstructor;
|
|
874
|
+
})();
|
|
875
|
+
return wsPackageConstructorPromise;
|
|
876
|
+
}
|
|
877
|
+
function getRuntimeWebSocketConstructor(runtimeWebSocket = globalThis.WebSocket) {
|
|
878
|
+
if (typeof runtimeWebSocket === "function") return runtimeWebSocket;
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
var BridgeClient = class {
|
|
882
|
+
ws = null;
|
|
883
|
+
codec = null;
|
|
884
|
+
adapter = null;
|
|
885
|
+
url;
|
|
886
|
+
autoReconnect;
|
|
887
|
+
reconnectDelay;
|
|
888
|
+
connectTimeout;
|
|
889
|
+
activeStreams = /* @__PURE__ */ new Map();
|
|
890
|
+
wsProxies = /* @__PURE__ */ new Map();
|
|
891
|
+
pendingWsOpens = /* @__PURE__ */ new Map();
|
|
892
|
+
outgoingStreams = /* @__PURE__ */ new Map();
|
|
893
|
+
eventListeners = /* @__PURE__ */ new Map();
|
|
894
|
+
connectPromise = null;
|
|
895
|
+
isConnected = false;
|
|
896
|
+
constructor(options = {}) {
|
|
897
|
+
this.url = options.url ?? `ws://localhost:8787`;
|
|
898
|
+
this.autoReconnect = options.autoReconnect ?? true;
|
|
899
|
+
this.reconnectDelay = options.reconnectDelay ?? 1e3;
|
|
900
|
+
this.connectTimeout = options.connectTimeout ?? 5e3;
|
|
901
|
+
}
|
|
902
|
+
/** Get the WebSocket URL */
|
|
903
|
+
getUrl() {
|
|
904
|
+
return this.url;
|
|
905
|
+
}
|
|
906
|
+
/** Get the HTTP URL for transfer endpoint */
|
|
907
|
+
getHttpUrl() {
|
|
908
|
+
return this.url.replace(/^ws:\/\//, "http://").replace(/^wss:\/\//, "https://");
|
|
909
|
+
}
|
|
910
|
+
/** Connect to the bridge */
|
|
911
|
+
async connect() {
|
|
912
|
+
if (this.isConnected) return;
|
|
913
|
+
if (this.connectPromise) return this.connectPromise;
|
|
914
|
+
const WebSocketCtor = getRuntimeWebSocketConstructor();
|
|
915
|
+
const promise = WebSocketCtor ? this.openConnection(WebSocketCtor) : this.openConnectionWithPackageFallback();
|
|
916
|
+
this.connectPromise = promise;
|
|
917
|
+
promise.catch(() => {
|
|
918
|
+
if (this.connectPromise === promise) this.connectPromise = null;
|
|
919
|
+
});
|
|
920
|
+
return promise;
|
|
921
|
+
}
|
|
922
|
+
async openConnectionWithPackageFallback() {
|
|
923
|
+
const WebSocketCtor = await importWsPackageConstructor();
|
|
924
|
+
return this.openConnection(WebSocketCtor);
|
|
925
|
+
}
|
|
926
|
+
openConnection(WebSocketCtor) {
|
|
927
|
+
return new Promise((resolve, reject) => {
|
|
928
|
+
const timeout = setTimeout(() => {
|
|
929
|
+
reject(/* @__PURE__ */ new Error(`Connection timeout: ${this.url}`));
|
|
930
|
+
this.ws?.close();
|
|
931
|
+
}, this.connectTimeout);
|
|
932
|
+
try {
|
|
933
|
+
this.ws = new WebSocketCtor(this.url);
|
|
934
|
+
this.ws.binaryType = "arraybuffer";
|
|
935
|
+
const adapter = new BridgeWsAdapter(this.ws);
|
|
936
|
+
this.adapter = adapter;
|
|
937
|
+
this.ws.onopen = () => {
|
|
938
|
+
clearTimeout(timeout);
|
|
939
|
+
this.codec = new TransportV2Codec(adapter, {
|
|
940
|
+
capabilities: [...BRIDGE_CLIENT_CAPABILITIES],
|
|
941
|
+
onUnknownControl: (data) => this.handleJsonMessage(data),
|
|
942
|
+
onUnknownBinary: (frame) => this.handleV2BinaryFrame(frame)
|
|
943
|
+
});
|
|
944
|
+
this.codec.sendHello();
|
|
945
|
+
this.codec.handshake.catch(() => {});
|
|
946
|
+
this.isConnected = true;
|
|
947
|
+
this.connectPromise = null;
|
|
948
|
+
resolve();
|
|
949
|
+
};
|
|
950
|
+
this.ws.onerror = (event) => {
|
|
951
|
+
clearTimeout(timeout);
|
|
952
|
+
this.connectPromise = null;
|
|
953
|
+
adapter.onerror?.({ error: event.error });
|
|
954
|
+
reject(/* @__PURE__ */ new Error("WebSocket connection failed"));
|
|
955
|
+
};
|
|
956
|
+
this.ws.onclose = (event) => {
|
|
957
|
+
adapter.onclose?.({
|
|
958
|
+
code: event?.code ?? 1006,
|
|
959
|
+
reason: event?.reason ?? ""
|
|
960
|
+
});
|
|
961
|
+
this.handleDisconnect();
|
|
962
|
+
};
|
|
963
|
+
this.ws.onmessage = (event) => {
|
|
964
|
+
adapter.onmessage?.({ data: event.data });
|
|
965
|
+
};
|
|
966
|
+
} catch (error) {
|
|
967
|
+
clearTimeout(timeout);
|
|
968
|
+
this.connectPromise = null;
|
|
969
|
+
reject(error);
|
|
970
|
+
}
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
/** Disconnect from the bridge and tear down all pending state */
|
|
974
|
+
disconnect() {
|
|
975
|
+
this.autoReconnect = false;
|
|
976
|
+
this.codec?.close();
|
|
977
|
+
this.codec = null;
|
|
978
|
+
this.adapter = null;
|
|
979
|
+
this.ws?.close();
|
|
980
|
+
this.ws = null;
|
|
981
|
+
this.isConnected = false;
|
|
982
|
+
this.cleanupPending(/* @__PURE__ */ new Error("Bridge disconnected"));
|
|
983
|
+
this.eventListeners.clear();
|
|
984
|
+
}
|
|
985
|
+
/** Alias for disconnect() */
|
|
986
|
+
close() {
|
|
987
|
+
this.disconnect();
|
|
988
|
+
}
|
|
989
|
+
/** Check if connected */
|
|
990
|
+
get connected() {
|
|
991
|
+
return this.isConnected;
|
|
992
|
+
}
|
|
993
|
+
handleDisconnect() {
|
|
994
|
+
this.isConnected = false;
|
|
995
|
+
this.codec?.close();
|
|
996
|
+
this.codec = null;
|
|
997
|
+
this.adapter = null;
|
|
998
|
+
this.ws = null;
|
|
999
|
+
this.cleanupPending(/* @__PURE__ */ new Error("Bridge disconnected"));
|
|
1000
|
+
if (this.autoReconnect) setTimeout(() => {
|
|
1001
|
+
this.connect().catch((error) => {
|
|
1002
|
+
bridgeLog.warn("auto-reconnect attempt failed", error);
|
|
1003
|
+
});
|
|
1004
|
+
}, this.reconnectDelay);
|
|
1005
|
+
}
|
|
1006
|
+
/** Reject/close all pending streams and ws proxies (codec owns RPC pending). */
|
|
1007
|
+
cleanupPending(error) {
|
|
1008
|
+
for (const pending of this.pendingWsOpens.values()) pending.reject(error);
|
|
1009
|
+
this.pendingWsOpens.clear();
|
|
1010
|
+
for (const stream of this.activeStreams.values()) {
|
|
1011
|
+
stream.closed = true;
|
|
1012
|
+
if (stream.pendingPull) {
|
|
1013
|
+
stream.pendingPull.reject(error);
|
|
1014
|
+
stream.pendingPull = null;
|
|
1015
|
+
}
|
|
1016
|
+
try {
|
|
1017
|
+
stream.controller.error(error);
|
|
1018
|
+
} catch {}
|
|
1019
|
+
}
|
|
1020
|
+
this.activeStreams.clear();
|
|
1021
|
+
for (const proxy of this.wsProxies.values()) try {
|
|
1022
|
+
proxy.onClose(1006, error.message);
|
|
1023
|
+
} catch {}
|
|
1024
|
+
this.wsProxies.clear();
|
|
1025
|
+
this.outgoingStreams.clear();
|
|
1026
|
+
}
|
|
1027
|
+
/** Call an RPC method */
|
|
1028
|
+
async call(method, params, timeoutMs = 3e4) {
|
|
1029
|
+
await this.ensureConnected();
|
|
1030
|
+
const codec = this.codec;
|
|
1031
|
+
if (!codec) throw new Error("Bridge disconnected");
|
|
1032
|
+
const { value: serializedParams, streams } = await serializeValue(params);
|
|
1033
|
+
for (const streamRef of streams) this.outgoingStreams.set(streamRef.sid, streamRef);
|
|
1034
|
+
const callPromise = codec.call(method, serializedParams);
|
|
1035
|
+
let timeoutHandle = null;
|
|
1036
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1037
|
+
timeoutHandle = setTimeout(() => {
|
|
1038
|
+
reject(/* @__PURE__ */ new Error(`RPC timeout: ${method}`));
|
|
1039
|
+
}, timeoutMs);
|
|
1040
|
+
});
|
|
1041
|
+
try {
|
|
1042
|
+
return deserializeValue(await Promise.race([callPromise, timeoutPromise]), (sid) => this.createReadableStream(sid));
|
|
1043
|
+
} catch (error) {
|
|
1044
|
+
if (!this.isConnected && error instanceof Error && /v2 transport closed|transport/.test(error.message)) throw new Error("Bridge disconnected");
|
|
1045
|
+
throw error;
|
|
1046
|
+
} finally {
|
|
1047
|
+
if (timeoutHandle !== null) clearTimeout(timeoutHandle);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
/**
|
|
1051
|
+
* Subscribe to bridge `event` notifications for a topic.
|
|
1052
|
+
*
|
|
1053
|
+
* Pass `'*'` to receive every event regardless of topic. Returns an
|
|
1054
|
+
* unsubscribe function; calling it removes this listener. Subscriptions
|
|
1055
|
+
* survive auto-reconnect and are only dropped on an explicit disconnect().
|
|
1056
|
+
*
|
|
1057
|
+
* NOTE: no gateway currently emits `event` frames, so listeners will not
|
|
1058
|
+
* fire until an event producer is wired on the gateway side. The subscriber
|
|
1059
|
+
* surface is provided so consumers can register ahead of that work.
|
|
1060
|
+
*/
|
|
1061
|
+
on(topic, cb) {
|
|
1062
|
+
let set = this.eventListeners.get(topic);
|
|
1063
|
+
if (!set) {
|
|
1064
|
+
set = /* @__PURE__ */ new Set();
|
|
1065
|
+
this.eventListeners.set(topic, set);
|
|
1066
|
+
}
|
|
1067
|
+
set.add(cb);
|
|
1068
|
+
return () => {
|
|
1069
|
+
const current = this.eventListeners.get(topic);
|
|
1070
|
+
if (!current) return;
|
|
1071
|
+
current.delete(cb);
|
|
1072
|
+
if (current.size === 0) this.eventListeners.delete(topic);
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
/** Create a proxied WebSocket to a Durable Object */
|
|
1076
|
+
async createWsProxy(binding, id, url, headers) {
|
|
1077
|
+
await this.ensureConnected();
|
|
1078
|
+
const wid = nextWsId();
|
|
1079
|
+
const proxy = {
|
|
1080
|
+
clientWs: null,
|
|
1081
|
+
onMessage: () => {},
|
|
1082
|
+
onClose: () => {}
|
|
1083
|
+
};
|
|
1084
|
+
this.wsProxies.set(wid, proxy);
|
|
1085
|
+
const openedPromise = new Promise((resolve, reject) => {
|
|
1086
|
+
this.pendingWsOpens.set(wid, {
|
|
1087
|
+
resolve,
|
|
1088
|
+
reject
|
|
1089
|
+
});
|
|
1090
|
+
});
|
|
1091
|
+
const msg = {
|
|
1092
|
+
t: "ws.open",
|
|
1093
|
+
wid,
|
|
1094
|
+
target: {
|
|
1095
|
+
binding,
|
|
1096
|
+
id,
|
|
1097
|
+
url,
|
|
1098
|
+
headers
|
|
1099
|
+
}
|
|
1100
|
+
};
|
|
1101
|
+
this.send(msg);
|
|
1102
|
+
try {
|
|
1103
|
+
await openedPromise;
|
|
1104
|
+
} catch (error) {
|
|
1105
|
+
this.wsProxies.delete(wid);
|
|
1106
|
+
throw error;
|
|
1107
|
+
}
|
|
1108
|
+
return {
|
|
1109
|
+
wid,
|
|
1110
|
+
send: (data) => {
|
|
1111
|
+
const payload = typeof data === "string" ? new TextEncoder().encode(data) : data;
|
|
1112
|
+
const flags = typeof data === "string" ? BinaryFlags.TEXT : 0;
|
|
1113
|
+
const frame = encodeBinaryFrame(BinaryKind.WsData, wid, 0, flags, payload);
|
|
1114
|
+
this.sendBinary(frame);
|
|
1115
|
+
},
|
|
1116
|
+
close: (code, reason) => {
|
|
1117
|
+
const closeMsg = {
|
|
1118
|
+
t: "ws.close",
|
|
1119
|
+
wid,
|
|
1120
|
+
code,
|
|
1121
|
+
reason
|
|
1122
|
+
};
|
|
1123
|
+
this.send(closeMsg);
|
|
1124
|
+
this.wsProxies.delete(wid);
|
|
1125
|
+
},
|
|
1126
|
+
onMessage: (handler) => {
|
|
1127
|
+
proxy.onMessage = handler;
|
|
1128
|
+
},
|
|
1129
|
+
onClose: (handler) => {
|
|
1130
|
+
proxy.onClose = handler;
|
|
1131
|
+
}
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
/** Create a readable stream that pulls from the bridge */
|
|
1135
|
+
createReadableStream(sid) {
|
|
1136
|
+
return new ReadableStream({
|
|
1137
|
+
start: (controller) => {
|
|
1138
|
+
this.activeStreams.set(sid, {
|
|
1139
|
+
controller,
|
|
1140
|
+
buffer: [],
|
|
1141
|
+
creditRemaining: 0,
|
|
1142
|
+
pendingPull: null,
|
|
1143
|
+
ended: false,
|
|
1144
|
+
closed: false
|
|
1145
|
+
});
|
|
1146
|
+
},
|
|
1147
|
+
pull: async (controller) => {
|
|
1148
|
+
const stream = this.activeStreams.get(sid);
|
|
1149
|
+
if (!stream || stream.closed) return;
|
|
1150
|
+
if (stream.buffer.length > 0) {
|
|
1151
|
+
const chunk = stream.buffer.shift();
|
|
1152
|
+
controller.enqueue(chunk);
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1155
|
+
if (stream.ended) {
|
|
1156
|
+
controller.close();
|
|
1157
|
+
this.activeStreams.delete(sid);
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
const pullMsg = {
|
|
1161
|
+
t: "stream.pull",
|
|
1162
|
+
sid,
|
|
1163
|
+
creditBytes: DEFAULT_CHUNK_SIZE * 4
|
|
1164
|
+
};
|
|
1165
|
+
this.send(pullMsg);
|
|
1166
|
+
await new Promise((resolve, reject) => {
|
|
1167
|
+
stream.pendingPull = {
|
|
1168
|
+
resolve,
|
|
1169
|
+
reject
|
|
1170
|
+
};
|
|
1171
|
+
});
|
|
1172
|
+
stream.pendingPull = null;
|
|
1173
|
+
if (stream.closed) return;
|
|
1174
|
+
if (stream.buffer.length > 0) {
|
|
1175
|
+
const chunk = stream.buffer.shift();
|
|
1176
|
+
controller.enqueue(chunk);
|
|
1177
|
+
return;
|
|
1178
|
+
}
|
|
1179
|
+
if (stream.ended) {
|
|
1180
|
+
controller.close();
|
|
1181
|
+
this.activeStreams.delete(sid);
|
|
1182
|
+
}
|
|
1183
|
+
},
|
|
1184
|
+
cancel: () => {
|
|
1185
|
+
const stream = this.activeStreams.get(sid);
|
|
1186
|
+
if (stream) {
|
|
1187
|
+
stream.closed = true;
|
|
1188
|
+
if (stream.pendingPull) {
|
|
1189
|
+
stream.pendingPull.reject(/* @__PURE__ */ new Error("Stream cancelled"));
|
|
1190
|
+
stream.pendingPull = null;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
this.activeStreams.delete(sid);
|
|
1194
|
+
}
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
1197
|
+
handleJsonMessage(data) {
|
|
1198
|
+
try {
|
|
1199
|
+
const msg = parseJsonMsg(data);
|
|
1200
|
+
switch (msg.t) {
|
|
1201
|
+
case "event":
|
|
1202
|
+
this.handleEvent(msg);
|
|
1203
|
+
break;
|
|
1204
|
+
case "stream.pull":
|
|
1205
|
+
this.handleStreamPull(msg);
|
|
1206
|
+
break;
|
|
1207
|
+
case "stream.end":
|
|
1208
|
+
this.handleStreamEnd(msg);
|
|
1209
|
+
break;
|
|
1210
|
+
case "stream.abort":
|
|
1211
|
+
this.handleStreamAbort(msg);
|
|
1212
|
+
break;
|
|
1213
|
+
case "ws.opened":
|
|
1214
|
+
this.handleWsOpened(msg);
|
|
1215
|
+
break;
|
|
1216
|
+
case "ws.close":
|
|
1217
|
+
this.handleWsClose(msg);
|
|
1218
|
+
break;
|
|
1219
|
+
}
|
|
1220
|
+
} catch (error) {
|
|
1221
|
+
console.error("[devflare bridge client] parse error:", data, error);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
/**
|
|
1225
|
+
* Receive a v2 binary frame. Frame format is byte-identical to the legacy
|
|
1226
|
+
* v1 frames for kinds 1 (StreamChunk) and 2 (WsData); v2 owns kind 3
|
|
1227
|
+
* (BodyChunk) which the codec handles internally before reaching here.
|
|
1228
|
+
*/
|
|
1229
|
+
handleV2BinaryFrame(frame) {
|
|
1230
|
+
switch (frame.kind) {
|
|
1231
|
+
case BinaryKind.StreamChunk:
|
|
1232
|
+
this.handleStreamChunk(frame);
|
|
1233
|
+
break;
|
|
1234
|
+
case BinaryKind.WsData:
|
|
1235
|
+
this.handleWsData(frame);
|
|
1236
|
+
break;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
handleEvent(msg) {
|
|
1240
|
+
this.dispatchEvent(this.eventListeners.get(msg.topic), msg.data, msg.topic);
|
|
1241
|
+
this.dispatchEvent(this.eventListeners.get("*"), msg.data, msg.topic);
|
|
1242
|
+
}
|
|
1243
|
+
dispatchEvent(listeners, data, topic) {
|
|
1244
|
+
if (!listeners) return;
|
|
1245
|
+
for (const cb of [...listeners]) try {
|
|
1246
|
+
cb(data);
|
|
1247
|
+
} catch (error) {
|
|
1248
|
+
bridgeLog.warn(`event listener for topic "${topic}" threw`, error);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
handleStreamPull(msg) {
|
|
1252
|
+
const streamRef = this.outgoingStreams.get(msg.sid);
|
|
1253
|
+
if (!streamRef) return;
|
|
1254
|
+
this.pumpStream(streamRef, msg.creditBytes);
|
|
1255
|
+
}
|
|
1256
|
+
async pumpStream(streamRef, creditBytes) {
|
|
1257
|
+
const reader = streamRef.stream.getReader();
|
|
1258
|
+
let sent = 0;
|
|
1259
|
+
let seq = 0;
|
|
1260
|
+
try {
|
|
1261
|
+
while (sent < creditBytes) {
|
|
1262
|
+
const { done, value } = await reader.read();
|
|
1263
|
+
if (done) {
|
|
1264
|
+
this.send({
|
|
1265
|
+
t: "stream.end",
|
|
1266
|
+
sid: streamRef.sid
|
|
1267
|
+
});
|
|
1268
|
+
this.outgoingStreams.delete(streamRef.sid);
|
|
1269
|
+
break;
|
|
1270
|
+
}
|
|
1271
|
+
if (value) {
|
|
1272
|
+
const frame = encodeBinaryFrame(BinaryKind.StreamChunk, streamRef.sid, seq++, 0, value);
|
|
1273
|
+
this.sendBinary(frame);
|
|
1274
|
+
sent += value.byteLength;
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
} catch (error) {
|
|
1278
|
+
this.send({
|
|
1279
|
+
t: "stream.abort",
|
|
1280
|
+
sid: streamRef.sid,
|
|
1281
|
+
error: String(error)
|
|
1282
|
+
});
|
|
1283
|
+
this.outgoingStreams.delete(streamRef.sid);
|
|
1284
|
+
} finally {
|
|
1285
|
+
reader.releaseLock();
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
handleStreamChunk(decoded) {
|
|
1289
|
+
const stream = this.activeStreams.get(decoded.id);
|
|
1290
|
+
if (!stream || stream.closed) return;
|
|
1291
|
+
stream.buffer.push(decoded.payload);
|
|
1292
|
+
if (stream.pendingPull) {
|
|
1293
|
+
const pending = stream.pendingPull;
|
|
1294
|
+
stream.pendingPull = null;
|
|
1295
|
+
pending.resolve();
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
handleStreamEnd(msg) {
|
|
1299
|
+
const stream = this.activeStreams.get(msg.sid);
|
|
1300
|
+
if (!stream) return;
|
|
1301
|
+
stream.ended = true;
|
|
1302
|
+
if (stream.pendingPull) {
|
|
1303
|
+
const pending = stream.pendingPull;
|
|
1304
|
+
stream.pendingPull = null;
|
|
1305
|
+
pending.resolve();
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
handleStreamAbort(msg) {
|
|
1309
|
+
const stream = this.activeStreams.get(msg.sid);
|
|
1310
|
+
if (!stream) return;
|
|
1311
|
+
const err = new Error(msg.error ?? "Stream aborted");
|
|
1312
|
+
stream.closed = true;
|
|
1313
|
+
if (stream.pendingPull) {
|
|
1314
|
+
const pending = stream.pendingPull;
|
|
1315
|
+
stream.pendingPull = null;
|
|
1316
|
+
pending.reject(err);
|
|
1317
|
+
}
|
|
1318
|
+
try {
|
|
1319
|
+
stream.controller.error(err);
|
|
1320
|
+
} catch {}
|
|
1321
|
+
this.activeStreams.delete(msg.sid);
|
|
1322
|
+
}
|
|
1323
|
+
handleWsData(decoded) {
|
|
1324
|
+
const proxy = this.wsProxies.get(decoded.id);
|
|
1325
|
+
if (!proxy) return;
|
|
1326
|
+
const data = (decoded.flags & BinaryFlags.TEXT) !== 0 ? new TextDecoder().decode(decoded.payload) : decoded.payload;
|
|
1327
|
+
proxy.onMessage(data);
|
|
1328
|
+
}
|
|
1329
|
+
handleWsClose(msg) {
|
|
1330
|
+
const proxy = this.wsProxies.get(msg.wid);
|
|
1331
|
+
if (!proxy) return;
|
|
1332
|
+
proxy.onClose(msg.code, msg.reason);
|
|
1333
|
+
this.wsProxies.delete(msg.wid);
|
|
1334
|
+
}
|
|
1335
|
+
handleWsOpened(msg) {
|
|
1336
|
+
const pending = this.pendingWsOpens.get(msg.wid);
|
|
1337
|
+
if (!pending) return;
|
|
1338
|
+
this.pendingWsOpens.delete(msg.wid);
|
|
1339
|
+
pending.resolve();
|
|
1340
|
+
}
|
|
1341
|
+
async ensureConnected() {
|
|
1342
|
+
if (!this.isConnected) await this.connect();
|
|
1343
|
+
}
|
|
1344
|
+
send(msg) {
|
|
1345
|
+
const codec = this.codec;
|
|
1346
|
+
if (!codec || !this.isConnected) throw new Error("Not connected to bridge");
|
|
1347
|
+
codec.sendText(stringifyJsonMsg(msg));
|
|
1348
|
+
}
|
|
1349
|
+
sendBinary(frame) {
|
|
1350
|
+
const codec = this.codec;
|
|
1351
|
+
if (!codec || !this.isConnected) throw new Error("Not connected to bridge");
|
|
1352
|
+
codec.sendBinary(frame);
|
|
1353
|
+
}
|
|
1354
|
+
};
|
|
1355
|
+
let defaultClient = null;
|
|
1356
|
+
/** Get or create the default bridge client */
|
|
1357
|
+
function getClient(options) {
|
|
1358
|
+
if (!defaultClient) defaultClient = new BridgeClient(options);
|
|
1359
|
+
return defaultClient;
|
|
1360
|
+
}
|
|
1361
|
+
//#endregion
|
|
1362
|
+
//#region src/bridge/proxy.ts
|
|
1363
|
+
function createKVProxy(client, bindingName) {
|
|
1364
|
+
return {
|
|
1365
|
+
async get(key, options) {
|
|
1366
|
+
return client.call(`${bindingName}.kv.get`, [key, options]);
|
|
1367
|
+
},
|
|
1368
|
+
async put(key, value, options) {
|
|
1369
|
+
await client.call(`${bindingName}.kv.put`, [
|
|
1370
|
+
key,
|
|
1371
|
+
value,
|
|
1372
|
+
options
|
|
1373
|
+
]);
|
|
1374
|
+
},
|
|
1375
|
+
async delete(key) {
|
|
1376
|
+
await client.call(`${bindingName}.kv.delete`, [key]);
|
|
1377
|
+
},
|
|
1378
|
+
async list(options) {
|
|
1379
|
+
return client.call(`${bindingName}.kv.list`, [options]);
|
|
1380
|
+
},
|
|
1381
|
+
async getWithMetadata(key, options) {
|
|
1382
|
+
return client.call(`${bindingName}.kv.getWithMetadata`, [key, options]);
|
|
1383
|
+
}
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1386
|
+
function createR2Proxy(client, bindingName) {
|
|
1387
|
+
return {
|
|
1388
|
+
async head(key) {
|
|
1389
|
+
return client.call(`${bindingName}.r2.head`, [key]);
|
|
1390
|
+
},
|
|
1391
|
+
async get(key, options) {
|
|
1392
|
+
return client.call(`${bindingName}.r2.get`, [key, options]);
|
|
1393
|
+
},
|
|
1394
|
+
async put(key, value, options) {
|
|
1395
|
+
if (getValueSize(value) > 524288) {
|
|
1396
|
+
const transferId = `${bindingName}:${key}`;
|
|
1397
|
+
const transferUrl = client.getHttpUrl().replace(/\/$/, "") + `/_devflare/transfer/${encodeURIComponent(transferId)}`;
|
|
1398
|
+
const response = await fetch(transferUrl, {
|
|
1399
|
+
method: "PUT",
|
|
1400
|
+
body: value,
|
|
1401
|
+
headers: { ...options?.httpMetadata?.contentType ? { "Content-Type": options.httpMetadata.contentType } : {} }
|
|
1402
|
+
});
|
|
1403
|
+
if (!response.ok) {
|
|
1404
|
+
const error = await response.text();
|
|
1405
|
+
throw new Error(`HTTP transfer failed: ${error}`);
|
|
1406
|
+
}
|
|
1407
|
+
return deserializeValue(await response.json());
|
|
1408
|
+
}
|
|
1409
|
+
return client.call(`${bindingName}.r2.put`, [
|
|
1410
|
+
key,
|
|
1411
|
+
value,
|
|
1412
|
+
options
|
|
1413
|
+
]);
|
|
1414
|
+
},
|
|
1415
|
+
async delete(keys) {
|
|
1416
|
+
await client.call(`${bindingName}.r2.delete`, [keys]);
|
|
1417
|
+
},
|
|
1418
|
+
async list(options) {
|
|
1419
|
+
return client.call(`${bindingName}.r2.list`, [options]);
|
|
1420
|
+
},
|
|
1421
|
+
async createMultipartUpload(key, options) {
|
|
1422
|
+
return client.call(`${bindingName}.r2.createMultipartUpload`, [key, options]);
|
|
1423
|
+
},
|
|
1424
|
+
async resumeMultipartUpload(key, uploadId) {
|
|
1425
|
+
return client.call(`${bindingName}.r2.resumeMultipartUpload`, [key, uploadId]);
|
|
1426
|
+
}
|
|
1427
|
+
};
|
|
1428
|
+
}
|
|
1429
|
+
function getValueSize(value) {
|
|
1430
|
+
if (value instanceof Blob) return value.size;
|
|
1431
|
+
if (value instanceof ArrayBuffer) return value.byteLength;
|
|
1432
|
+
if (value instanceof Uint8Array) return value.byteLength;
|
|
1433
|
+
if (typeof value === "string") return new TextEncoder().encode(value).byteLength;
|
|
1434
|
+
if (value instanceof ReadableStream) return Number.POSITIVE_INFINITY;
|
|
1435
|
+
return 0;
|
|
1436
|
+
}
|
|
1437
|
+
function createD1Proxy(client, bindingName) {
|
|
1438
|
+
return {
|
|
1439
|
+
prepare(sql) {
|
|
1440
|
+
return createD1StatementProxy(client, bindingName, sql, []);
|
|
1441
|
+
},
|
|
1442
|
+
async batch(statements) {
|
|
1443
|
+
const serialized = statements.map((stmt) => {
|
|
1444
|
+
const s = stmt;
|
|
1445
|
+
return {
|
|
1446
|
+
sql: s._sql,
|
|
1447
|
+
bindings: s._bindings
|
|
1448
|
+
};
|
|
1449
|
+
});
|
|
1450
|
+
return client.call(`${bindingName}.d1.batch`, [serialized]);
|
|
1451
|
+
},
|
|
1452
|
+
async exec(sql) {
|
|
1453
|
+
return client.call(`${bindingName}.d1.exec`, [sql]);
|
|
1454
|
+
},
|
|
1455
|
+
async dump() {
|
|
1456
|
+
return client.call(`${bindingName}.d1.dump`, []);
|
|
1457
|
+
}
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
function createD1StatementProxy(client, bindingName, sql, bindings) {
|
|
1461
|
+
return {
|
|
1462
|
+
_sql: sql,
|
|
1463
|
+
_bindings: bindings,
|
|
1464
|
+
bind(...values) {
|
|
1465
|
+
return createD1StatementProxy(client, bindingName, sql, values);
|
|
1466
|
+
},
|
|
1467
|
+
async first(column) {
|
|
1468
|
+
return client.call(`${bindingName}.d1.stmt.first`, [
|
|
1469
|
+
sql,
|
|
1470
|
+
...bindings,
|
|
1471
|
+
column
|
|
1472
|
+
]);
|
|
1473
|
+
},
|
|
1474
|
+
async all() {
|
|
1475
|
+
return client.call(`${bindingName}.d1.stmt.all`, [sql, ...bindings]);
|
|
1476
|
+
},
|
|
1477
|
+
async run() {
|
|
1478
|
+
return client.call(`${bindingName}.d1.stmt.run`, [sql, ...bindings]);
|
|
1479
|
+
},
|
|
1480
|
+
async raw(options) {
|
|
1481
|
+
return client.call(`${bindingName}.d1.stmt.raw`, [
|
|
1482
|
+
sql,
|
|
1483
|
+
...bindings,
|
|
1484
|
+
options
|
|
1485
|
+
]);
|
|
1486
|
+
}
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1489
|
+
function createDOProxy(client, bindingName, proxyOptions = {}) {
|
|
1490
|
+
return {
|
|
1491
|
+
idFromName(name) {
|
|
1492
|
+
return createDOIdProxy(client, bindingName, {
|
|
1493
|
+
type: "name",
|
|
1494
|
+
value: name,
|
|
1495
|
+
jurisdiction: proxyOptions.jurisdiction
|
|
1496
|
+
});
|
|
1497
|
+
},
|
|
1498
|
+
idFromString(hexId) {
|
|
1499
|
+
return createDOIdProxy(client, bindingName, {
|
|
1500
|
+
type: "hex",
|
|
1501
|
+
value: hexId,
|
|
1502
|
+
jurisdiction: proxyOptions.jurisdiction
|
|
1503
|
+
});
|
|
1504
|
+
},
|
|
1505
|
+
newUniqueId(options) {
|
|
1506
|
+
return createDOIdProxy(client, bindingName, {
|
|
1507
|
+
type: "unique",
|
|
1508
|
+
value: crypto.randomUUID().replace(/-/g, ""),
|
|
1509
|
+
options,
|
|
1510
|
+
jurisdiction: proxyOptions.jurisdiction
|
|
1511
|
+
});
|
|
1512
|
+
},
|
|
1513
|
+
get(id) {
|
|
1514
|
+
return createDOStubProxy(client, bindingName, id._idInfo, proxyOptions);
|
|
1515
|
+
},
|
|
1516
|
+
getByName(name) {
|
|
1517
|
+
const id = this.idFromName(name);
|
|
1518
|
+
return this.get(id);
|
|
1519
|
+
},
|
|
1520
|
+
jurisdiction(jurisdiction) {
|
|
1521
|
+
return createDOProxy(client, bindingName, {
|
|
1522
|
+
...proxyOptions,
|
|
1523
|
+
jurisdiction
|
|
1524
|
+
});
|
|
1525
|
+
}
|
|
1526
|
+
};
|
|
1527
|
+
}
|
|
1528
|
+
function createDOIdProxy(client, bindingName, idInfo) {
|
|
1529
|
+
return {
|
|
1530
|
+
_idInfo: idInfo,
|
|
1531
|
+
toString() {
|
|
1532
|
+
if (idInfo.type === "hex") return idInfo.value;
|
|
1533
|
+
return `${idInfo.type}:${idInfo.value}`;
|
|
1534
|
+
},
|
|
1535
|
+
equals(other) {
|
|
1536
|
+
return this.toString() === other.toString();
|
|
1537
|
+
}
|
|
1538
|
+
};
|
|
1539
|
+
}
|
|
1540
|
+
function createDOStubProxy(client, bindingName, idInfo, proxyOptions = {}) {
|
|
1541
|
+
const { transformResult } = proxyOptions;
|
|
1542
|
+
let resolvedId = null;
|
|
1543
|
+
const resolveId = async () => {
|
|
1544
|
+
if (resolvedId) return resolvedId;
|
|
1545
|
+
switch (idInfo.type) {
|
|
1546
|
+
case "name":
|
|
1547
|
+
resolvedId = await client.call(`${bindingName}.do.idFromName`, [idInfo.value, idInfo.jurisdiction]);
|
|
1548
|
+
break;
|
|
1549
|
+
case "hex":
|
|
1550
|
+
resolvedId = {
|
|
1551
|
+
__type: "DOId",
|
|
1552
|
+
hex: idInfo.value
|
|
1553
|
+
};
|
|
1554
|
+
break;
|
|
1555
|
+
case "unique":
|
|
1556
|
+
resolvedId = await client.call(`${bindingName}.do.newUniqueId`, [idInfo.options, idInfo.jurisdiction]);
|
|
1557
|
+
break;
|
|
1558
|
+
}
|
|
1559
|
+
return resolvedId;
|
|
1560
|
+
};
|
|
1561
|
+
return new Proxy({
|
|
1562
|
+
async fetch(input, init) {
|
|
1563
|
+
const id = await resolveId();
|
|
1564
|
+
const { serialized } = await serializeRequest(input instanceof Request ? input : new Request(input, init));
|
|
1565
|
+
return deserializeResponse(await client.call(`${bindingName}.do.fetch`, [
|
|
1566
|
+
bindingName,
|
|
1567
|
+
id,
|
|
1568
|
+
serialized
|
|
1569
|
+
]));
|
|
1570
|
+
},
|
|
1571
|
+
async connect(url, options) {
|
|
1572
|
+
const id = await resolveId();
|
|
1573
|
+
const headersList = [];
|
|
1574
|
+
if (options?.headers) new Headers(options.headers).forEach((value, key) => {
|
|
1575
|
+
headersList.push([key, value]);
|
|
1576
|
+
});
|
|
1577
|
+
const wsProxy = await client.createWsProxy(bindingName, id.hex, url, headersList);
|
|
1578
|
+
let readController = null;
|
|
1579
|
+
const readable = new ReadableStream({
|
|
1580
|
+
start(controller) {
|
|
1581
|
+
readController = controller;
|
|
1582
|
+
},
|
|
1583
|
+
cancel() {
|
|
1584
|
+
wsProxy.close();
|
|
1585
|
+
}
|
|
1586
|
+
});
|
|
1587
|
+
wsProxy.onMessage((data) => {
|
|
1588
|
+
if (readController) {
|
|
1589
|
+
const chunk = typeof data === "string" ? new TextEncoder().encode(data) : data;
|
|
1590
|
+
readController.enqueue(chunk);
|
|
1591
|
+
}
|
|
1592
|
+
});
|
|
1593
|
+
wsProxy.onClose((code, reason) => {
|
|
1594
|
+
if (readController) readController.close();
|
|
1595
|
+
});
|
|
1596
|
+
return {
|
|
1597
|
+
readable,
|
|
1598
|
+
writable: new WritableStream({
|
|
1599
|
+
write(chunk) {
|
|
1600
|
+
wsProxy.send(chunk);
|
|
1601
|
+
},
|
|
1602
|
+
close() {
|
|
1603
|
+
wsProxy.close(1e3, "Normal closure");
|
|
1604
|
+
},
|
|
1605
|
+
abort(reason) {
|
|
1606
|
+
wsProxy.close(1001, reason?.toString() ?? "Aborted");
|
|
1607
|
+
}
|
|
1608
|
+
}),
|
|
1609
|
+
get opened() {
|
|
1610
|
+
return Promise.resolve({
|
|
1611
|
+
remoteAddress: "127.0.0.1",
|
|
1612
|
+
localAddress: "127.0.0.1"
|
|
1613
|
+
});
|
|
1614
|
+
},
|
|
1615
|
+
get closed() {
|
|
1616
|
+
return new Promise((resolve) => {
|
|
1617
|
+
wsProxy.onClose(() => resolve());
|
|
1618
|
+
});
|
|
1619
|
+
},
|
|
1620
|
+
close() {
|
|
1621
|
+
wsProxy.close(1e3, "Normal closure");
|
|
1622
|
+
return Promise.resolve();
|
|
1623
|
+
},
|
|
1624
|
+
startTls() {
|
|
1625
|
+
throw new Error("startTls() is not supported on a Durable Object WebSocket connection. StartTLS applies to raw TCP sockets (cloudflare:sockets connect()), not WebSocket-tunneled DO connections, whose transport is already secured by the connection itself.");
|
|
1626
|
+
}
|
|
1627
|
+
};
|
|
1628
|
+
},
|
|
1629
|
+
get id() {
|
|
1630
|
+
return createDOIdProxy(client, bindingName, idInfo);
|
|
1631
|
+
},
|
|
1632
|
+
get name() {
|
|
1633
|
+
return idInfo.type === "name" ? idInfo.value : void 0;
|
|
1634
|
+
}
|
|
1635
|
+
}, { get(target, prop) {
|
|
1636
|
+
if (prop in target) return target[prop];
|
|
1637
|
+
if (typeof prop === "symbol") return;
|
|
1638
|
+
if (prop === "then" || prop === "catch" || prop === "finally") return;
|
|
1639
|
+
return async (...args) => {
|
|
1640
|
+
const id = await resolveId();
|
|
1641
|
+
let result = await client.call(`${bindingName}.do.rpc`, [
|
|
1642
|
+
bindingName,
|
|
1643
|
+
id,
|
|
1644
|
+
prop,
|
|
1645
|
+
args
|
|
1646
|
+
]);
|
|
1647
|
+
if (transformResult) result = transformResult(result);
|
|
1648
|
+
return result;
|
|
1649
|
+
};
|
|
1650
|
+
} });
|
|
1651
|
+
}
|
|
1652
|
+
function isResponseLike(value) {
|
|
1653
|
+
return value instanceof Response;
|
|
1654
|
+
}
|
|
1655
|
+
function createServiceProxy(client, bindingName, proxyOptions = {}) {
|
|
1656
|
+
const { transformResult } = proxyOptions;
|
|
1657
|
+
return new Proxy({ async fetch(input, init) {
|
|
1658
|
+
const { serialized } = await serializeRequest(input instanceof Request ? input : new Request(input, init));
|
|
1659
|
+
const result = await client.call(`${bindingName}.service.fetch`, [serialized]);
|
|
1660
|
+
if (isResponseLike(result)) return result;
|
|
1661
|
+
return deserializeResponse(result);
|
|
1662
|
+
} }, { get(target, prop) {
|
|
1663
|
+
if (typeof prop !== "string") return;
|
|
1664
|
+
if (prop in target) return target[prop];
|
|
1665
|
+
if (prop === "then" || prop === "catch" || prop === "finally") return;
|
|
1666
|
+
if (prop === "toString") return () => `[DevflareServiceBinding ${bindingName}]`;
|
|
1667
|
+
return async (...args) => {
|
|
1668
|
+
let result = await client.call(`${bindingName}.service.rpc`, [prop, args]);
|
|
1669
|
+
if (transformResult) result = transformResult(result);
|
|
1670
|
+
return result;
|
|
1671
|
+
};
|
|
1672
|
+
} });
|
|
1673
|
+
}
|
|
1674
|
+
const EMPTY_QUEUE_METRICS = {
|
|
1675
|
+
backlogCount: 0,
|
|
1676
|
+
backlogBytes: 0
|
|
1677
|
+
};
|
|
1678
|
+
function createQueueResponse() {
|
|
1679
|
+
return { metadata: { metrics: EMPTY_QUEUE_METRICS } };
|
|
1680
|
+
}
|
|
1681
|
+
function createQueueProxy(client, bindingName) {
|
|
1682
|
+
return {
|
|
1683
|
+
async metrics() {
|
|
1684
|
+
return EMPTY_QUEUE_METRICS;
|
|
1685
|
+
},
|
|
1686
|
+
async send(message, options) {
|
|
1687
|
+
await client.call(`${bindingName}.queue.send`, [message, options]);
|
|
1688
|
+
return createQueueResponse();
|
|
1689
|
+
},
|
|
1690
|
+
async sendBatch(messages, options) {
|
|
1691
|
+
await client.call(`${bindingName}.queue.sendBatch`, [messages, options]);
|
|
1692
|
+
return createQueueResponse();
|
|
1693
|
+
}
|
|
1694
|
+
};
|
|
1695
|
+
}
|
|
1696
|
+
function createAIProxy(client, bindingName) {
|
|
1697
|
+
return { async run(model, inputs, options) {
|
|
1698
|
+
return client.call(`${bindingName}.ai.run`, [
|
|
1699
|
+
model,
|
|
1700
|
+
inputs,
|
|
1701
|
+
options
|
|
1702
|
+
]);
|
|
1703
|
+
} };
|
|
1704
|
+
}
|
|
1705
|
+
function createSendEmailProxy(client, bindingName) {
|
|
1706
|
+
return { async send(message) {
|
|
1707
|
+
return client.call(`${bindingName}.email.send`, [message]);
|
|
1708
|
+
} };
|
|
1709
|
+
}
|
|
1710
|
+
function createWorkflowInstanceProxy(client, bindingName, id) {
|
|
1711
|
+
return {
|
|
1712
|
+
id,
|
|
1713
|
+
async pause() {
|
|
1714
|
+
await client.call(`${bindingName}.workflow.pause`, [id]);
|
|
1715
|
+
},
|
|
1716
|
+
async resume() {
|
|
1717
|
+
await client.call(`${bindingName}.workflow.resume`, [id]);
|
|
1718
|
+
},
|
|
1719
|
+
async terminate() {
|
|
1720
|
+
await client.call(`${bindingName}.workflow.terminate`, [id]);
|
|
1721
|
+
},
|
|
1722
|
+
async restart() {
|
|
1723
|
+
await client.call(`${bindingName}.workflow.restart`, [id]);
|
|
1724
|
+
},
|
|
1725
|
+
async status() {
|
|
1726
|
+
return client.call(`${bindingName}.workflow.status`, [id]);
|
|
1727
|
+
},
|
|
1728
|
+
async sendEvent(event) {
|
|
1729
|
+
await client.call(`${bindingName}.workflow.sendEvent`, [id, event]);
|
|
1730
|
+
}
|
|
1731
|
+
};
|
|
1732
|
+
}
|
|
1733
|
+
function createWorkflowProxy(client, bindingName) {
|
|
1734
|
+
const toInstance = (value) => {
|
|
1735
|
+
const id = value?.id;
|
|
1736
|
+
if (typeof id !== "string") throw new Error(`Workflow ${bindingName} returned an instance without a string id.`);
|
|
1737
|
+
return createWorkflowInstanceProxy(client, bindingName, id);
|
|
1738
|
+
};
|
|
1739
|
+
return {
|
|
1740
|
+
async create(options) {
|
|
1741
|
+
return toInstance(await client.call(`${bindingName}.workflow.create`, [options]));
|
|
1742
|
+
},
|
|
1743
|
+
async get(id) {
|
|
1744
|
+
return toInstance(await client.call(`${bindingName}.workflow.get`, [id]));
|
|
1745
|
+
}
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
/** Module-level storage for binding hints */
|
|
1749
|
+
let globalBindingHints = {};
|
|
1750
|
+
/**
|
|
1751
|
+
* Create an env proxy that routes all binding access through the bridge
|
|
1752
|
+
*/
|
|
1753
|
+
function createEnvProxy(options = {}) {
|
|
1754
|
+
const client = options.client ?? getClient();
|
|
1755
|
+
const bindingProxies = /* @__PURE__ */ new Map();
|
|
1756
|
+
const doProxyOptions = { transformResult: options.transformResult };
|
|
1757
|
+
const serviceProxyOptions = { transformResult: options.transformResult };
|
|
1758
|
+
const strict = options.strict === true;
|
|
1759
|
+
const hints = {
|
|
1760
|
+
...globalBindingHints,
|
|
1761
|
+
...options.hints
|
|
1762
|
+
};
|
|
1763
|
+
return new Proxy({}, {
|
|
1764
|
+
get(target, prop) {
|
|
1765
|
+
if (typeof prop !== "string") return void 0;
|
|
1766
|
+
if (bindingProxies.has(prop)) return bindingProxies.get(prop);
|
|
1767
|
+
const hint = hints[prop];
|
|
1768
|
+
if (!hint && strict) return;
|
|
1769
|
+
let proxy;
|
|
1770
|
+
switch (hint) {
|
|
1771
|
+
case "kv":
|
|
1772
|
+
proxy = createKVProxy(client, prop);
|
|
1773
|
+
break;
|
|
1774
|
+
case "r2":
|
|
1775
|
+
proxy = createR2Proxy(client, prop);
|
|
1776
|
+
break;
|
|
1777
|
+
case "d1":
|
|
1778
|
+
proxy = createD1Proxy(client, prop);
|
|
1779
|
+
break;
|
|
1780
|
+
case "do":
|
|
1781
|
+
proxy = createDOProxy(client, prop, doProxyOptions);
|
|
1782
|
+
break;
|
|
1783
|
+
case "queue":
|
|
1784
|
+
proxy = createQueueProxy(client, prop);
|
|
1785
|
+
break;
|
|
1786
|
+
case "ai":
|
|
1787
|
+
proxy = createAIProxy(client, prop);
|
|
1788
|
+
break;
|
|
1789
|
+
case "service":
|
|
1790
|
+
proxy = createServiceProxy(client, prop, serviceProxyOptions);
|
|
1791
|
+
break;
|
|
1792
|
+
case "sendEmail":
|
|
1793
|
+
proxy = createSendEmailProxy(client, prop);
|
|
1794
|
+
break;
|
|
1795
|
+
case "workflow":
|
|
1796
|
+
proxy = createWorkflowProxy(client, prop);
|
|
1797
|
+
break;
|
|
1798
|
+
case "secret":
|
|
1799
|
+
case "var":
|
|
1800
|
+
proxy = createSimpleBindingProxy(client, prop);
|
|
1801
|
+
break;
|
|
1802
|
+
default: proxy = createGenericBindingProxy(client, prop);
|
|
1803
|
+
}
|
|
1804
|
+
bindingProxies.set(prop, proxy);
|
|
1805
|
+
return proxy;
|
|
1806
|
+
},
|
|
1807
|
+
has(target, prop) {
|
|
1808
|
+
return typeof prop === "string" && (!strict || prop in hints);
|
|
1809
|
+
},
|
|
1810
|
+
ownKeys() {
|
|
1811
|
+
return Object.keys(hints);
|
|
1812
|
+
},
|
|
1813
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
1814
|
+
if (typeof prop === "string" && (!strict || prop in hints)) return {
|
|
1815
|
+
configurable: true,
|
|
1816
|
+
enumerable: true,
|
|
1817
|
+
writable: false
|
|
1818
|
+
};
|
|
1819
|
+
}
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1822
|
+
function createGenericBindingProxy(client, bindingName) {
|
|
1823
|
+
return new Proxy({}, { get(target, prop) {
|
|
1824
|
+
if (typeof prop !== "string") return void 0;
|
|
1825
|
+
if ([
|
|
1826
|
+
"get",
|
|
1827
|
+
"put",
|
|
1828
|
+
"delete",
|
|
1829
|
+
"list",
|
|
1830
|
+
"getWithMetadata"
|
|
1831
|
+
].includes(prop)) return createKVProxy(client, bindingName)[prop];
|
|
1832
|
+
if ([
|
|
1833
|
+
"idFromName",
|
|
1834
|
+
"idFromString",
|
|
1835
|
+
"newUniqueId",
|
|
1836
|
+
"get"
|
|
1837
|
+
].includes(prop)) return createDOProxy(client, bindingName)[prop];
|
|
1838
|
+
if ([
|
|
1839
|
+
"prepare",
|
|
1840
|
+
"batch",
|
|
1841
|
+
"exec",
|
|
1842
|
+
"dump"
|
|
1843
|
+
].includes(prop)) return createD1Proxy(client, bindingName)[prop];
|
|
1844
|
+
if (["head"].includes(prop)) return createR2Proxy(client, bindingName)[prop];
|
|
1845
|
+
return async (...args) => {
|
|
1846
|
+
return client.call(`${bindingName}.${prop}`, args);
|
|
1847
|
+
};
|
|
1848
|
+
} });
|
|
1849
|
+
}
|
|
1850
|
+
function createSimpleBindingProxy(client, bindingName) {
|
|
1851
|
+
let cachedValue;
|
|
1852
|
+
let fetched = false;
|
|
1853
|
+
let pendingValue = null;
|
|
1854
|
+
const loadValue = () => {
|
|
1855
|
+
if (fetched) return Promise.resolve(cachedValue);
|
|
1856
|
+
if (!pendingValue) pendingValue = client.call(`${bindingName}.var.value`, []).then((value) => {
|
|
1857
|
+
cachedValue = value;
|
|
1858
|
+
fetched = true;
|
|
1859
|
+
return value;
|
|
1860
|
+
}).catch((error) => {
|
|
1861
|
+
pendingValue = null;
|
|
1862
|
+
throw error;
|
|
1863
|
+
});
|
|
1864
|
+
return pendingValue;
|
|
1865
|
+
};
|
|
1866
|
+
return {
|
|
1867
|
+
then(resolve, reject) {
|
|
1868
|
+
return loadValue().then(resolve ?? void 0, reject ?? void 0);
|
|
1869
|
+
},
|
|
1870
|
+
toString() {
|
|
1871
|
+
if (!fetched) throw new Error(`Binding ${bindingName} not yet fetched. Use await.`);
|
|
1872
|
+
return String(cachedValue);
|
|
1873
|
+
}
|
|
1874
|
+
};
|
|
1875
|
+
}
|
|
1876
|
+
let globalEnvProxy = null;
|
|
1877
|
+
/**
|
|
1878
|
+
* Get the global env proxy for bridge RPC.
|
|
1879
|
+
*
|
|
1880
|
+
* @internal
|
|
1881
|
+
* Internal bridge surface — not part of the documented public API. Prefer
|
|
1882
|
+
* `import { env } from 'devflare'`, which transparently picks the right
|
|
1883
|
+
* source (request context, test context, or bridge) for the current
|
|
1884
|
+
* environment. `bridgeEnv` is retained as an internal escape hatch for the
|
|
1885
|
+
* bridge implementation itself and may change without a major version bump.
|
|
1886
|
+
*
|
|
1887
|
+
* @example
|
|
1888
|
+
* ```ts
|
|
1889
|
+
* await bridgeEnv.MY_KV.get('key')
|
|
1890
|
+
* await bridgeEnv.MY_DO.get(id).fetch(request)
|
|
1891
|
+
* ```
|
|
1892
|
+
*/
|
|
1893
|
+
const bridgeEnv = new Proxy({}, { get(target, prop) {
|
|
1894
|
+
if (!globalEnvProxy) globalEnvProxy = createEnvProxy({ lazy: true });
|
|
1895
|
+
return globalEnvProxy[prop];
|
|
1896
|
+
} });
|
|
1897
|
+
/**
|
|
1898
|
+
* Initialize the env proxy with specific options
|
|
1899
|
+
*/
|
|
1900
|
+
function initEnv(options = {}) {
|
|
1901
|
+
globalEnvProxy = createEnvProxy(options);
|
|
1902
|
+
return globalEnvProxy;
|
|
1903
|
+
}
|
|
1904
|
+
/**
|
|
1905
|
+
* Set binding hints for better proxy creation
|
|
1906
|
+
* Hints help the bridge create optimized proxies for each binding type
|
|
1907
|
+
*/
|
|
1908
|
+
function setBindingHints(hints) {
|
|
1909
|
+
globalBindingHints = {
|
|
1910
|
+
...globalBindingHints,
|
|
1911
|
+
...hints
|
|
1912
|
+
};
|
|
1913
|
+
globalEnvProxy = null;
|
|
1914
|
+
}
|
|
1915
|
+
//#endregion
|
|
1916
|
+
//#region src/runtime/context-events.ts
|
|
1917
|
+
function createLocals$1(locals) {
|
|
1918
|
+
return locals ?? {};
|
|
1919
|
+
}
|
|
1920
|
+
/**
|
|
1921
|
+
* Builds the shared scaffold used by every event builder: a wrapped runtime env
|
|
1922
|
+
* (with SendEmail bindings proxied) plus a locals bag. Every event type layers
|
|
1923
|
+
* its specific fields on top of this shell.
|
|
1924
|
+
*/
|
|
1925
|
+
function prepareEventShell(env, options = {}) {
|
|
1926
|
+
return {
|
|
1927
|
+
env: wrapEnvSendEmailBindings(env),
|
|
1928
|
+
locals: createLocals$1(options.locals)
|
|
1929
|
+
};
|
|
1930
|
+
}
|
|
1931
|
+
function createAugmentedTarget(target, extra) {
|
|
1932
|
+
return new Proxy(target, {
|
|
1933
|
+
get(target, prop) {
|
|
1934
|
+
if (prop in extra) return extra[prop];
|
|
1935
|
+
const value = Reflect.get(target, prop, target);
|
|
1936
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
1937
|
+
},
|
|
1938
|
+
has(target, prop) {
|
|
1939
|
+
return prop in extra || prop in target;
|
|
1940
|
+
},
|
|
1941
|
+
ownKeys(target) {
|
|
1942
|
+
return Array.from(new Set([...Reflect.ownKeys(target), ...Reflect.ownKeys(extra)]));
|
|
1943
|
+
},
|
|
1944
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
1945
|
+
if (prop in extra) return {
|
|
1946
|
+
configurable: true,
|
|
1947
|
+
enumerable: true,
|
|
1948
|
+
writable: false,
|
|
1949
|
+
value: extra[prop]
|
|
1950
|
+
};
|
|
1951
|
+
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
1952
|
+
}
|
|
1953
|
+
});
|
|
1954
|
+
}
|
|
1955
|
+
function createBaseEvent(type, env, ctx, options = {}) {
|
|
1956
|
+
return {
|
|
1957
|
+
type,
|
|
1958
|
+
ctx,
|
|
1959
|
+
...prepareEventShell(env, { locals: options.locals }),
|
|
1960
|
+
request: options.request ?? null,
|
|
1961
|
+
params: options.params
|
|
1962
|
+
};
|
|
1963
|
+
}
|
|
1964
|
+
function createFetchEvent(request, env, ctx, options = {}) {
|
|
1965
|
+
return createAugmentedTarget(request, {
|
|
1966
|
+
type: "fetch",
|
|
1967
|
+
ctx,
|
|
1968
|
+
...prepareEventShell(env, { locals: options.locals }),
|
|
1969
|
+
url: new URL(request.url),
|
|
1970
|
+
request,
|
|
1971
|
+
params: options.params ?? {}
|
|
1972
|
+
});
|
|
1973
|
+
}
|
|
1974
|
+
function createQueueEvent(batch, env, ctx, options = {}) {
|
|
1975
|
+
return createAugmentedTarget(batch, {
|
|
1976
|
+
type: "queue",
|
|
1977
|
+
ctx,
|
|
1978
|
+
...prepareEventShell(env, { locals: options.locals }),
|
|
1979
|
+
batch
|
|
1980
|
+
});
|
|
1981
|
+
}
|
|
1982
|
+
function createScheduledEvent(controller, env, ctx, options = {}) {
|
|
1983
|
+
return createAugmentedTarget(controller, {
|
|
1984
|
+
type: "scheduled",
|
|
1985
|
+
ctx,
|
|
1986
|
+
...prepareEventShell(env, { locals: options.locals }),
|
|
1987
|
+
controller
|
|
1988
|
+
});
|
|
1989
|
+
}
|
|
1990
|
+
function createEmailEvent(message, env, ctx, options = {}) {
|
|
1991
|
+
return createAugmentedTarget(message, {
|
|
1992
|
+
type: "email",
|
|
1993
|
+
ctx,
|
|
1994
|
+
...prepareEventShell(env, { locals: options.locals }),
|
|
1995
|
+
message
|
|
1996
|
+
});
|
|
1997
|
+
}
|
|
1998
|
+
function createTailEvent(events, env, ctx, options = {}) {
|
|
1999
|
+
return createAugmentedTarget(events, {
|
|
2000
|
+
type: "tail",
|
|
2001
|
+
ctx,
|
|
2002
|
+
...prepareEventShell(env, { locals: options.locals }),
|
|
2003
|
+
events
|
|
2004
|
+
});
|
|
2005
|
+
}
|
|
2006
|
+
function createDurableObjectFetchEvent(request, env, state, options = {}) {
|
|
2007
|
+
return createAugmentedTarget(request, {
|
|
2008
|
+
type: "durable-object-fetch",
|
|
2009
|
+
ctx: state,
|
|
2010
|
+
state,
|
|
2011
|
+
...prepareEventShell(env, { locals: options.locals }),
|
|
2012
|
+
request
|
|
2013
|
+
});
|
|
2014
|
+
}
|
|
2015
|
+
function createDurableObjectAlarmEvent(env, state, options = {}) {
|
|
2016
|
+
return {
|
|
2017
|
+
type: "durable-object-alarm",
|
|
2018
|
+
ctx: state,
|
|
2019
|
+
state,
|
|
2020
|
+
...prepareEventShell(env, { locals: options.locals })
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
function createDurableObjectWebSocketMessageEvent(ws, message, env, state, options = {}) {
|
|
2024
|
+
return createAugmentedTarget(ws, {
|
|
2025
|
+
type: "durable-object-websocket-message",
|
|
2026
|
+
ctx: state,
|
|
2027
|
+
state,
|
|
2028
|
+
...prepareEventShell(env, { locals: options.locals }),
|
|
2029
|
+
ws,
|
|
2030
|
+
message
|
|
2031
|
+
});
|
|
2032
|
+
}
|
|
2033
|
+
function createDurableObjectWebSocketCloseEvent(ws, code, reason, wasClean, env, state, options = {}) {
|
|
2034
|
+
return createAugmentedTarget(ws, {
|
|
2035
|
+
type: "durable-object-websocket-close",
|
|
2036
|
+
ctx: state,
|
|
2037
|
+
state,
|
|
2038
|
+
...prepareEventShell(env, { locals: options.locals }),
|
|
2039
|
+
ws,
|
|
2040
|
+
code,
|
|
2041
|
+
reason,
|
|
2042
|
+
wasClean
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
function createDurableObjectWebSocketErrorEvent(ws, error, env, state, options = {}) {
|
|
2046
|
+
return createAugmentedTarget(ws, {
|
|
2047
|
+
type: "durable-object-websocket-error",
|
|
2048
|
+
ctx: state,
|
|
2049
|
+
state,
|
|
2050
|
+
...prepareEventShell(env, { locals: options.locals }),
|
|
2051
|
+
ws,
|
|
2052
|
+
error
|
|
2053
|
+
});
|
|
2054
|
+
}
|
|
2055
|
+
function createDefaultEvent(env, ctx, request, type, locals) {
|
|
2056
|
+
switch (type) {
|
|
2057
|
+
case "fetch":
|
|
2058
|
+
if (request && ctx) return createFetchEvent(request, env, ctx, { locals });
|
|
2059
|
+
return createBaseEvent(type, env, ctx, {
|
|
2060
|
+
locals,
|
|
2061
|
+
request
|
|
2062
|
+
});
|
|
2063
|
+
case "durable-object-fetch":
|
|
2064
|
+
if (request && ctx) return createDurableObjectFetchEvent(request, env, ctx, { locals });
|
|
2065
|
+
return createBaseEvent(type, env, ctx, {
|
|
2066
|
+
locals,
|
|
2067
|
+
request
|
|
2068
|
+
});
|
|
2069
|
+
case "durable-object-alarm":
|
|
2070
|
+
if (ctx) return createDurableObjectAlarmEvent(env, ctx, { locals });
|
|
2071
|
+
return createBaseEvent(type, env, ctx, { locals });
|
|
2072
|
+
case "queue":
|
|
2073
|
+
case "scheduled":
|
|
2074
|
+
case "email":
|
|
2075
|
+
case "tail":
|
|
2076
|
+
case "durable-object-websocket-message":
|
|
2077
|
+
case "durable-object-websocket-close":
|
|
2078
|
+
case "durable-object-websocket-error": return createBaseEvent(type, env, ctx, {
|
|
2079
|
+
locals,
|
|
2080
|
+
request
|
|
2081
|
+
});
|
|
2082
|
+
default: throw new Error(`createDefaultEvent: unknown event type ${String(type)}`);
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
//#endregion
|
|
2086
|
+
//#region src/runtime/validation.ts
|
|
2087
|
+
/**
|
|
2088
|
+
* Error thrown when accessing context properties outside an active handler trail
|
|
2089
|
+
*/
|
|
2090
|
+
var ContextAccessError = class ContextAccessError extends Error {
|
|
2091
|
+
contextName;
|
|
2092
|
+
propertyName;
|
|
2093
|
+
constructor(contextName, propertyName, message) {
|
|
2094
|
+
super(message ?? `Cannot access ${contextName}.${propertyName} outside of an active Devflare handler trail.\n\nThis typically happens when:\n 1. Accessing ${contextName} at module top-level (during import)\n 2. Accessing ${contextName} in a callback that runs after the handler ends\n 3. Accessing ${contextName} in a setTimeout/setInterval callback\n\nMove the access inside your handler function or middleware.`);
|
|
2095
|
+
this.name = "ContextAccessError";
|
|
2096
|
+
this.contextName = contextName;
|
|
2097
|
+
this.propertyName = propertyName;
|
|
2098
|
+
}
|
|
2099
|
+
/**
|
|
2100
|
+
* Builds a `ContextAccessError` for the "no active handler trail" failure mode
|
|
2101
|
+
* (no AsyncLocalStorage store), with guidance toward the most common causes.
|
|
2102
|
+
* Pass `message` to override the default `nodejs_compat`-mentioning guidance.
|
|
2103
|
+
*/
|
|
2104
|
+
static contextUnavailable(message) {
|
|
2105
|
+
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.\n\nThis usually means one of:\n\n1. Accessing context at module top-level (runs at cold start, not per-request)\n2. Accessing context in setTimeout/setInterval callbacks\n3. Missing 'nodejs_compat' compatibility flag in your worker config\n\nFix: Move the access inside your handler, middleware, or a helper called from that handler trail.\nLearn more: https://devflare.dev/docs/context-errors");
|
|
2106
|
+
}
|
|
2107
|
+
};
|
|
2108
|
+
function createContextProxy(getter, name, options = {}) {
|
|
2109
|
+
const mutable = options.mutable ?? true;
|
|
2110
|
+
return new Proxy({}, {
|
|
2111
|
+
get(_target, prop) {
|
|
2112
|
+
const ctx = getter();
|
|
2113
|
+
if (ctx === void 0 || ctx === null) throw new ContextAccessError(name, String(prop));
|
|
2114
|
+
return ctx[prop];
|
|
2115
|
+
},
|
|
2116
|
+
set(_target, prop, value) {
|
|
2117
|
+
if (!mutable) throw new TypeError(`Cannot assign to '${String(prop)}' on '${name}' because it is read-only.\nUse 'locals' for mutable request-scoped data.`);
|
|
2118
|
+
const ctx = getter();
|
|
2119
|
+
if (ctx === void 0 || ctx === null) throw new ContextAccessError(name, String(prop));
|
|
2120
|
+
ctx[prop] = value;
|
|
2121
|
+
return true;
|
|
2122
|
+
},
|
|
2123
|
+
deleteProperty(_target, prop) {
|
|
2124
|
+
if (!mutable) throw new TypeError(`Cannot delete property '${String(prop)}' from '${name}' because it is read-only.`);
|
|
2125
|
+
const ctx = getter();
|
|
2126
|
+
if (ctx === void 0 || ctx === null) return true;
|
|
2127
|
+
return Reflect.deleteProperty(ctx, prop);
|
|
2128
|
+
},
|
|
2129
|
+
has(_target, prop) {
|
|
2130
|
+
const ctx = getter();
|
|
2131
|
+
if (ctx === void 0 || ctx === null) return false;
|
|
2132
|
+
return prop in ctx;
|
|
2133
|
+
},
|
|
2134
|
+
ownKeys(_target) {
|
|
2135
|
+
const ctx = getter();
|
|
2136
|
+
if (ctx === void 0 || ctx === null) return [];
|
|
2137
|
+
return Reflect.ownKeys(ctx);
|
|
2138
|
+
},
|
|
2139
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
2140
|
+
const ctx = getter();
|
|
2141
|
+
if (ctx === void 0 || ctx === null) return;
|
|
2142
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(ctx, prop);
|
|
2143
|
+
if (!descriptor) return;
|
|
2144
|
+
if (!mutable) return {
|
|
2145
|
+
...descriptor,
|
|
2146
|
+
writable: false
|
|
2147
|
+
};
|
|
2148
|
+
return descriptor;
|
|
2149
|
+
}
|
|
2150
|
+
});
|
|
2151
|
+
}
|
|
2152
|
+
//#endregion
|
|
2153
|
+
//#region src/runtime/context.ts
|
|
2154
|
+
const storage = new AsyncLocalStorage();
|
|
2155
|
+
function createLocals() {
|
|
2156
|
+
return {};
|
|
2157
|
+
}
|
|
2158
|
+
function runWithContext(env, ctx, request, fn, type = "fetch") {
|
|
2159
|
+
return runWithEventContext(createDefaultEvent(env, ctx, request, type, createLocals()), fn);
|
|
2160
|
+
}
|
|
2161
|
+
function runWithEventContext(event, fn) {
|
|
2162
|
+
const context = {
|
|
2163
|
+
env: event.env,
|
|
2164
|
+
ctx: event.ctx,
|
|
2165
|
+
request: event.request ?? null,
|
|
2166
|
+
locals: event.locals,
|
|
2167
|
+
type: event.type,
|
|
2168
|
+
event
|
|
2169
|
+
};
|
|
2170
|
+
return storage.run(context, fn);
|
|
2171
|
+
}
|
|
2172
|
+
function getContext() {
|
|
2173
|
+
const context = storage.getStore();
|
|
2174
|
+
if (!context) throw ContextAccessError.contextUnavailable();
|
|
2175
|
+
return context;
|
|
2176
|
+
}
|
|
2177
|
+
function getContextOrNull() {
|
|
2178
|
+
return storage.getStore() ?? null;
|
|
2179
|
+
}
|
|
2180
|
+
function getEventContext() {
|
|
2181
|
+
return getContext().event;
|
|
2182
|
+
}
|
|
2183
|
+
function getEventContextOrNull() {
|
|
2184
|
+
return getContextOrNull()?.event ?? null;
|
|
2185
|
+
}
|
|
2186
|
+
function hasContext() {
|
|
2187
|
+
return storage.getStore() !== void 0;
|
|
2188
|
+
}
|
|
2189
|
+
function createEventAccessor(name, matcher) {
|
|
2190
|
+
const accessor = (() => {
|
|
2191
|
+
const currentEvent = getEventContextOrNull();
|
|
2192
|
+
if (!currentEvent) throw ContextAccessError.contextUnavailable();
|
|
2193
|
+
if (!matcher(currentEvent)) throw ContextAccessError.contextUnavailable(`${name} is not available in the current '${currentEvent.type}' context.
|
|
2194
|
+
|
|
2195
|
+
Devflare stores event objects in AsyncLocalStorage so helpers called within a handler can reach the active event.
|
|
2196
|
+
Use ${name}.safe() to return null instead of throwing, or call the getter that matches the active surface.`);
|
|
2197
|
+
return currentEvent;
|
|
2198
|
+
});
|
|
2199
|
+
accessor.safe = () => {
|
|
2200
|
+
const currentEvent = getEventContextOrNull();
|
|
2201
|
+
return currentEvent && matcher(currentEvent) ? currentEvent : null;
|
|
2202
|
+
};
|
|
2203
|
+
return accessor;
|
|
2204
|
+
}
|
|
2205
|
+
function isFetchEvent(event) {
|
|
2206
|
+
return event.type === "fetch" && event.request instanceof Request;
|
|
2207
|
+
}
|
|
2208
|
+
function isQueueEvent(event) {
|
|
2209
|
+
return event.type === "queue" && "batch" in event;
|
|
2210
|
+
}
|
|
2211
|
+
function isScheduledEvent(event) {
|
|
2212
|
+
return event.type === "scheduled" && "controller" in event;
|
|
2213
|
+
}
|
|
2214
|
+
function isEmailEvent(event) {
|
|
2215
|
+
return event.type === "email" && "message" in event;
|
|
2216
|
+
}
|
|
2217
|
+
function isTailEvent(event) {
|
|
2218
|
+
return event.type === "tail" && Array.isArray(event) && "events" in event;
|
|
2219
|
+
}
|
|
2220
|
+
function isDurableObjectEvent(event) {
|
|
2221
|
+
return event.type.startsWith("durable-object-") && "state" in event;
|
|
2222
|
+
}
|
|
2223
|
+
function isDurableObjectFetchEvent(event) {
|
|
2224
|
+
return event.type === "durable-object-fetch" && event.request instanceof Request;
|
|
2225
|
+
}
|
|
2226
|
+
function isDurableObjectAlarmEvent(event) {
|
|
2227
|
+
return event.type === "durable-object-alarm" && "state" in event;
|
|
2228
|
+
}
|
|
2229
|
+
function isDurableObjectWebSocketMessageEvent(event) {
|
|
2230
|
+
return event.type === "durable-object-websocket-message" && "ws" in event && "message" in event;
|
|
2231
|
+
}
|
|
2232
|
+
function isDurableObjectWebSocketCloseEvent(event) {
|
|
2233
|
+
return event.type === "durable-object-websocket-close" && "ws" in event && "code" in event;
|
|
2234
|
+
}
|
|
2235
|
+
function isDurableObjectWebSocketErrorEvent(event) {
|
|
2236
|
+
return event.type === "durable-object-websocket-error" && "ws" in event && "error" in event;
|
|
2237
|
+
}
|
|
2238
|
+
const getFetchEvent = createEventAccessor("getFetchEvent()", isFetchEvent);
|
|
2239
|
+
const getQueueEvent = createEventAccessor("getQueueEvent()", isQueueEvent);
|
|
2240
|
+
const getScheduledEvent = createEventAccessor("getScheduledEvent()", isScheduledEvent);
|
|
2241
|
+
const getEmailEvent = createEventAccessor("getEmailEvent()", isEmailEvent);
|
|
2242
|
+
const getTailEvent = createEventAccessor("getTailEvent()", isTailEvent);
|
|
2243
|
+
const getDurableObjectEvent = createEventAccessor("getDurableObjectEvent()", isDurableObjectEvent);
|
|
2244
|
+
const getDurableObjectFetchEvent = createEventAccessor("getDurableObjectFetchEvent()", isDurableObjectFetchEvent);
|
|
2245
|
+
const getDurableObjectAlarmEvent = createEventAccessor("getDurableObjectAlarmEvent()", isDurableObjectAlarmEvent);
|
|
2246
|
+
const getDurableObjectWebSocketMessageEvent = createEventAccessor("getDurableObjectWebSocketMessageEvent()", isDurableObjectWebSocketMessageEvent);
|
|
2247
|
+
const getDurableObjectWebSocketCloseEvent = createEventAccessor("getDurableObjectWebSocketCloseEvent()", isDurableObjectWebSocketCloseEvent);
|
|
2248
|
+
const getDurableObjectWebSocketErrorEvent = createEventAccessor("getDurableObjectWebSocketErrorEvent()", isDurableObjectWebSocketErrorEvent);
|
|
2249
|
+
//#endregion
|
|
2250
|
+
export { createTailEvent as A, createDurableObjectWebSocketCloseEvent as C, createFetchEvent as D, createEmailEvent as E, BridgeClient as F, getClient as I, createEnvProxy as M, initEnv as N, createQueueEvent as O, setBindingHints as P, createDurableObjectFetchEvent as S, createDurableObjectWebSocketMessageEvent as T, runWithContext as _, getDurableObjectFetchEvent as a, createContextProxy as b, getDurableObjectWebSocketMessageEvent as c, getEventContextOrNull as d, getFetchEvent as f, hasContext as g, getTailEvent as h, getDurableObjectEvent as i, bridgeEnv as j, createScheduledEvent as k, getEmailEvent as l, getScheduledEvent as m, getContextOrNull as n, getDurableObjectWebSocketCloseEvent as o, getQueueEvent as p, getDurableObjectAlarmEvent as r, getDurableObjectWebSocketErrorEvent as s, getContext as t, getEventContext as u, runWithEventContext as v, createDurableObjectWebSocketErrorEvent as w, createDurableObjectAlarmEvent as x, ContextAccessError as y };
|