@lovrozagar/honey 0.6.8 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +514 -192
- package/bin/honey.js +25 -0
- package/dist/accepts.d.ts +7 -1
- package/dist/accepts.d.ts.map +1 -1
- package/dist/accepts.js +126 -0
- package/dist/accepts.js.map +1 -0
- package/dist/body-kind.d.ts +26 -0
- package/dist/body-kind.d.ts.map +1 -0
- package/dist/body-kind.js +70 -0
- package/dist/body-kind.js.map +1 -0
- package/dist/body-limit.d.ts +5 -1
- package/dist/body-limit.d.ts.map +1 -1
- package/dist/body-limit.js +126 -0
- package/dist/body-limit.js.map +1 -0
- package/dist/build/index.d.ts +19 -3
- package/dist/build/index.d.ts.map +1 -1
- package/dist/build/index.js +173 -0
- package/dist/build/index.js.map +1 -0
- package/dist/cli-args.d.ts +33 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +102 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli-go/auth.go +26 -0
- package/dist/cli-go/config.go +192 -0
- package/dist/cli-go/errors.go +75 -0
- package/dist/cli-go/multipart.go +79 -0
- package/dist/cli-go/output.go +163 -0
- package/dist/cli-go/root.go +30 -0
- package/dist/cli-go/stream.go +88 -0
- package/dist/cli-go/version.go +5 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +209 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/defaults.js +48 -0
- package/dist/client/defaults.js.map +1 -0
- package/dist/client/error.d.ts +35 -0
- package/dist/client/error.d.ts.map +1 -1
- package/dist/client/error.js +71 -0
- package/dist/client/error.js.map +1 -0
- package/dist/client/http.d.ts +67 -8
- package/dist/client/http.d.ts.map +1 -1
- package/dist/client/http.js +571 -0
- package/dist/client/http.js.map +1 -0
- package/dist/client/index.d.ts +3 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +95 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/path.d.ts +26 -0
- package/dist/client/path.d.ts.map +1 -0
- package/dist/client/path.js +163 -0
- package/dist/client/path.js.map +1 -0
- package/dist/client/redirect-policy.d.ts +12 -0
- package/dist/client/redirect-policy.d.ts.map +1 -0
- package/dist/client/redirect-policy.js +20 -0
- package/dist/client/redirect-policy.js.map +1 -0
- package/dist/client/sdk.d.ts +36 -0
- package/dist/client/sdk.d.ts.map +1 -1
- package/dist/client/sdk.js +292 -0
- package/dist/client/sdk.js.map +1 -0
- package/dist/client/sse.d.ts +13 -0
- package/dist/client/sse.d.ts.map +1 -1
- package/dist/client/sse.js +129 -0
- package/dist/client/sse.js.map +1 -0
- package/dist/client/types.js +2 -0
- package/dist/client/types.js.map +1 -0
- package/dist/client/ws.d.ts +9 -2
- package/dist/client/ws.d.ts.map +1 -1
- package/dist/client/ws.js +112 -0
- package/dist/client/ws.js.map +1 -0
- package/dist/client-go/errors.go +236 -0
- package/dist/client-go/export.go +44 -0
- package/dist/client-go/invalidation.go +371 -0
- package/dist/client-go/nullable.go +62 -0
- package/dist/client-go/realtime.go +354 -0
- package/dist/client-go/result.go +20 -0
- package/dist/client-go/runtime.go +975 -0
- package/dist/client-go/sse.go +159 -0
- package/dist/client-go/transport.go +495 -0
- package/dist/client-go/ws.go +128 -0
- package/dist/client-info.d.ts +36 -0
- package/dist/client-info.d.ts.map +1 -0
- package/dist/client-info.js +53 -0
- package/dist/client-info.js.map +1 -0
- package/dist/client-mcp/README.md +10 -0
- package/dist/client-mcp/server.ts +221 -0
- package/dist/client-mcp/types.ts +19 -0
- package/dist/client-python/_errors.py +115 -0
- package/dist/client-python/_invalidation.py +494 -0
- package/dist/client-python/_realtime.py +179 -0
- package/dist/client-python/_runtime.py +860 -0
- package/dist/client-python/_sse.py +155 -0
- package/dist/client-python/_transport.py +366 -0
- package/dist/client-python/_ws.py +159 -0
- package/dist/client-python/py.typed +0 -0
- package/dist/client-rust/errors.rs +220 -0
- package/dist/client-rust/invalidation.rs +412 -0
- package/dist/client-rust/invalidation_sync.rs +93 -0
- package/dist/client-rust/nullable.rs +17 -0
- package/dist/client-rust/realtime.rs +702 -0
- package/dist/client-rust/result.rs +22 -0
- package/dist/client-rust/runtime.rs +980 -0
- package/dist/client-rust/runtime_sync.rs +484 -0
- package/dist/client-rust/sse.rs +188 -0
- package/dist/client-rust/ws.rs +167 -0
- package/dist/codegen-go-cli.d.ts.map +1 -1
- package/dist/codegen-go-cli.js +964 -0
- package/dist/codegen-go-cli.js.map +1 -0
- package/dist/codegen-go.d.ts +15 -3
- package/dist/codegen-go.d.ts.map +1 -1
- package/dist/codegen-go.js +872 -0
- package/dist/codegen-go.js.map +1 -0
- package/dist/codegen-hash.js +9 -0
- package/dist/codegen-hash.js.map +1 -0
- package/dist/codegen-ir.d.ts +69 -2
- package/dist/codegen-ir.d.ts.map +1 -1
- package/dist/codegen-ir.js +661 -0
- package/dist/codegen-ir.js.map +1 -0
- package/dist/codegen-lang.d.ts +65 -0
- package/dist/codegen-lang.d.ts.map +1 -0
- package/dist/codegen-lang.js +526 -0
- package/dist/codegen-lang.js.map +1 -0
- package/dist/codegen-load.d.ts +31 -0
- package/dist/codegen-load.d.ts.map +1 -0
- package/dist/codegen-load.js +138 -0
- package/dist/codegen-load.js.map +1 -0
- package/dist/codegen-loaders.js +55 -0
- package/dist/codegen-loaders.js.map +1 -0
- package/dist/codegen-mcp.d.ts.map +1 -1
- package/dist/codegen-mcp.js +368 -0
- package/dist/codegen-mcp.js.map +1 -0
- package/dist/codegen-python.d.ts +13 -1
- package/dist/codegen-python.d.ts.map +1 -1
- package/dist/codegen-python.js +828 -0
- package/dist/codegen-python.js.map +1 -0
- package/dist/codegen-route-tree-intern.d.ts +15 -5
- package/dist/codegen-route-tree-intern.d.ts.map +1 -1
- package/dist/codegen-route-tree-intern.js +221 -0
- package/dist/codegen-route-tree-intern.js.map +1 -0
- package/dist/codegen-rust.d.ts.map +1 -1
- package/dist/codegen-rust.js +1293 -0
- package/dist/codegen-rust.js.map +1 -0
- package/dist/codegen-sanitize.d.ts.map +1 -1
- package/dist/codegen-sanitize.js +56 -0
- package/dist/codegen-sanitize.js.map +1 -0
- package/dist/codegen-schema-naming.d.ts +5 -0
- package/dist/codegen-schema-naming.d.ts.map +1 -1
- package/dist/codegen-schema-naming.js +150 -0
- package/dist/codegen-schema-naming.js.map +1 -0
- package/dist/codegen-sdk-model.d.ts +71 -0
- package/dist/codegen-sdk-model.d.ts.map +1 -0
- package/dist/codegen-sdk-model.js +179 -0
- package/dist/codegen-sdk-model.js.map +1 -0
- package/dist/codegen.d.ts +41 -23
- package/dist/codegen.d.ts.map +1 -1
- package/dist/codegen.js +4610 -0
- package/dist/codegen.js.map +1 -0
- package/dist/context.d.ts +36 -6
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +242 -0
- package/dist/context.js.map +1 -0
- package/dist/cookie-sign.d.ts +16 -2
- package/dist/cookie-sign.d.ts.map +1 -1
- package/dist/cookie-sign.js +104 -0
- package/dist/cookie-sign.js.map +1 -0
- package/dist/cookie.d.ts +12 -0
- package/dist/cookie.d.ts.map +1 -1
- package/dist/cookie.js +138 -0
- package/dist/cookie.js.map +1 -0
- package/dist/cors.d.ts +1 -0
- package/dist/cors.d.ts.map +1 -1
- package/dist/cors.js +87 -0
- package/dist/cors.js.map +1 -0
- package/dist/crypto.d.ts +6 -1
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +38 -0
- package/dist/crypto.js.map +1 -0
- package/dist/csrf.d.ts +19 -0
- package/dist/csrf.d.ts.map +1 -1
- package/dist/csrf.js +79 -0
- package/dist/csrf.js.map +1 -0
- package/dist/curl-logger.d.ts +14 -3
- package/dist/curl-logger.d.ts.map +1 -1
- package/dist/curl-logger.js +199 -0
- package/dist/curl-logger.js.map +1 -0
- package/dist/detect-runtime.js +13 -0
- package/dist/detect-runtime.js.map +1 -0
- package/dist/dict.d.ts +11 -0
- package/dist/dict.d.ts.map +1 -0
- package/dist/dict.js +13 -0
- package/dist/dict.js.map +1 -0
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +44 -0
- package/dist/error.js.map +1 -0
- package/dist/errors.js +39 -0
- package/dist/errors.js.map +1 -0
- package/dist/etag.d.ts +2 -0
- package/dist/etag.d.ts.map +1 -1
- package/dist/etag.js +82 -0
- package/dist/etag.js.map +1 -0
- package/dist/feature-detect.d.ts +25 -0
- package/dist/feature-detect.d.ts.map +1 -0
- package/dist/feature-detect.js +144 -0
- package/dist/feature-detect.js.map +1 -0
- package/dist/feature-load.js +36 -0
- package/dist/feature-load.js.map +1 -0
- package/dist/feature-slots.d.ts +44 -0
- package/dist/feature-slots.d.ts.map +1 -0
- package/dist/feature-slots.js +48 -0
- package/dist/feature-slots.js.map +1 -0
- package/dist/fetch-request.d.ts +10 -0
- package/dist/fetch-request.d.ts.map +1 -0
- package/dist/fetch-request.js +13 -0
- package/dist/fetch-request.js.map +1 -0
- package/dist/gen-process.d.ts +15 -0
- package/dist/gen-process.d.ts.map +1 -0
- package/dist/gen-process.js +43 -0
- package/dist/gen-process.js.map +1 -0
- package/dist/gen-write.d.ts +19 -0
- package/dist/gen-write.d.ts.map +1 -0
- package/dist/gen-write.js +120 -0
- package/dist/gen-write.js.map +1 -0
- package/dist/glob.d.ts +21 -0
- package/dist/glob.d.ts.map +1 -0
- package/dist/glob.js +115 -0
- package/dist/glob.js.map +1 -0
- package/dist/go-type-emitter.d.ts +18 -4
- package/dist/go-type-emitter.d.ts.map +1 -1
- package/dist/go-type-emitter.js +594 -0
- package/dist/go-type-emitter.js.map +1 -0
- package/dist/honey-response.d.ts.map +1 -1
- package/dist/honey-response.js +338 -0
- package/dist/honey-response.js.map +1 -0
- package/dist/i18n-slot.d.ts +8 -0
- package/dist/i18n-slot.d.ts.map +1 -1
- package/dist/i18n-slot.js +14 -0
- package/dist/i18n-slot.js.map +1 -0
- package/dist/i18n.d.ts +3 -0
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +250 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +408 -148
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2324 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +3 -5
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +140 -0
- package/dist/init.js.map +1 -0
- package/dist/input.js +4 -0
- package/dist/input.js.map +1 -0
- package/dist/invalidate-check.d.ts +11 -0
- package/dist/invalidate-check.d.ts.map +1 -1
- package/dist/invalidate-check.js +163 -0
- package/dist/invalidate-check.js.map +1 -0
- package/dist/invoke-user.d.ts +35 -0
- package/dist/invoke-user.d.ts.map +1 -0
- package/dist/invoke-user.js +73 -0
- package/dist/invoke-user.js.map +1 -0
- package/dist/ip-restrict.d.ts +13 -1
- package/dist/ip-restrict.d.ts.map +1 -1
- package/dist/ip-restrict.js +60 -0
- package/dist/ip-restrict.js.map +1 -0
- package/dist/ip.d.ts +39 -0
- package/dist/ip.d.ts.map +1 -0
- package/dist/ip.js +209 -0
- package/dist/ip.js.map +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +113 -0
- package/dist/logger.js.map +1 -0
- package/dist/media-type.d.ts +30 -0
- package/dist/media-type.d.ts.map +1 -0
- package/dist/media-type.js +97 -0
- package/dist/media-type.js.map +1 -0
- package/dist/meta-spec-merge.d.ts +32 -0
- package/dist/meta-spec-merge.d.ts.map +1 -0
- package/dist/meta-spec-merge.js +68 -0
- package/dist/meta-spec-merge.js.map +1 -0
- package/dist/meta-spec.d.ts +16 -3
- package/dist/meta-spec.d.ts.map +1 -1
- package/dist/meta-spec.js +535 -0
- package/dist/meta-spec.js.map +1 -0
- package/dist/middleware.d.ts +23 -6
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +253 -0
- package/dist/middleware.js.map +1 -0
- package/dist/node-request.d.ts +57 -12
- package/dist/node-request.d.ts.map +1 -1
- package/dist/node-request.js +407 -0
- package/dist/node-request.js.map +1 -0
- package/dist/node.d.ts +20 -3
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +396 -0
- package/dist/node.js.map +1 -0
- package/dist/openapi/collect.d.ts +6 -3
- package/dist/openapi/collect.d.ts.map +1 -1
- package/dist/openapi/collect.js +30 -0
- package/dist/openapi/collect.js.map +1 -0
- package/dist/openapi/docs-page.d.ts +42 -0
- package/dist/openapi/docs-page.d.ts.map +1 -0
- package/dist/openapi/docs-page.js +80 -0
- package/dist/openapi/docs-page.js.map +1 -0
- package/dist/openapi/document.d.ts +4 -0
- package/dist/openapi/document.d.ts.map +1 -1
- package/dist/openapi/document.js +785 -0
- package/dist/openapi/document.js.map +1 -0
- package/dist/openapi/json-schema-slot.d.ts +7 -0
- package/dist/openapi/json-schema-slot.d.ts.map +1 -1
- package/dist/openapi/json-schema-slot.js +38 -0
- package/dist/openapi/json-schema-slot.js.map +1 -0
- package/dist/openapi/register.d.ts.map +1 -1
- package/dist/openapi/register.js +20 -0
- package/dist/openapi/register.js.map +1 -0
- package/dist/openapi/scalar.d.ts +3 -1
- package/dist/openapi/scalar.d.ts.map +1 -1
- package/dist/openapi/scalar.js +21 -0
- package/dist/openapi/scalar.js.map +1 -0
- package/dist/openapi/serve.d.ts +9 -0
- package/dist/openapi/serve.d.ts.map +1 -0
- package/dist/openapi/serve.js +36 -0
- package/dist/openapi/serve.js.map +1 -0
- package/dist/openapi/spec-factory.d.ts +30 -1
- package/dist/openapi/spec-factory.d.ts.map +1 -1
- package/dist/openapi/spec-factory.js +52 -0
- package/dist/openapi/spec-factory.js.map +1 -0
- package/dist/openapi/spec.d.ts +14 -5
- package/dist/openapi/spec.d.ts.map +1 -1
- package/dist/openapi/spec.js +50 -0
- package/dist/openapi/spec.js.map +1 -0
- package/dist/openapi/swagger.d.ts +3 -1
- package/dist/openapi/swagger.d.ts.map +1 -1
- package/dist/openapi/swagger.js +22 -0
- package/dist/openapi/swagger.js.map +1 -0
- package/dist/pattern.d.ts +71 -0
- package/dist/pattern.d.ts.map +1 -0
- package/dist/pattern.js +239 -0
- package/dist/pattern.js.map +1 -0
- package/dist/peer.d.ts +17 -0
- package/dist/peer.d.ts.map +1 -0
- package/dist/peer.js +50 -0
- package/dist/peer.js.map +1 -0
- package/dist/plugin.d.ts +67 -16
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +649 -0
- package/dist/plugin.js.map +1 -0
- package/dist/powered-by.d.ts.map +1 -1
- package/dist/powered-by.js +11 -0
- package/dist/powered-by.js.map +1 -0
- package/dist/pretty-json.d.ts.map +1 -1
- package/dist/pretty-json.js +47 -0
- package/dist/pretty-json.js.map +1 -0
- package/dist/producer-stream.d.ts +47 -0
- package/dist/producer-stream.d.ts.map +1 -0
- package/dist/producer-stream.js +267 -0
- package/dist/producer-stream.js.map +1 -0
- package/dist/proxy.d.ts +47 -8
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +274 -0
- package/dist/proxy.js.map +1 -0
- package/dist/python-type-emitter.d.ts +14 -1
- package/dist/python-type-emitter.d.ts.map +1 -1
- package/dist/python-type-emitter.js +157 -0
- package/dist/python-type-emitter.js.map +1 -0
- package/dist/realtime/bus.d.ts +17 -1
- package/dist/realtime/bus.d.ts.map +1 -1
- package/dist/realtime/bus.js +112 -0
- package/dist/realtime/bus.js.map +1 -0
- package/dist/realtime/register.d.ts +3 -0
- package/dist/realtime/register.d.ts.map +1 -0
- package/dist/realtime/register.js +10 -0
- package/dist/realtime/register.js.map +1 -0
- package/dist/realtime/route.d.ts +65 -26
- package/dist/realtime/route.d.ts.map +1 -1
- package/dist/realtime/route.js +72 -0
- package/dist/realtime/route.js.map +1 -0
- package/dist/realtime/server.d.ts +43 -0
- package/dist/realtime/server.d.ts.map +1 -0
- package/dist/realtime/server.js +255 -0
- package/dist/realtime/server.js.map +1 -0
- package/dist/request-id.d.ts +7 -0
- package/dist/request-id.d.ts.map +1 -1
- package/dist/request-id.js +16 -0
- package/dist/request-id.js.map +1 -0
- package/dist/request-limits.d.ts +3 -0
- package/dist/request-limits.d.ts.map +1 -0
- package/dist/request-limits.js +3 -0
- package/dist/request-limits.js.map +1 -0
- package/dist/request-path.d.ts +33 -0
- package/dist/request-path.d.ts.map +1 -0
- package/dist/request-path.js +178 -0
- package/dist/request-path.js.map +1 -0
- package/dist/request-to-curl.d.ts +7 -1
- package/dist/request-to-curl.d.ts.map +1 -1
- package/dist/request-to-curl.js +48 -0
- package/dist/request-to-curl.js.map +1 -0
- package/dist/response.d.ts +25 -2
- package/dist/response.d.ts.map +1 -1
- package/dist/response.js +313 -0
- package/dist/response.js.map +1 -0
- package/dist/rust-type-emitter.d.ts +14 -2
- package/dist/rust-type-emitter.d.ts.map +1 -1
- package/dist/rust-type-emitter.js +463 -0
- package/dist/rust-type-emitter.js.map +1 -0
- package/dist/secure-headers.d.ts.map +1 -1
- package/dist/secure-headers.js +53 -0
- package/dist/secure-headers.js.map +1 -0
- package/dist/serve-register.d.ts +4 -0
- package/dist/serve-register.d.ts.map +1 -1
- package/dist/serve-register.js +9 -0
- package/dist/serve-register.js.map +1 -0
- package/dist/serve-slot.d.ts +3 -0
- package/dist/serve-slot.d.ts.map +1 -1
- package/dist/serve-slot.js +52 -0
- package/dist/serve-slot.js.map +1 -0
- package/dist/serve.d.ts +18 -1
- package/dist/serve.d.ts.map +1 -1
- package/dist/serve.js +157 -0
- package/dist/serve.js.map +1 -0
- package/dist/server-timing.d.ts.map +1 -1
- package/dist/server-timing.js +51 -0
- package/dist/server-timing.js.map +1 -0
- package/dist/static.d.ts +9 -0
- package/dist/static.d.ts.map +1 -1
- package/dist/static.js +102 -0
- package/dist/static.js.map +1 -0
- package/dist/telemetry/otel.d.ts +2 -0
- package/dist/telemetry/otel.d.ts.map +1 -1
- package/dist/telemetry/otel.js +135 -0
- package/dist/telemetry/otel.js.map +1 -0
- package/dist/testing.d.ts +12 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +124 -0
- package/dist/testing.js.map +1 -0
- package/dist/timeout.d.ts +6 -0
- package/dist/timeout.d.ts.map +1 -1
- package/dist/timeout.js +36 -0
- package/dist/timeout.js.map +1 -0
- package/dist/tree.d.ts +133 -36
- package/dist/tree.d.ts.map +1 -1
- package/dist/tree.js +437 -0
- package/dist/tree.js.map +1 -0
- package/dist/trust.d.ts +21 -0
- package/dist/trust.d.ts.map +1 -0
- package/dist/trust.js +100 -0
- package/dist/trust.js.map +1 -0
- package/dist/ts-type-emitter.d.ts.map +1 -1
- package/dist/ts-type-emitter.js +150 -0
- package/dist/ts-type-emitter.js.map +1 -0
- package/dist/type-emitter.d.ts +16 -2
- package/dist/type-emitter.d.ts.map +1 -1
- package/dist/type-emitter.js +729 -0
- package/dist/type-emitter.js.map +1 -0
- package/dist/type-extractor.d.ts +8 -4
- package/dist/type-extractor.d.ts.map +1 -1
- package/dist/type-extractor.js +819 -0
- package/dist/type-extractor.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +96 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +14 -2
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +335 -0
- package/dist/validation.js.map +1 -0
- package/dist/with-headers.d.ts +15 -0
- package/dist/with-headers.d.ts.map +1 -0
- package/dist/with-headers.js +45 -0
- package/dist/with-headers.js.map +1 -0
- package/dist/ws/bun.d.ts +11 -5
- package/dist/ws/bun.d.ts.map +1 -1
- package/dist/ws/bun.js +82 -0
- package/dist/ws/bun.js.map +1 -0
- package/dist/ws/cloudflare.d.ts +25 -3
- package/dist/ws/cloudflare.d.ts.map +1 -1
- package/dist/ws/cloudflare.js +117 -0
- package/dist/ws/cloudflare.js.map +1 -0
- package/dist/ws/deno.d.ts +4 -4
- package/dist/ws/deno.d.ts.map +1 -1
- package/dist/ws/deno.js +133 -0
- package/dist/ws/deno.js.map +1 -0
- package/dist/ws/node.d.ts +20 -3
- package/dist/ws/node.d.ts.map +1 -1
- package/dist/ws/node.js +173 -0
- package/dist/ws/node.js.map +1 -0
- package/dist/ws/session.d.ts +11 -0
- package/dist/ws/session.d.ts.map +1 -0
- package/dist/ws/session.js +60 -0
- package/dist/ws/session.js.map +1 -0
- package/dist/ws/shared.d.ts +65 -0
- package/dist/ws/shared.d.ts.map +1 -0
- package/dist/ws/shared.js +103 -0
- package/dist/ws/shared.js.map +1 -0
- package/dist/ws-origin.d.ts +20 -0
- package/dist/ws-origin.d.ts.map +1 -0
- package/dist/ws-origin.js +41 -0
- package/dist/ws-origin.js.map +1 -0
- package/dist/yaml.d.ts +15 -1
- package/dist/yaml.d.ts.map +1 -1
- package/dist/yaml.js +101 -0
- package/dist/yaml.js.map +1 -0
- package/docs/invalidate-spec.md +13 -1
- package/docs/meta-spec.md +36 -12
- package/docs/packaging.md +43 -24
- package/docs/regression-matrix/README.md +32 -0
- package/docs/regression-matrix/review.md +44 -0
- package/docs/regression-matrix/ws1-3.md +97 -0
- package/docs/regression-matrix/ws4-8.md +107 -0
- package/docs/regression-matrix/ws9-12.md +266 -0
- package/docs/sdk.md +102 -52
- package/package.json +183 -52
- package/src/accepts.ts +91 -33
- package/src/body-kind.ts +67 -0
- package/src/body-limit.ts +102 -87
- package/src/build/index.ts +104 -54
- package/src/cli-args.ts +123 -0
- package/src/cli-go/auth.go +12 -1
- package/src/cli-go/config.go +29 -2
- package/src/cli-go/errors.go +28 -10
- package/src/cli-go/multipart.go +51 -27
- package/src/cli-go/output.go +58 -4
- package/src/cli-go/root.go +1 -1
- package/src/cli-go/version.go +2 -2
- package/src/cli.ts +154 -148
- package/src/client/error.ts +56 -1
- package/src/client/http.ts +479 -256
- package/src/client/index.ts +55 -17
- package/src/client/path.ts +169 -0
- package/src/client/redirect-policy.ts +19 -0
- package/src/client/sdk.ts +180 -101
- package/src/client/sse.ts +92 -66
- package/src/client/ws.ts +67 -31
- package/src/client-go/errors.go +41 -12
- package/src/client-go/export.go +44 -0
- package/src/client-go/invalidation.go +52 -54
- package/src/client-go/nullable.go +62 -0
- package/src/client-go/realtime.go +147 -110
- package/src/client-go/runtime.go +646 -88
- package/src/client-go/sse.go +104 -94
- package/src/client-go/transport.go +67 -27
- package/src/client-go/ws.go +49 -25
- package/src/client-info.ts +79 -0
- package/src/client-mcp/server.ts +133 -3
- package/src/client-python/_invalidation.py +207 -291
- package/src/client-python/_realtime.py +63 -40
- package/src/client-python/_runtime.py +501 -119
- package/src/client-python/_sse.py +130 -74
- package/src/client-python/_transport.py +37 -9
- package/src/client-python/_ws.py +50 -22
- package/src/client-rust/errors.rs +21 -1
- package/src/client-rust/invalidation.rs +202 -231
- package/src/client-rust/invalidation_sync.rs +16 -229
- package/src/client-rust/nullable.rs +17 -0
- package/src/client-rust/realtime.rs +217 -217
- package/src/client-rust/runtime.rs +602 -177
- package/src/client-rust/runtime_sync.rs +169 -145
- package/src/client-rust/sse.rs +142 -121
- package/src/client-rust/ws.rs +61 -37
- package/src/codegen-go-cli.ts +607 -728
- package/src/codegen-go.ts +710 -770
- package/src/codegen-ir.ts +381 -75
- package/src/codegen-lang.ts +517 -0
- package/src/codegen-load.ts +150 -0
- package/src/codegen-mcp.ts +207 -108
- package/src/codegen-python.ts +684 -816
- package/src/codegen-route-tree-intern.ts +51 -25
- package/src/codegen-rust.ts +946 -1240
- package/src/codegen-sanitize.ts +0 -4
- package/src/codegen-schema-naming.ts +19 -6
- package/src/codegen-sdk-model.ts +228 -0
- package/src/codegen.ts +1488 -1140
- package/src/context.ts +130 -11
- package/src/cookie-sign.ts +85 -16
- package/src/cookie.ts +66 -11
- package/src/cors.ts +55 -54
- package/src/crypto.ts +27 -5
- package/src/csrf.ts +57 -25
- package/src/curl-logger.ts +155 -114
- package/src/dict.ts +12 -0
- package/src/error.ts +4 -2
- package/src/etag.ts +58 -34
- package/src/feature-detect.ts +147 -0
- package/src/feature-slots.ts +70 -0
- package/src/fetch-request.ts +13 -0
- package/src/gen-process.ts +42 -0
- package/src/gen-write.ts +127 -0
- package/src/glob.ts +109 -0
- package/src/go-type-emitter.ts +406 -155
- package/src/honey-response.ts +36 -9
- package/src/i18n-slot.ts +10 -0
- package/src/i18n.ts +98 -23
- package/src/index.ts +1887 -1756
- package/src/init.ts +40 -28
- package/src/invalidate-check.ts +42 -4
- package/src/invoke-user.ts +95 -0
- package/src/ip-restrict.ts +47 -161
- package/src/ip.ts +194 -0
- package/src/logger.ts +65 -36
- package/src/media-type.ts +104 -0
- package/src/meta-spec-merge.ts +80 -0
- package/src/meta-spec.ts +0 -0
- package/src/middleware.ts +112 -12
- package/src/node-request.ts +242 -52
- package/src/node.ts +318 -75
- package/src/openapi/collect.ts +19 -44
- package/src/openapi/docs-page.ts +89 -0
- package/src/openapi/document.ts +503 -224
- package/src/openapi/json-schema-slot.ts +40 -0
- package/src/openapi/register.ts +7 -2
- package/src/openapi/scalar.ts +11 -10
- package/src/openapi/serve.ts +39 -0
- package/src/openapi/spec-factory.ts +50 -1
- package/src/openapi/spec.ts +53 -30
- package/src/openapi/swagger.ts +12 -11
- package/src/pattern.ts +245 -0
- package/src/peer.ts +53 -0
- package/src/plugin.ts +270 -185
- package/src/powered-by.ts +2 -2
- package/src/pretty-json.ts +25 -9
- package/src/producer-stream.ts +296 -0
- package/src/proxy.ts +253 -55
- package/src/python-type-emitter.ts +68 -56
- package/src/realtime/bus.ts +56 -9
- package/src/realtime/register.ts +13 -0
- package/src/realtime/route.ts +129 -80
- package/src/realtime/server.ts +298 -0
- package/src/request-id.ts +13 -3
- package/src/request-limits.ts +2 -0
- package/src/request-path.ts +165 -0
- package/src/request-to-curl.ts +28 -7
- package/src/response.ts +143 -103
- package/src/rust-type-emitter.ts +265 -170
- package/src/secure-headers.ts +8 -4
- package/src/serve-register.ts +4 -0
- package/src/serve-slot.ts +38 -0
- package/src/serve.ts +113 -25
- package/src/server-timing.ts +11 -7
- package/src/static.ts +85 -32
- package/src/telemetry/otel.ts +29 -7
- package/src/testing.ts +76 -14
- package/src/timeout.ts +15 -7
- package/src/tree.ts +405 -333
- package/src/trust.ts +117 -0
- package/src/ts-type-emitter.ts +18 -12
- package/src/type-emitter.ts +227 -89
- package/src/type-extractor.ts +603 -423
- package/src/types.ts +8 -0
- package/src/validation.ts +221 -96
- package/src/with-headers.ts +45 -0
- package/src/ws/bun.ts +53 -15
- package/src/ws/cloudflare.ts +81 -19
- package/src/ws/deno.ts +124 -36
- package/src/ws/node.ts +173 -79
- package/src/ws/session.ts +73 -0
- package/src/ws/shared.ts +140 -0
- package/src/ws-origin.ts +53 -0
- package/src/yaml.ts +45 -22
- package/dist/client-mcp/server.d.ts +0 -10
- package/dist/client-mcp/server.d.ts.map +0 -1
- package/dist/client-mcp/types.d.ts +0 -16
- package/dist/client-mcp/types.d.ts.map +0 -1
- package/dist/cloudflare/realtime.d.ts +0 -30
- package/dist/cloudflare/realtime.d.ts.map +0 -1
- package/dist/realtime/buffer.d.ts +0 -18
- package/dist/realtime/buffer.d.ts.map +0 -1
- package/dist/realtime/longpoll.d.ts +0 -23
- package/dist/realtime/longpoll.d.ts.map +0 -1
- package/dist/realtime/protocol.d.ts +0 -50
- package/dist/realtime/protocol.d.ts.map +0 -1
- package/dist/realtime/runtime.d.ts +0 -74
- package/dist/realtime/runtime.d.ts.map +0 -1
- package/src/cloudflare/realtime.ts +0 -234
- package/src/realtime/buffer.ts +0 -101
- package/src/realtime/longpoll.ts +0 -148
- package/src/realtime/protocol.ts +0 -128
- package/src/realtime/runtime.ts +0 -427
package/src/ws/node.ts
CHANGED
|
@@ -1,36 +1,58 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {
|
|
2
|
+
type RawSocket,
|
|
3
|
+
type WSAdapter,
|
|
4
|
+
type WSAdapterOptions,
|
|
5
|
+
type WSContext,
|
|
6
|
+
WSContextImpl,
|
|
7
|
+
type WSHandler,
|
|
8
|
+
} from "./cloudflare.ts"
|
|
2
9
|
|
|
3
10
|
import type { WSAdapter, WSHandler } from "./cloudflare.ts"
|
|
4
|
-
import { WSContextImpl } from "./cloudflare.ts"
|
|
11
|
+
import { fireHandler, WSContextImpl } from "./cloudflare.ts"
|
|
12
|
+
import {
|
|
13
|
+
type ResolvedWSOptions,
|
|
14
|
+
resolveWSOptions,
|
|
15
|
+
selectProtocol,
|
|
16
|
+
toArrayBuffer,
|
|
17
|
+
type WSAdapterOptions,
|
|
18
|
+
} from "./shared.ts"
|
|
19
|
+
|
|
20
|
+
type WebSocketServerOptions = {
|
|
21
|
+
handleProtocols?: (protocols: Set<string>, req: unknown) => string | false
|
|
22
|
+
maxPayload: number
|
|
23
|
+
noServer: true
|
|
24
|
+
perMessageDeflate: boolean
|
|
25
|
+
}
|
|
5
26
|
|
|
6
27
|
type WsModule = {
|
|
7
|
-
WebSocketServer: new (opts:
|
|
8
|
-
handleUpgrade(req: unknown, socket: unknown, head: unknown, cb: (ws: NodeWS) => void): void
|
|
9
|
-
}
|
|
28
|
+
WebSocketServer: new (opts: WebSocketServerOptions) => WssInstance
|
|
10
29
|
}
|
|
11
30
|
|
|
12
31
|
type NodeWS = {
|
|
32
|
+
binaryType: string
|
|
33
|
+
bufferedAmount: number
|
|
13
34
|
close(code?: number, reason?: string): void
|
|
14
35
|
on(event: "close", cb: (code: number, reason: Buffer) => void): void
|
|
15
36
|
on(event: "error", cb: (err: unknown) => void): void
|
|
16
|
-
on(event: "message", cb: (data:
|
|
17
|
-
on(event: "pong", cb: () => void): void
|
|
37
|
+
on(event: "message", cb: (data: ArrayBuffer | Buffer | Buffer[], isBinary: boolean) => void): void
|
|
38
|
+
on(event: "pong" | "ping", cb: () => void): void
|
|
18
39
|
ping(): void
|
|
19
40
|
readyState: number
|
|
20
41
|
send(data: ArrayBuffer | Buffer | Uint8Array | string): void
|
|
42
|
+
terminate(): void
|
|
21
43
|
}
|
|
22
44
|
|
|
23
|
-
|
|
45
|
+
/**
|
|
46
|
+
* What the Node adapter (`serve()`) puts on `env.__nodeUpgrade`. `upgraded` turns true once the
|
|
47
|
+
* 101 is written: from then on the socket belongs to `ws`, and the adapter must not write to it.
|
|
48
|
+
*/
|
|
49
|
+
export type NodeUpgradeData = {
|
|
24
50
|
head: Buffer
|
|
25
51
|
req: unknown
|
|
26
52
|
socket: unknown
|
|
53
|
+
upgraded: boolean
|
|
27
54
|
}
|
|
28
55
|
|
|
29
|
-
/**
|
|
30
|
-
* Node.js WebSocket adapter.
|
|
31
|
-
* Requires the `ws` package. Creates a no-server WebSocketServer internally.
|
|
32
|
-
* Reads __nodeUpgrade from env (placed there by serve()).
|
|
33
|
-
*/
|
|
34
56
|
type WssInstance = {
|
|
35
57
|
handleUpgrade(req: unknown, socket: unknown, head: unknown, cb: (ws: NodeWS) => void): void
|
|
36
58
|
}
|
|
@@ -40,96 +62,166 @@ type KeepaliveConfig = {
|
|
|
40
62
|
timeout: number
|
|
41
63
|
}
|
|
42
64
|
|
|
43
|
-
export
|
|
65
|
+
export type NodeWebSocketOptions = WSAdapterOptions & {
|
|
66
|
+
/** Ping every `interval` ms; a pong missing after `timeout` ms terminates the connection. */
|
|
67
|
+
keepalive?: KeepaliveConfig
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const WS_MISSING =
|
|
71
|
+
'WebSocket routes on Node need the "ws" package, which is an optional peer dependency of honey. Install it: npm install ws'
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Node.js WebSocket adapter, on the `ws` package (an optional peer dependency). It reads
|
|
75
|
+
* `env.__nodeUpgrade`, which honey's `serve()` puts there for an upgrade request.
|
|
76
|
+
*/
|
|
77
|
+
export function nodeWebSocket(opts?: NodeWebSocketOptions): WSAdapter {
|
|
78
|
+
const options: ResolvedWSOptions = resolveWSOptions(opts)
|
|
79
|
+
const keepalive = opts?.keepalive
|
|
80
|
+
if (keepalive !== undefined && !(keepalive.interval > 0 && keepalive.timeout > 0)) {
|
|
81
|
+
throw new TypeError("nodeWebSocket: keepalive.interval and keepalive.timeout must be positive")
|
|
82
|
+
}
|
|
44
83
|
let wss: WssInstance | null = null
|
|
45
|
-
let wssReady: Promise<
|
|
84
|
+
let wssReady: Promise<WssInstance> | null = null
|
|
85
|
+
const open = new Set<NodeWS>()
|
|
86
|
+
/* the Request being upgraded, for the protocol callback (ws hands it the IncomingMessage) */
|
|
87
|
+
let upgrading: Request | null = null
|
|
46
88
|
|
|
47
|
-
const ensureWss =
|
|
48
|
-
if (wss) return wss
|
|
89
|
+
const ensureWss = (): Promise<WssInstance> => {
|
|
90
|
+
if (wss) return Promise.resolve(wss)
|
|
49
91
|
if (!wssReady) {
|
|
50
|
-
wssReady = import("ws").then(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
92
|
+
wssReady = import("ws").then(
|
|
93
|
+
(mod) => {
|
|
94
|
+
const wsModule = mod as unknown as WsModule
|
|
95
|
+
wss = new wsModule.WebSocketServer({
|
|
96
|
+
handleProtocols: (protocols) => {
|
|
97
|
+
if (protocols.size === 0 || upgrading === null) return false
|
|
98
|
+
return selectProtocol(upgrading, options) ?? false
|
|
99
|
+
},
|
|
100
|
+
maxPayload: options.maxPayload,
|
|
101
|
+
noServer: true,
|
|
102
|
+
perMessageDeflate: false,
|
|
103
|
+
})
|
|
104
|
+
return wss
|
|
105
|
+
},
|
|
106
|
+
(err: unknown) => {
|
|
107
|
+
/* not cached: installing ws later works without a restart */
|
|
108
|
+
wssReady = null
|
|
109
|
+
throw new Error(WS_MISSING, { cause: err })
|
|
110
|
+
},
|
|
111
|
+
)
|
|
54
112
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
113
|
+
return wssReady
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const watch = (ws: NodeWS): void => {
|
|
117
|
+
let pingTimer: ReturnType<typeof setInterval> | undefined
|
|
118
|
+
let pongTimeout: ReturnType<typeof setTimeout> | undefined
|
|
119
|
+
let idleTimer: ReturnType<typeof setInterval> | undefined
|
|
120
|
+
let lastSeen = Date.now()
|
|
121
|
+
const seen = (): void => {
|
|
122
|
+
lastSeen = Date.now()
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
ws.on("pong", () => {
|
|
126
|
+
seen()
|
|
127
|
+
if (pongTimeout !== undefined) {
|
|
128
|
+
clearTimeout(pongTimeout)
|
|
129
|
+
pongTimeout = undefined
|
|
130
|
+
}
|
|
131
|
+
})
|
|
132
|
+
ws.on("ping", seen)
|
|
133
|
+
|
|
134
|
+
if (keepalive) {
|
|
135
|
+
pingTimer = setInterval(() => {
|
|
136
|
+
if (ws.readyState !== 1) return
|
|
137
|
+
/* one pong outstanding at a time: a slow pong must not stack timers */
|
|
138
|
+
if (pongTimeout !== undefined) return
|
|
139
|
+
ws.ping()
|
|
140
|
+
pongTimeout = setTimeout(() => ws.terminate(), keepalive.timeout)
|
|
141
|
+
}, keepalive.interval)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const idle = options.idleTimeout
|
|
145
|
+
if (idle > 0) {
|
|
146
|
+
const tick = Math.max(Math.floor(idle / 2), 1)
|
|
147
|
+
idleTimer = setInterval(() => {
|
|
148
|
+
if (ws.readyState !== 1) return
|
|
149
|
+
const quiet = Date.now() - lastSeen
|
|
150
|
+
if (quiet >= idle) ws.terminate()
|
|
151
|
+
else if (quiet >= tick) ws.ping()
|
|
152
|
+
}, tick)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const stop = (): void => {
|
|
156
|
+
if (pingTimer !== undefined) clearInterval(pingTimer)
|
|
157
|
+
if (pongTimeout !== undefined) clearTimeout(pongTimeout)
|
|
158
|
+
if (idleTimer !== undefined) clearInterval(idleTimer)
|
|
159
|
+
pingTimer = pongTimeout = idleTimer = undefined
|
|
160
|
+
}
|
|
161
|
+
ws.on("close", stop)
|
|
162
|
+
ws.on("error", stop)
|
|
58
163
|
}
|
|
59
164
|
|
|
60
165
|
return {
|
|
61
|
-
|
|
166
|
+
closeAll(code: number, reason: string) {
|
|
167
|
+
for (const ws of open) {
|
|
168
|
+
try {
|
|
169
|
+
ws.close(code, reason)
|
|
170
|
+
} catch {
|
|
171
|
+
ws.terminate()
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
options,
|
|
176
|
+
async upgrade(req: Request, env: unknown, handler: WSHandler<unknown>) {
|
|
62
177
|
const server = await ensureWss()
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
178
|
+
const upgrade = (env as Record<string, unknown>).__nodeUpgrade as NodeUpgradeData | undefined
|
|
179
|
+
if (upgrade === undefined) {
|
|
180
|
+
throw new Error("nodeWebSocket: no upgrade socket; serve the app with honey's serve() on Node")
|
|
181
|
+
}
|
|
66
182
|
|
|
67
183
|
return new Promise((resolve, reject) => {
|
|
184
|
+
/* ws answers a malformed handshake itself and never calls back: fail instead of hanging */
|
|
185
|
+
const sock = upgrade.socket as { once?(event: "close", cb: () => void): void }
|
|
186
|
+
sock.once?.("close", () => {
|
|
187
|
+
if (!upgrade.upgraded) reject(new Error("WebSocket handshake failed"))
|
|
188
|
+
})
|
|
189
|
+
upgrading = req
|
|
68
190
|
try {
|
|
69
191
|
server.handleUpgrade(upgrade.req, upgrade.socket, upgrade.head, (ws: NodeWS) => {
|
|
70
|
-
|
|
192
|
+
upgrade.upgraded = true
|
|
193
|
+
ws.binaryType = "arraybuffer"
|
|
194
|
+
open.add(ws)
|
|
195
|
+
const socket = new WSContextImpl(ws, options)
|
|
71
196
|
|
|
72
|
-
ws.on("message", (data:
|
|
197
|
+
ws.on("message", (data: ArrayBuffer | Buffer | Buffer[], isBinary: boolean) => {
|
|
198
|
+
let payload: ArrayBuffer | string
|
|
73
199
|
if (!isBinary) {
|
|
74
|
-
/* text frame
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength) as ArrayBuffer,
|
|
83
|
-
)
|
|
84
|
-
} else if (Array.isArray(data)) {
|
|
85
|
-
const merged = Buffer.concat(data)
|
|
86
|
-
handler.onMessage?.(
|
|
87
|
-
undefined,
|
|
88
|
-
socket,
|
|
89
|
-
merged.buffer.slice(merged.byteOffset, merged.byteOffset + merged.byteLength) as ArrayBuffer,
|
|
90
|
-
)
|
|
200
|
+
/* text frame: a string, as on every other runtime */
|
|
201
|
+
payload = Buffer.isBuffer(data)
|
|
202
|
+
? data.toString("utf-8")
|
|
203
|
+
: data instanceof ArrayBuffer
|
|
204
|
+
? Buffer.from(data).toString("utf-8")
|
|
205
|
+
: Buffer.concat(data).toString("utf-8")
|
|
206
|
+
} else if (data instanceof ArrayBuffer) {
|
|
207
|
+
payload = data
|
|
91
208
|
} else {
|
|
92
|
-
|
|
209
|
+
payload = toArrayBuffer(Array.isArray(data) ? Buffer.concat(data) : data)
|
|
93
210
|
}
|
|
211
|
+
fireHandler("message", () => handler.onMessage?.(undefined, socket, payload))
|
|
94
212
|
})
|
|
95
|
-
|
|
96
|
-
/* keepalive ping/pong */
|
|
97
|
-
let pingTimer: ReturnType<typeof setInterval> | undefined
|
|
98
|
-
let pongTimeout: ReturnType<typeof setTimeout> | undefined
|
|
99
|
-
|
|
100
|
-
if (opts?.keepalive) {
|
|
101
|
-
const { interval, timeout } = opts.keepalive
|
|
102
|
-
ws.on("pong", () => {
|
|
103
|
-
if (pongTimeout !== undefined) {
|
|
104
|
-
clearTimeout(pongTimeout)
|
|
105
|
-
pongTimeout = undefined
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
pingTimer = setInterval(() => {
|
|
109
|
-
if (ws.readyState !== 1) {
|
|
110
|
-
clearInterval(pingTimer)
|
|
111
|
-
return
|
|
112
|
-
}
|
|
113
|
-
ws.ping()
|
|
114
|
-
pongTimeout = setTimeout(() => {
|
|
115
|
-
ws.close(1001, "keepalive timeout")
|
|
116
|
-
}, timeout)
|
|
117
|
-
}, interval)
|
|
118
|
-
}
|
|
213
|
+
watch(ws)
|
|
119
214
|
|
|
120
215
|
ws.on("close", (code: number, reason: Buffer) => {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
handler.onClose?.(undefined, socket, code, reason.toString())
|
|
216
|
+
open.delete(ws)
|
|
217
|
+
fireHandler("close", () => handler.onClose?.(undefined, socket, code, reason.toString()))
|
|
124
218
|
})
|
|
125
219
|
|
|
126
220
|
ws.on("error", (err: unknown) => {
|
|
127
|
-
|
|
128
|
-
if (pongTimeout !== undefined) clearTimeout(pongTimeout)
|
|
129
|
-
handler.onError?.(undefined, socket, err)
|
|
221
|
+
fireHandler("error", () => handler.onError?.(undefined, socket, err))
|
|
130
222
|
})
|
|
131
223
|
|
|
132
|
-
handler.onOpen?.(undefined, socket)
|
|
224
|
+
fireHandler("open", () => handler.onOpen?.(undefined, socket))
|
|
133
225
|
|
|
134
226
|
/* Node's Response rejects status 101 (Fetch spec: 200-599 only).
|
|
135
227
|
Create a valid Response and override status for the sentinel check. */
|
|
@@ -139,6 +231,8 @@ export function nodeWebSocket(opts?: { keepalive?: KeepaliveConfig }): WSAdapter
|
|
|
139
231
|
})
|
|
140
232
|
} catch (err) {
|
|
141
233
|
reject(err)
|
|
234
|
+
} finally {
|
|
235
|
+
upgrading = null
|
|
142
236
|
}
|
|
143
237
|
})
|
|
144
238
|
},
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The server side of one websocket route connection: the user's callbacks run on one ordered
|
|
3
|
+
* queue (open, then messages, then close), each contained, with a cap on waiting messages.
|
|
4
|
+
* Every honey adapter imports this module, which registers it, so the core never bundles it
|
|
5
|
+
* for an app without websockets.
|
|
6
|
+
*/
|
|
7
|
+
import { registerFeature } from "../feature-slots.ts"
|
|
8
|
+
import { createEventQueue, invokeUser, type InvokeLogger } from "../invoke-user.ts"
|
|
9
|
+
import { originAllowed } from "../ws-origin.ts"
|
|
10
|
+
import type { WSContext, WSHandler } from "./cloudflare.ts"
|
|
11
|
+
|
|
12
|
+
/** Messages one websocket connection may have waiting for its handler; more close it with 1008. */
|
|
13
|
+
const WS_PENDING_MAX = 1024
|
|
14
|
+
|
|
15
|
+
/** `callbacks` are the route's own; each receives the route's request context `ctx` first. */
|
|
16
|
+
export function createWsSession(opts: {
|
|
17
|
+
callbacks: WSHandler<unknown>
|
|
18
|
+
ctx: unknown
|
|
19
|
+
log: InvokeLogger | null
|
|
20
|
+
reconnectToken: string | null
|
|
21
|
+
route: string
|
|
22
|
+
}): WSHandler<unknown> {
|
|
23
|
+
const { callbacks, ctx, log, reconnectToken, route } = opts
|
|
24
|
+
const { onClose, onError, onMessage, onOpen, onReconnect } = callbacks
|
|
25
|
+
const queue = createEventQueue()
|
|
26
|
+
let pending = 0
|
|
27
|
+
|
|
28
|
+
const run = (phase: string, ws: WSContext, fn: () => unknown): Promise<unknown> =>
|
|
29
|
+
invokeUser(fn, {
|
|
30
|
+
fields: { route },
|
|
31
|
+
log,
|
|
32
|
+
onError: onError ? (err) => onError(ctx, ws, err) : null,
|
|
33
|
+
phase: `websocket ${phase}`,
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
onClose: (_ctx, ws, code, reason) => {
|
|
38
|
+
if (onClose) void queue.push(() => run("close", ws, () => onClose(ctx, ws, code, reason)))
|
|
39
|
+
},
|
|
40
|
+
/* a transport error: tell onError once; if onError throws, that is logged */
|
|
41
|
+
onError: (_ctx, ws, error) => {
|
|
42
|
+
void queue.push(() =>
|
|
43
|
+
invokeUser(() => (onError ? onError(ctx, ws, error) : Promise.reject(error)), {
|
|
44
|
+
fields: { route },
|
|
45
|
+
log,
|
|
46
|
+
phase: "websocket error",
|
|
47
|
+
}),
|
|
48
|
+
)
|
|
49
|
+
},
|
|
50
|
+
onMessage: (_ctx, ws, data) => {
|
|
51
|
+
if (!onMessage) return
|
|
52
|
+
if (pending >= WS_PENDING_MAX) {
|
|
53
|
+
ws.close(1008, "too many pending messages")
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
pending++
|
|
57
|
+
void queue.push(() =>
|
|
58
|
+
run("message", ws, () => onMessage(ctx, ws, data)).finally(() => {
|
|
59
|
+
pending--
|
|
60
|
+
}),
|
|
61
|
+
)
|
|
62
|
+
},
|
|
63
|
+
onOpen: (_ctx, ws) => {
|
|
64
|
+
if (reconnectToken && onReconnect) {
|
|
65
|
+
void queue.push(() => run("open", ws, () => onReconnect(ctx, ws, reconnectToken)))
|
|
66
|
+
} else if (onOpen) {
|
|
67
|
+
void queue.push(() => run("open", ws, () => onOpen(ctx, ws)))
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
registerFeature("ws", { createWsSession, originAllowed })
|
package/src/ws/shared.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options every WebSocket adapter takes, with the same meaning and defaults on Node, Bun, Deno
|
|
3
|
+
* and Workers. Each adapter enforces what its runtime does not.
|
|
4
|
+
*/
|
|
5
|
+
export type WSAdapterOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* Largest inbound message in bytes. A bigger one closes the connection with 1009.
|
|
8
|
+
* Default 1 MiB.
|
|
9
|
+
*/
|
|
10
|
+
maxPayload?: number
|
|
11
|
+
/**
|
|
12
|
+
* Outbound bytes a socket may hold unsent before `backpressurePolicy` applies to the next
|
|
13
|
+
* `send()`. Default 8 MiB.
|
|
14
|
+
*/
|
|
15
|
+
backpressureLimit?: number
|
|
16
|
+
/**
|
|
17
|
+
* Over `backpressureLimit`: `"close"` closes the connection with 1013 (try again later),
|
|
18
|
+
* `"drop"` discards the message. Default `"close"`.
|
|
19
|
+
*/
|
|
20
|
+
backpressurePolicy?: "close" | "drop"
|
|
21
|
+
/**
|
|
22
|
+
* Close a connection that has received nothing (no message, no pong) for this many
|
|
23
|
+
* milliseconds. Idle peers are pinged first where the runtime allows it. `0` disables.
|
|
24
|
+
* Default 120 000 (Bun's default). Deno and Bun take whole seconds.
|
|
25
|
+
*/
|
|
26
|
+
idleTimeout?: number
|
|
27
|
+
/**
|
|
28
|
+
* Choose the subprotocol from the ones the client offered (`Sec-WebSocket-Protocol`).
|
|
29
|
+
* Return `null` or `undefined` for none. Default: the first one offered.
|
|
30
|
+
*/
|
|
31
|
+
protocol?: (offered: string[], req: Request) => string | null | undefined
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type ResolvedWSOptions = {
|
|
35
|
+
backpressureLimit: number
|
|
36
|
+
backpressurePolicy: "close" | "drop"
|
|
37
|
+
idleTimeout: number
|
|
38
|
+
maxPayload: number
|
|
39
|
+
protocol: (offered: string[], req: Request) => string | null | undefined
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const DEFAULT_MAX_PAYLOAD = 1024 * 1024
|
|
43
|
+
export const DEFAULT_BACKPRESSURE_LIMIT = 8 * 1024 * 1024
|
|
44
|
+
export const DEFAULT_IDLE_TIMEOUT = 120_000
|
|
45
|
+
|
|
46
|
+
/** Close codes the adapters and the realtime server use. */
|
|
47
|
+
export const CLOSE_NORMAL = 1000
|
|
48
|
+
export const CLOSE_GOING_AWAY = 1001
|
|
49
|
+
export const CLOSE_POLICY = 1008
|
|
50
|
+
export const CLOSE_TOO_BIG = 1009
|
|
51
|
+
export const CLOSE_INTERNAL = 1011
|
|
52
|
+
export const CLOSE_TRY_AGAIN = 1013
|
|
53
|
+
|
|
54
|
+
/** Longest close reason a frame can carry (125-byte control payload minus the 2-byte code). */
|
|
55
|
+
export const MAX_CLOSE_REASON = 123
|
|
56
|
+
|
|
57
|
+
const firstOffered = (offered: string[]): string | null => offered[0] ?? null
|
|
58
|
+
|
|
59
|
+
function nonNegative(name: string, value: number | undefined, fallback: number): number {
|
|
60
|
+
if (value === undefined) return fallback
|
|
61
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
62
|
+
throw new TypeError(`WebSocket adapter: ${name} must be a non-negative number`)
|
|
63
|
+
}
|
|
64
|
+
return value
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function resolveWSOptions(opts: WSAdapterOptions | undefined): ResolvedWSOptions {
|
|
68
|
+
const policy = opts?.backpressurePolicy ?? "close"
|
|
69
|
+
if (policy !== "close" && policy !== "drop") {
|
|
70
|
+
throw new TypeError('WebSocket adapter: backpressurePolicy must be "close" or "drop"')
|
|
71
|
+
}
|
|
72
|
+
const maxPayload = nonNegative("maxPayload", opts?.maxPayload, DEFAULT_MAX_PAYLOAD)
|
|
73
|
+
if (maxPayload === 0) throw new TypeError("WebSocket adapter: maxPayload must be positive")
|
|
74
|
+
return {
|
|
75
|
+
backpressureLimit: nonNegative("backpressureLimit", opts?.backpressureLimit, DEFAULT_BACKPRESSURE_LIMIT),
|
|
76
|
+
backpressurePolicy: policy,
|
|
77
|
+
idleTimeout: nonNegative("idleTimeout", opts?.idleTimeout, DEFAULT_IDLE_TIMEOUT),
|
|
78
|
+
maxPayload,
|
|
79
|
+
protocol: opts?.protocol ?? firstOffered,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** The subprotocols the client offered, in order. */
|
|
84
|
+
export function offeredProtocols(req: Request): string[] {
|
|
85
|
+
const raw = req.headers.get("sec-websocket-protocol")
|
|
86
|
+
if (raw === null) return []
|
|
87
|
+
const out: string[] = []
|
|
88
|
+
for (const part of raw.split(",")) {
|
|
89
|
+
const p = part.trim()
|
|
90
|
+
if (p !== "") out.push(p)
|
|
91
|
+
}
|
|
92
|
+
return out
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** The subprotocol to answer with, or `null`. A choice the client did not offer is ignored. */
|
|
96
|
+
export function selectProtocol(req: Request, opts: ResolvedWSOptions): string | null {
|
|
97
|
+
const offered = offeredProtocols(req)
|
|
98
|
+
if (offered.length === 0) return null
|
|
99
|
+
const chosen = opts.protocol(offered, req)
|
|
100
|
+
return typeof chosen === "string" && offered.includes(chosen) ? chosen : null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Outbound bytes the runtime holds for this socket, when it reports them. */
|
|
104
|
+
export function bufferedAmountOf(raw: unknown): number {
|
|
105
|
+
if (raw === null || typeof raw !== "object") return 0
|
|
106
|
+
const r = raw as { bufferedAmount?: unknown; getBufferedAmount?: () => unknown }
|
|
107
|
+
if (typeof r.getBufferedAmount === "function") {
|
|
108
|
+
const n = r.getBufferedAmount()
|
|
109
|
+
return typeof n === "number" ? n : 0
|
|
110
|
+
}
|
|
111
|
+
return typeof r.bufferedAmount === "number" ? r.bufferedAmount : 0
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Whether an inbound message is larger than `limit` bytes. */
|
|
115
|
+
export function exceedsPayload(data: ArrayBuffer | ArrayBufferView | Blob | string, limit: number): boolean {
|
|
116
|
+
if (typeof data === "string") {
|
|
117
|
+
if (data.length > limit) return true
|
|
118
|
+
/* a UTF-16 unit is at most 3 UTF-8 bytes, so most strings need no encode */
|
|
119
|
+
if (data.length * 3 <= limit) return false
|
|
120
|
+
return new TextEncoder().encode(data).byteLength > limit
|
|
121
|
+
}
|
|
122
|
+
if (typeof Blob !== "undefined" && data instanceof Blob) return data.size > limit
|
|
123
|
+
return (data as ArrayBuffer | ArrayBufferView).byteLength > limit
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** `data` as an `ArrayBuffer` holding exactly its bytes (a pooled Buffer's backing store is larger). */
|
|
127
|
+
export function toArrayBuffer(data: ArrayBuffer | ArrayBufferView): ArrayBuffer {
|
|
128
|
+
if (data instanceof ArrayBuffer) return data
|
|
129
|
+
const { buffer, byteLength, byteOffset } = data
|
|
130
|
+
if (byteOffset === 0 && byteLength === buffer.byteLength && buffer instanceof ArrayBuffer) return buffer
|
|
131
|
+
return buffer.slice(byteOffset, byteOffset + byteLength) as ArrayBuffer
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** A close code a server may send: 1000, 1001-1014 except the reserved ones, or 3000-4999. */
|
|
135
|
+
export function sendableCloseCode(code: number | undefined): number {
|
|
136
|
+
if (code === undefined) return 1000
|
|
137
|
+
if (code === 1000 || (code >= 3000 && code <= 4999)) return code
|
|
138
|
+
if (code >= 1001 && code <= 1014 && code !== 1004 && code !== 1005 && code !== 1006) return code
|
|
139
|
+
return 1000
|
|
140
|
+
}
|
package/src/ws-origin.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which browser origins may open a WebSocket. A browser lets any page open a socket to any host
|
|
3
|
+
* and sends that host's cookies with it, so a cookie-authenticated socket is open to cross-site
|
|
4
|
+
* hijacking unless the server checks `Origin`.
|
|
5
|
+
*
|
|
6
|
+
* - `"*"`: every origin.
|
|
7
|
+
* - a list: those exact origins (`https://app.example.com`), plus same-origin.
|
|
8
|
+
* - a function: called with the `Origin` value; same-origin always passes.
|
|
9
|
+
* - unset (the default): same-origin always passes; a cross-origin upgrade is rejected when it
|
|
10
|
+
* carries credentials (`Cookie` or `Authorization`), since that is what hijacking needs. A
|
|
11
|
+
* request without `Origin` (not a browser) passes.
|
|
12
|
+
*/
|
|
13
|
+
export type WSOriginPolicy = "*" | readonly string[] | ((origin: string) => boolean)
|
|
14
|
+
|
|
15
|
+
function originHost(origin: string): string | null {
|
|
16
|
+
if (origin === "null") return null
|
|
17
|
+
try {
|
|
18
|
+
return new URL(origin).host.toLowerCase()
|
|
19
|
+
} catch {
|
|
20
|
+
return null
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function validateOriginPolicy(policy: unknown): WSOriginPolicy {
|
|
25
|
+
if (policy === "*" || typeof policy === "function") return policy as WSOriginPolicy
|
|
26
|
+
if (Array.isArray(policy) && policy.every((o) => typeof o === "string")) {
|
|
27
|
+
for (const o of policy as string[]) {
|
|
28
|
+
if (originHost(o) === null)
|
|
29
|
+
throw new TypeError(`allowedOrigins: "${o}" is not an origin like https://example.com`)
|
|
30
|
+
}
|
|
31
|
+
return Object.freeze([...(policy as string[])])
|
|
32
|
+
}
|
|
33
|
+
throw new TypeError('allowedOrigins must be "*", a list of origins, or a function')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Whether an upgrade from `origin` may proceed. `host` is the host the client asked for
|
|
38
|
+
* (`clientInfo(ctx).host`, which follows `trustProxy`).
|
|
39
|
+
*/
|
|
40
|
+
export function originAllowed(
|
|
41
|
+
policy: WSOriginPolicy | null,
|
|
42
|
+
origin: string | null,
|
|
43
|
+
host: string | null,
|
|
44
|
+
hasCredentials: boolean,
|
|
45
|
+
): boolean {
|
|
46
|
+
if (policy === "*") return true
|
|
47
|
+
if (origin === null) return true
|
|
48
|
+
const oh = originHost(origin)
|
|
49
|
+
if (oh !== null && host !== null && oh === host.toLowerCase()) return true
|
|
50
|
+
if (policy === null) return !hasCredentials
|
|
51
|
+
if (typeof policy === "function") return policy(origin) === true
|
|
52
|
+
return policy.includes(origin)
|
|
53
|
+
}
|
package/src/yaml.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* JSON-compatible YAML 1.2 emitter: the same document as `JSON.stringify`, in a
|
|
3
|
+
* different encoding. Input is first normalized through JSON (so `undefined` keys
|
|
4
|
+
* are skipped, `Date` becomes its ISO string, `NaN` becomes `null`), then every
|
|
5
|
+
* string that is not plainly safe is written as a double-quoted scalar, which
|
|
6
|
+
* also reads the same under YAML 1.1 parsers.
|
|
7
|
+
*/
|
|
2
8
|
|
|
3
9
|
const INDENT = " "
|
|
4
10
|
|
|
@@ -7,38 +13,55 @@ export function yamlSiblingPath(jsonPath: string): string {
|
|
|
7
13
|
return jsonPath.endsWith(".json") ? `${jsonPath.slice(0, -5)}.yaml` : `${jsonPath}.yaml`
|
|
8
14
|
}
|
|
9
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Where an OpenAPI output configured at `path` is written. A `.yaml`/`.yml` path is that YAML file
|
|
18
|
+
* alone; any other path is JSON there plus its YAML sibling.
|
|
19
|
+
*/
|
|
20
|
+
export function openApiOutputPaths(path: string): { json: string | null; yaml: string } {
|
|
21
|
+
if (path.endsWith(".yaml") || path.endsWith(".yml")) return { json: null, yaml: path }
|
|
22
|
+
return { json: path, yaml: yamlSiblingPath(path) }
|
|
23
|
+
}
|
|
24
|
+
|
|
10
25
|
export function toYaml(value: unknown): string {
|
|
11
|
-
|
|
26
|
+
const json = JSON.stringify(value)
|
|
27
|
+
/* JSON.stringify(undefined) is undefined; emit the JSON equivalent of "nothing". */
|
|
28
|
+
const normalized: unknown = json === undefined ? null : JSON.parse(json)
|
|
29
|
+
return `${emit(normalized, 0)}\n`
|
|
12
30
|
}
|
|
13
31
|
|
|
14
32
|
function emit(value: unknown, indent: number): string {
|
|
15
|
-
if (value === null
|
|
33
|
+
if (value === null) return "null"
|
|
16
34
|
if (typeof value === "boolean") return value ? "true" : "false"
|
|
17
|
-
if (typeof value === "number")
|
|
18
|
-
if (!Number.isFinite(value)) return JSON.stringify(String(value))
|
|
19
|
-
return Object.is(value, -0) ? "-0" : String(value)
|
|
20
|
-
}
|
|
35
|
+
if (typeof value === "number") return String(value)
|
|
21
36
|
if (typeof value === "string") return emitString(value)
|
|
22
37
|
if (Array.isArray(value)) return emitArray(value, indent)
|
|
23
|
-
|
|
24
|
-
return JSON.stringify(String(value))
|
|
38
|
+
return emitObject(value as Record<string, unknown>, indent)
|
|
25
39
|
}
|
|
26
40
|
|
|
41
|
+
/*
|
|
42
|
+
* A plain scalar is used only for a conservative shape: starts with a letter,
|
|
43
|
+
* `_`, `/` or `$`; contains only word characters, `.`, `/`, `$`, `-`, `+`,
|
|
44
|
+
* `{}`, `()` and inner spaces. That excludes every indicator, `: `, ` #`,
|
|
45
|
+
* leading digits (numbers, YAML 1.1 octal and sexagesimal), and `.inf`/`.nan`.
|
|
46
|
+
*/
|
|
47
|
+
const PLAIN_RE = /^[A-Za-z_/$](?:[\w./${}()+-]| (?! ))*$/
|
|
48
|
+
/* Words YAML 1.1 or 1.2 resolves to null or a boolean. */
|
|
49
|
+
const RESERVED_RE = /^(?:y|n|yes|no|on|off|true|false|null|~)$/i
|
|
50
|
+
|
|
27
51
|
function emitString(value: string): string {
|
|
28
|
-
if (value
|
|
29
|
-
|
|
30
|
-
return value
|
|
52
|
+
if (PLAIN_RE.test(value) && !value.endsWith(" ") && !RESERVED_RE.test(value)) return value
|
|
53
|
+
return quote(value)
|
|
31
54
|
}
|
|
32
55
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
56
|
+
/*
|
|
57
|
+
* JSON string syntax is a valid YAML double-quoted scalar, except that YAML
|
|
58
|
+
* forbids raw DEL, C1 controls (other than NEL) and the BOM/non-characters.
|
|
59
|
+
*/
|
|
60
|
+
function quote(value: string): string {
|
|
61
|
+
return JSON.stringify(value).replace(
|
|
62
|
+
/[\u007f-\u0084\u0086-\u009f]/g,
|
|
63
|
+
(ch) => `\\u${ch.charCodeAt(0).toString(16).padStart(4, "0")}`,
|
|
64
|
+
)
|
|
42
65
|
}
|
|
43
66
|
|
|
44
67
|
function isNonEmptyCollection(value: unknown): boolean {
|
|
@@ -70,7 +93,7 @@ function emitObject(value: Record<string, unknown>, indent: number): string {
|
|
|
70
93
|
return keys
|
|
71
94
|
.map((key) => {
|
|
72
95
|
const child = value[key]
|
|
73
|
-
const renderedKey =
|
|
96
|
+
const renderedKey = emitString(key)
|
|
74
97
|
if (isNonEmptyCollection(child)) {
|
|
75
98
|
return `${pad}${renderedKey}:\n${emit(child, indent + 1)}`
|
|
76
99
|
}
|