@lovrozagar/honey 0.6.8 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +776 -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 +562 -424
- 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/client-go/sse.go
CHANGED
|
@@ -5,6 +5,7 @@ package sdk
|
|
|
5
5
|
import (
|
|
6
6
|
"bufio"
|
|
7
7
|
"context"
|
|
8
|
+
"errors"
|
|
8
9
|
"io"
|
|
9
10
|
"iter"
|
|
10
11
|
"net/http"
|
|
@@ -12,7 +13,8 @@ import (
|
|
|
12
13
|
"strings"
|
|
13
14
|
)
|
|
14
15
|
|
|
15
|
-
// SSEEvent represents a single server-sent event.
|
|
16
|
+
// SSEEvent represents a single server-sent event. ID is the last event ID seen
|
|
17
|
+
// on the stream so far (the spec's sticky "last event ID buffer").
|
|
16
18
|
type SSEEvent struct {
|
|
17
19
|
Data string
|
|
18
20
|
Event string
|
|
@@ -20,130 +22,138 @@ type SSEEvent struct {
|
|
|
20
22
|
Retry int
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
// sseMaxLine caps one line, and sseMaxEvent the data of one event.
|
|
26
|
+
const (
|
|
27
|
+
sseMaxLine = 1024 * 1024
|
|
28
|
+
sseMaxEvent = 8 * 1024 * 1024
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
// ErrSSELineTooLong is returned when a single SSE line exceeds the cap.
|
|
32
|
+
var ErrSSELineTooLong = errors.New("honey: sse line exceeds 1 MiB")
|
|
24
33
|
|
|
25
34
|
// parseSSEStream returns an iter.Seq2 that yields SSEEvent values read from resp.Body.
|
|
26
35
|
// On non-2xx response it yields a typed error immediately then terminates.
|
|
27
36
|
// The response body is closed when the iterator returns.
|
|
28
|
-
//
|
|
29
|
-
// Ported from public/honey/core/src/client/sse.ts:62-102 — bufio.Scanner with
|
|
30
|
-
// double-newline split mirrors the TextDecoder+split(/\r\n\r\n|…/) approach.
|
|
31
37
|
func parseSSEStream(ctx context.Context, resp *http.Response) iter.Seq2[SSEEvent, error] {
|
|
32
38
|
return func(yield func(SSEEvent, error) bool) {
|
|
33
39
|
defer resp.Body.Close()
|
|
34
40
|
|
|
35
41
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
36
|
-
body, _ :=
|
|
37
|
-
|
|
38
|
-
yield(SSEEvent{}, apiErr)
|
|
42
|
+
body, _ := readBody(resp.Body, 64<<10)
|
|
43
|
+
yield(SSEEvent{}, raiseForStatus(resp, body))
|
|
39
44
|
return
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
scanner.Buffer(make([]byte, 0, 4096), sseMaxBuffer)
|
|
44
|
-
scanner.Split(splitDoubleNewline)
|
|
45
|
-
|
|
46
|
-
for scanner.Scan() {
|
|
47
|
+
for ev, err := range parseSSE(resp.Body) {
|
|
47
48
|
if ctx.Err() != nil {
|
|
48
49
|
return
|
|
49
50
|
}
|
|
50
|
-
|
|
51
|
-
if strings.TrimSpace(block) == "" {
|
|
52
|
-
continue
|
|
53
|
-
}
|
|
54
|
-
ev, ok := parseSSEBlock(block)
|
|
55
|
-
if !ok {
|
|
56
|
-
continue
|
|
57
|
-
}
|
|
58
|
-
if !yield(ev, nil) {
|
|
51
|
+
if !yield(ev, err) || err != nil {
|
|
59
52
|
return
|
|
60
53
|
}
|
|
61
54
|
}
|
|
62
|
-
|
|
63
|
-
if err := scanner.Err(); err != nil {
|
|
64
|
-
yield(SSEEvent{}, err)
|
|
65
|
-
}
|
|
66
55
|
}
|
|
67
56
|
}
|
|
68
57
|
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
58
|
+
// parseSSE implements the WHATWG event-stream parser: lines end in CRLF, LF or
|
|
59
|
+
// CR; a blank line dispatches; a final event without its blank line is
|
|
60
|
+
// discarded; the id is sticky across events; retry needs only ASCII digits.
|
|
61
|
+
func parseSSE(r io.Reader) iter.Seq2[SSEEvent, error] {
|
|
62
|
+
return func(yield func(SSEEvent, error) bool) {
|
|
63
|
+
br := bufio.NewReaderSize(r, 64*1024)
|
|
64
|
+
var (
|
|
65
|
+
data strings.Builder
|
|
66
|
+
hasData bool
|
|
67
|
+
event string
|
|
68
|
+
lastID string
|
|
69
|
+
retry int
|
|
70
|
+
firstLine = true
|
|
71
|
+
)
|
|
72
|
+
for {
|
|
73
|
+
line, err := readSSELine(br)
|
|
74
|
+
if err != nil {
|
|
75
|
+
if !errors.Is(err, io.EOF) {
|
|
76
|
+
yield(SSEEvent{}, err)
|
|
77
|
+
}
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
if firstLine {
|
|
81
|
+
line = strings.TrimPrefix(line, string(rune(0xFEFF)))
|
|
82
|
+
firstLine = false
|
|
83
|
+
}
|
|
84
|
+
if line == "" {
|
|
85
|
+
if hasData {
|
|
86
|
+
ev := SSEEvent{Data: data.String(), Event: event, ID: lastID, Retry: retry}
|
|
87
|
+
if !yield(ev, nil) {
|
|
88
|
+
return
|
|
89
|
+
}
|
|
80
90
|
}
|
|
91
|
+
data.Reset()
|
|
92
|
+
hasData = false
|
|
93
|
+
event = ""
|
|
94
|
+
retry = 0
|
|
95
|
+
continue
|
|
96
|
+
}
|
|
97
|
+
if strings.HasPrefix(line, ":") {
|
|
98
|
+
continue
|
|
81
99
|
}
|
|
82
|
-
|
|
83
|
-
|
|
100
|
+
field, value := line, ""
|
|
101
|
+
if i := strings.IndexByte(line, ':'); i >= 0 {
|
|
102
|
+
field, value = line[:i], strings.TrimPrefix(line[i+1:], " ")
|
|
103
|
+
}
|
|
104
|
+
switch field {
|
|
105
|
+
case "data":
|
|
106
|
+
if hasData {
|
|
107
|
+
data.WriteByte('\n')
|
|
108
|
+
}
|
|
109
|
+
if data.Len()+len(value) > sseMaxEvent {
|
|
110
|
+
yield(SSEEvent{}, errors.New("honey: sse event exceeds 8 MiB"))
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
data.WriteString(value)
|
|
114
|
+
hasData = true
|
|
115
|
+
case "event":
|
|
116
|
+
event = value
|
|
117
|
+
case "id":
|
|
118
|
+
if !strings.ContainsRune(value, 0) {
|
|
119
|
+
lastID = value
|
|
120
|
+
}
|
|
121
|
+
case "retry":
|
|
122
|
+
if value != "" && strings.Trim(value, "0123456789") == "" {
|
|
123
|
+
if n, convErr := strconv.Atoi(value); convErr == nil {
|
|
124
|
+
retry = n
|
|
125
|
+
}
|
|
126
|
+
}
|
|
84
127
|
}
|
|
85
128
|
}
|
|
86
129
|
}
|
|
87
|
-
if atEOF && len(data) > 0 {
|
|
88
|
-
return len(data), data, nil
|
|
89
|
-
}
|
|
90
|
-
return 0, nil, nil
|
|
91
130
|
}
|
|
92
131
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
line := strings.TrimRight(rawLine, "\r")
|
|
104
|
-
if strings.HasPrefix(line, ":") {
|
|
105
|
-
continue
|
|
106
|
-
}
|
|
107
|
-
isComment = false
|
|
108
|
-
|
|
109
|
-
colonIdx := strings.IndexByte(line, ':')
|
|
110
|
-
var field, val string
|
|
111
|
-
if colonIdx == -1 {
|
|
112
|
-
field = line
|
|
113
|
-
val = ""
|
|
114
|
-
} else {
|
|
115
|
-
field = line[:colonIdx]
|
|
116
|
-
val = line[colonIdx+1:]
|
|
117
|
-
if strings.HasPrefix(val, " ") {
|
|
118
|
-
val = val[1:]
|
|
132
|
+
// readSSELine reads one line without its terminator. A CR may be followed by
|
|
133
|
+
// an LF that belongs to the same terminator. io.EOF is returned only when no
|
|
134
|
+
// complete line remains, so a truncated final line is never parsed.
|
|
135
|
+
func readSSELine(br *bufio.Reader) (string, error) {
|
|
136
|
+
var b strings.Builder
|
|
137
|
+
for {
|
|
138
|
+
c, err := br.ReadByte()
|
|
139
|
+
if err != nil {
|
|
140
|
+
if errors.Is(err, io.EOF) {
|
|
141
|
+
return "", io.EOF
|
|
119
142
|
}
|
|
143
|
+
return "", err
|
|
120
144
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
data = data + "\n" + val
|
|
128
|
-
}
|
|
129
|
-
hasData = true
|
|
130
|
-
case "event":
|
|
131
|
-
event = val
|
|
132
|
-
case "id":
|
|
133
|
-
/* per spec: id containing null byte must be ignored */
|
|
134
|
-
if !strings.ContainsRune(val, 0) {
|
|
135
|
-
id = val
|
|
136
|
-
}
|
|
137
|
-
case "retry":
|
|
138
|
-
if n, err := strconv.Atoi(val); err == nil && n >= 0 {
|
|
139
|
-
retry = n
|
|
145
|
+
switch c {
|
|
146
|
+
case '\n':
|
|
147
|
+
return b.String(), nil
|
|
148
|
+
case '\r':
|
|
149
|
+
if next, peekErr := br.Peek(1); peekErr == nil && next[0] == '\n' {
|
|
150
|
+
_, _ = br.ReadByte()
|
|
140
151
|
}
|
|
152
|
+
return b.String(), nil
|
|
141
153
|
}
|
|
154
|
+
if b.Len() >= sseMaxLine {
|
|
155
|
+
return "", ErrSSELineTooLong
|
|
156
|
+
}
|
|
157
|
+
b.WriteByte(c)
|
|
142
158
|
}
|
|
143
|
-
|
|
144
|
-
if isComment || !hasData {
|
|
145
|
-
return SSEEvent{}, false
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return SSEEvent{Data: data, Event: event, ID: id, Retry: retry}, true
|
|
149
159
|
}
|
|
@@ -12,6 +12,7 @@ import (
|
|
|
12
12
|
"net/url"
|
|
13
13
|
"strings"
|
|
14
14
|
"sync"
|
|
15
|
+
"time"
|
|
15
16
|
|
|
16
17
|
"nhooyr.io/websocket"
|
|
17
18
|
)
|
|
@@ -28,6 +29,9 @@ const (
|
|
|
28
29
|
|
|
29
30
|
// TransportOpts is handed to each Transport.Connect call. Mirrors the TS
|
|
30
31
|
// TransportOpts plus per-language extras (HTTPClient for SSE/longpoll dial).
|
|
32
|
+
//
|
|
33
|
+
// MaxMessageBytes caps one inbound WebSocket message (zero means 16 MiB).
|
|
34
|
+
// PollTimeout bounds one long-poll request (zero means 60s).
|
|
31
35
|
type TransportOpts struct {
|
|
32
36
|
ReconnectToken string
|
|
33
37
|
LastEventID string
|
|
@@ -36,6 +40,20 @@ type TransportOpts struct {
|
|
|
36
40
|
ReconnectDelayMs int
|
|
37
41
|
Protocols []string
|
|
38
42
|
HTTPClient *http.Client
|
|
43
|
+
MaxMessageBytes int64
|
|
44
|
+
PollTimeout time.Duration
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const (
|
|
48
|
+
defaultMaxMessageBytes = 16 << 20
|
|
49
|
+
defaultPollTimeout = 60 * time.Second
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
func (o *TransportOpts) maxMessageBytes() int64 {
|
|
53
|
+
if o == nil || o.MaxMessageBytes <= 0 {
|
|
54
|
+
return defaultMaxMessageBytes
|
|
55
|
+
}
|
|
56
|
+
return o.MaxMessageBytes
|
|
39
57
|
}
|
|
40
58
|
|
|
41
59
|
// TransportConn is the live per-transport connection object. Each built-in
|
|
@@ -106,6 +124,7 @@ func (t *WsTransport) Connect(ctx context.Context, rawURL string, opts *Transpor
|
|
|
106
124
|
if len(opts.Headers) > 0 {
|
|
107
125
|
dialOpts.HTTPHeader = opts.Headers.Clone()
|
|
108
126
|
}
|
|
127
|
+
dialOpts.HTTPClient = opts.HTTPClient
|
|
109
128
|
}
|
|
110
129
|
if dialOpts.Subprotocols == nil && len(t.Subprotocols) > 0 {
|
|
111
130
|
dialOpts.Subprotocols = t.Subprotocols
|
|
@@ -114,6 +133,7 @@ func (t *WsTransport) Connect(ctx context.Context, rawURL string, opts *Transpor
|
|
|
114
133
|
if err != nil {
|
|
115
134
|
return nil, err
|
|
116
135
|
}
|
|
136
|
+
conn.SetReadLimit(opts.maxMessageBytes())
|
|
117
137
|
return &wsConn{conn: conn}, nil
|
|
118
138
|
}
|
|
119
139
|
|
|
@@ -155,6 +175,7 @@ func (c *wsConn) Close() error {
|
|
|
155
175
|
return c.conn.Close(websocket.StatusNormalClosure, "client close")
|
|
156
176
|
}
|
|
157
177
|
|
|
178
|
+
// toWsURL swaps the scheme only; a URL inside the query string is untouched.
|
|
158
179
|
func toWsURL(u string) string {
|
|
159
180
|
if strings.HasPrefix(u, "https://") {
|
|
160
181
|
return "wss://" + u[len("https://"):]
|
|
@@ -199,8 +220,13 @@ func (t *SseTransport) Connect(ctx context.Context, rawURL string, opts *Transpo
|
|
|
199
220
|
}
|
|
200
221
|
u = u + sep + "reconnect_token=" + url.QueryEscape(opts.ReconnectToken)
|
|
201
222
|
}
|
|
202
|
-
|
|
223
|
+
/* ctx bounds the open only; the stream lives until Close cancels streamCtx */
|
|
224
|
+
streamCtx, cancel := context.WithCancel(context.Background())
|
|
225
|
+
stop := context.AfterFunc(ctx, cancel)
|
|
226
|
+
req, err := http.NewRequestWithContext(streamCtx, "GET", u, nil)
|
|
203
227
|
if err != nil {
|
|
228
|
+
stop()
|
|
229
|
+
cancel()
|
|
204
230
|
return nil, err
|
|
205
231
|
}
|
|
206
232
|
req.Header.Set("Accept", "text/event-stream")
|
|
@@ -218,19 +244,34 @@ func (t *SseTransport) Connect(ctx context.Context, rawURL string, opts *Transpo
|
|
|
218
244
|
req.Header.Set("X-Request-Id", newUUIDv4())
|
|
219
245
|
}
|
|
220
246
|
resp, err := client.Do(req)
|
|
247
|
+
opened := stop()
|
|
221
248
|
if err != nil {
|
|
249
|
+
cancel()
|
|
222
250
|
return nil, err
|
|
223
251
|
}
|
|
252
|
+
if !opened {
|
|
253
|
+
/* ctx ended while the headers arrived */
|
|
254
|
+
_ = resp.Body.Close()
|
|
255
|
+
cancel()
|
|
256
|
+
return nil, ctx.Err()
|
|
257
|
+
}
|
|
224
258
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
225
259
|
_ = resp.Body.Close()
|
|
260
|
+
cancel()
|
|
226
261
|
return nil, fmt.Errorf("honey: sse transport: status %d", resp.StatusCode)
|
|
227
262
|
}
|
|
263
|
+
if ct := resp.Header.Get("Content-Type"); !strings.HasPrefix(strings.ToLower(ct), "text/event-stream") {
|
|
264
|
+
_ = resp.Body.Close()
|
|
265
|
+
cancel()
|
|
266
|
+
return nil, fmt.Errorf("honey: sse transport: unexpected content type %q", ct)
|
|
267
|
+
}
|
|
228
268
|
sc := &sseConn{
|
|
229
|
-
resp:
|
|
230
|
-
next:
|
|
231
|
-
done:
|
|
269
|
+
resp: resp,
|
|
270
|
+
next: make(chan sseResult, 1),
|
|
271
|
+
done: make(chan struct{}),
|
|
272
|
+
cancel: cancel,
|
|
232
273
|
}
|
|
233
|
-
go sc.run(
|
|
274
|
+
go sc.run(streamCtx)
|
|
234
275
|
return sc, nil
|
|
235
276
|
}
|
|
236
277
|
|
|
@@ -243,8 +284,10 @@ type sseConn struct {
|
|
|
243
284
|
resp *http.Response
|
|
244
285
|
next chan sseResult
|
|
245
286
|
done chan struct{}
|
|
287
|
+
cancel context.CancelFunc
|
|
246
288
|
mu sync.Mutex
|
|
247
289
|
closed bool
|
|
290
|
+
once sync.Once
|
|
248
291
|
}
|
|
249
292
|
|
|
250
293
|
func (c *sseConn) Kind() TransportKind { return TransportSse }
|
|
@@ -303,21 +346,11 @@ func (c *sseConn) Send(ctx context.Context, data any) error {
|
|
|
303
346
|
}
|
|
304
347
|
|
|
305
348
|
func (c *sseConn) Close() error {
|
|
306
|
-
c.
|
|
307
|
-
alreadyClosed := c.closed
|
|
308
|
-
c.mu.Unlock()
|
|
309
|
-
/* signal producer, then close body — parseSSEStream closes body on its own
|
|
310
|
-
* iterator exit, but bodyClose here is idempotent for the already-closed
|
|
311
|
-
* case via Body.Close()'s stdlib contract. */
|
|
312
|
-
select {
|
|
313
|
-
case <-c.done:
|
|
314
|
-
default:
|
|
349
|
+
c.once.Do(func() {
|
|
315
350
|
close(c.done)
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
}
|
|
320
|
-
return nil
|
|
351
|
+
c.cancel()
|
|
352
|
+
})
|
|
353
|
+
return c.resp.Body.Close()
|
|
321
354
|
}
|
|
322
355
|
|
|
323
356
|
/* ──────────────────────────── Longpoll adapter ─────────────────────────── */
|
|
@@ -346,9 +379,13 @@ func (t *LongpollTransport) Connect(ctx context.Context, rawURL string, opts *Tr
|
|
|
346
379
|
client = http.DefaultClient
|
|
347
380
|
}
|
|
348
381
|
lp := &longpollConn{
|
|
349
|
-
client:
|
|
350
|
-
url:
|
|
351
|
-
headers:
|
|
382
|
+
client: client,
|
|
383
|
+
url: rawURL,
|
|
384
|
+
headers: http.Header{},
|
|
385
|
+
pollTimeout: defaultPollTimeout,
|
|
386
|
+
}
|
|
387
|
+
if opts != nil && opts.PollTimeout > 0 {
|
|
388
|
+
lp.pollTimeout = opts.PollTimeout
|
|
352
389
|
}
|
|
353
390
|
if opts != nil {
|
|
354
391
|
lp.reconnectToken = opts.ReconnectToken
|
|
@@ -361,6 +398,7 @@ func (t *LongpollTransport) Connect(ctx context.Context, rawURL string, opts *Tr
|
|
|
361
398
|
}
|
|
362
399
|
|
|
363
400
|
type longpollConn struct {
|
|
401
|
+
pollTimeout time.Duration
|
|
364
402
|
client *http.Client
|
|
365
403
|
url string
|
|
366
404
|
headers http.Header
|
|
@@ -398,7 +436,9 @@ func (c *longpollConn) Recv(ctx context.Context) (any, error) {
|
|
|
398
436
|
}
|
|
399
437
|
u = u + sep + q.Encode()
|
|
400
438
|
}
|
|
401
|
-
|
|
439
|
+
pollCtx, cancel := context.WithTimeout(ctx, c.pollTimeout)
|
|
440
|
+
defer cancel()
|
|
441
|
+
req, err := http.NewRequestWithContext(pollCtx, "GET", u, nil)
|
|
402
442
|
if err != nil {
|
|
403
443
|
return nil, err
|
|
404
444
|
}
|
|
@@ -412,13 +452,13 @@ func (c *longpollConn) Recv(ctx context.Context) (any, error) {
|
|
|
412
452
|
return nil, err
|
|
413
453
|
}
|
|
414
454
|
defer resp.Body.Close()
|
|
415
|
-
body, err := io.ReadAll(resp.Body)
|
|
416
|
-
if err != nil {
|
|
417
|
-
return nil, err
|
|
418
|
-
}
|
|
419
455
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
420
456
|
return nil, fmt.Errorf("honey: longpoll transport: status %d", resp.StatusCode)
|
|
421
457
|
}
|
|
458
|
+
body, err := readBody(resp.Body, defaultMaxMessageBytes)
|
|
459
|
+
if err != nil {
|
|
460
|
+
return nil, err
|
|
461
|
+
}
|
|
422
462
|
var v any
|
|
423
463
|
if jsonErr := json.Unmarshal(body, &v); jsonErr != nil {
|
|
424
464
|
v = string(body)
|
package/src/client-go/ws.go
CHANGED
|
@@ -5,6 +5,7 @@ package sdk
|
|
|
5
5
|
import (
|
|
6
6
|
"context"
|
|
7
7
|
"encoding/json"
|
|
8
|
+
"errors"
|
|
8
9
|
"sync"
|
|
9
10
|
|
|
10
11
|
"nhooyr.io/websocket"
|
|
@@ -19,31 +20,35 @@ const WSStatusGoingAway = websocket.StatusGoingAway
|
|
|
19
20
|
// WSStatusProtocolError is the protocol error close code (1002).
|
|
20
21
|
const WSStatusProtocolError = websocket.StatusProtocolError
|
|
21
22
|
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
//
|
|
27
|
-
//
|
|
23
|
+
// defaultWSReadLimit replaces nhooyr's 32 KiB default, which closes the
|
|
24
|
+
// connection on any larger frame.
|
|
25
|
+
const defaultWSReadLimit = 16 << 20
|
|
26
|
+
|
|
27
|
+
// TypedWebSocket wraps a nhooyr.io/websocket connection with an event fanout
|
|
28
|
+
// system that mirrors the TS client's .on() escape hatch.
|
|
28
29
|
type TypedWebSocket struct {
|
|
29
|
-
conn
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
handlers map[string][]func(data []byte)
|
|
34
|
-
dialOptions websocket.DialOptions
|
|
30
|
+
conn *websocket.Conn
|
|
31
|
+
mu sync.Mutex
|
|
32
|
+
handlers map[string][]func(data []byte)
|
|
33
|
+
closed bool
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
// newTypedWebSocket constructs a TypedWebSocket from an already-dialled conn.
|
|
38
37
|
func newTypedWebSocket(conn *websocket.Conn) *TypedWebSocket {
|
|
38
|
+
conn.SetReadLimit(defaultWSReadLimit)
|
|
39
39
|
return &TypedWebSocket{
|
|
40
40
|
conn: conn,
|
|
41
41
|
handlers: make(map[string][]func(data []byte)),
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
//
|
|
46
|
-
|
|
45
|
+
// SetReadLimit sets the largest inbound message, in bytes (default 16 MiB).
|
|
46
|
+
func (w *TypedWebSocket) SetReadLimit(n int64) {
|
|
47
|
+
w.conn.SetReadLimit(n)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Send serialises data to JSON when it is a struct or map, and passes []byte
|
|
51
|
+
// (binary frame) and string (text frame) through as-is.
|
|
47
52
|
func (w *TypedWebSocket) Send(ctx context.Context, data interface{}) error {
|
|
48
53
|
switch v := data.(type) {
|
|
49
54
|
case []byte:
|
|
@@ -60,28 +65,35 @@ func (w *TypedWebSocket) Send(ctx context.Context, data interface{}) error {
|
|
|
60
65
|
}
|
|
61
66
|
|
|
62
67
|
// Close sends a WebSocket close frame with the given status code and reason.
|
|
68
|
+
// A reason over 123 bytes is truncated to fit the frame.
|
|
63
69
|
func (w *TypedWebSocket) Close(code websocket.StatusCode, reason string) error {
|
|
64
|
-
|
|
70
|
+
if len(reason) > 123 {
|
|
71
|
+
reason = reason[:123]
|
|
72
|
+
}
|
|
73
|
+
err := w.conn.Close(code, reason)
|
|
74
|
+
w.fireClose(int(code), reason)
|
|
75
|
+
return err
|
|
65
76
|
}
|
|
66
77
|
|
|
67
|
-
// Read reads the next message from the connection.
|
|
68
|
-
//
|
|
78
|
+
// Read reads the next message from the connection. On a close frame it fires
|
|
79
|
+
// "close" handlers (data is the close reason); on any other failure it fires
|
|
80
|
+
// "error" handlers (data is the error text).
|
|
69
81
|
func (w *TypedWebSocket) Read(ctx context.Context) ([]byte, error) {
|
|
70
|
-
w.once.Do(func() {
|
|
71
|
-
if len(w.sendBuffer) > 0 {
|
|
72
|
-
_ = w.conn.Write(ctx, websocket.MessageText, w.sendBuffer)
|
|
73
|
-
w.sendBuffer = nil
|
|
74
|
-
}
|
|
75
|
-
})
|
|
76
82
|
_, msg, err := w.conn.Read(ctx)
|
|
77
83
|
if err != nil {
|
|
84
|
+
var ce websocket.CloseError
|
|
85
|
+
if errors.As(err, &ce) {
|
|
86
|
+
w.fireClose(int(ce.Code), ce.Reason)
|
|
87
|
+
} else {
|
|
88
|
+
w.fanout("error", []byte(err.Error()))
|
|
89
|
+
}
|
|
78
90
|
return nil, err
|
|
79
91
|
}
|
|
80
92
|
w.fanout("message", msg)
|
|
81
93
|
return msg, nil
|
|
82
94
|
}
|
|
83
95
|
|
|
84
|
-
// On registers an event handler. Supported events: "message", "close", "error"
|
|
96
|
+
// On registers an event handler. Supported events: "message", "close", "error".
|
|
85
97
|
// The handler receives the raw message bytes; callers unmarshal as needed.
|
|
86
98
|
// This is an escape hatch — prefer ranging over Read for typed message dispatch.
|
|
87
99
|
func (w *TypedWebSocket) On(event string, handler func(data []byte)) {
|
|
@@ -90,9 +102,21 @@ func (w *TypedWebSocket) On(event string, handler func(data []byte)) {
|
|
|
90
102
|
w.handlers[event] = append(w.handlers[event], handler)
|
|
91
103
|
}
|
|
92
104
|
|
|
105
|
+
func (w *TypedWebSocket) fireClose(code int, reason string) {
|
|
106
|
+
w.mu.Lock()
|
|
107
|
+
if w.closed {
|
|
108
|
+
w.mu.Unlock()
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
w.closed = true
|
|
112
|
+
w.mu.Unlock()
|
|
113
|
+
_ = code
|
|
114
|
+
w.fanout("close", []byte(reason))
|
|
115
|
+
}
|
|
116
|
+
|
|
93
117
|
func (w *TypedWebSocket) fanout(event string, data []byte) {
|
|
94
118
|
w.mu.Lock()
|
|
95
|
-
handlers := w.handlers[event]
|
|
119
|
+
handlers := append([]func([]byte){}, w.handlers[event]...)
|
|
96
120
|
w.mu.Unlock()
|
|
97
121
|
for _, h := range handlers {
|
|
98
122
|
h(data)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { canonicalIp } from "./ip.ts"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Who sent a request, and over what, as the core sees it without `app.trustProxy()`: the peer
|
|
5
|
+
* the runtime reports is the client, and forwarding headers are client-controlled text. Trusting
|
|
6
|
+
* reverse proxies (hop counts, CIDR lists) lives in `trust.ts`, which `trustProxy()` loads.
|
|
7
|
+
*/
|
|
8
|
+
export type ClientInfo = {
|
|
9
|
+
/** Canonical client address, or `null` when it is unknown or a trusted header holds garbage. */
|
|
10
|
+
ip: string | null
|
|
11
|
+
/** Host the client asked for (`host[:port]`), or `null`. */
|
|
12
|
+
host: string | null
|
|
13
|
+
protocol: "http" | "https"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The app's compiled `trustProxy()` setting. Anything but `off` carries its own resolver, so
|
|
18
|
+
* the core never imports the hop and range logic.
|
|
19
|
+
*/
|
|
20
|
+
export type TrustSetting =
|
|
21
|
+
| { readonly kind: "off" }
|
|
22
|
+
| {
|
|
23
|
+
readonly kind: "hops" | "ranges"
|
|
24
|
+
readonly resolve: (req: Request, peer: string | null) => ClientInfo
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const TRUST_OFF: TrustSetting = Object.freeze({ kind: "off" })
|
|
28
|
+
|
|
29
|
+
const HOST = /^(?:\[[0-9A-Fa-f:.]+\]|[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?\.?)(?::\d{1,5})?$/
|
|
30
|
+
|
|
31
|
+
/** `host[:port]` as RFC 9110 allows it in `Host`; nothing that could change a URL's meaning. */
|
|
32
|
+
export function isValidHost(host: string): boolean {
|
|
33
|
+
if (!HOST.test(host)) return false
|
|
34
|
+
const colon = host.lastIndexOf(":")
|
|
35
|
+
if (colon !== -1 && host.lastIndexOf("]") < colon) {
|
|
36
|
+
const port = Number(host.slice(colon + 1))
|
|
37
|
+
if (port > 65535) return false
|
|
38
|
+
}
|
|
39
|
+
return true
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Bun before 1.4 builds `request.url` by concatenating `Host` and the request target, so a
|
|
44
|
+
* `Host: x/admin?` picks the routed path. Later versions hand over the target alone.
|
|
45
|
+
*/
|
|
46
|
+
export const BUN_URL_FROM_HOST: boolean = (() => {
|
|
47
|
+
const version = (globalThis as { Bun?: { version?: string } }).Bun?.version
|
|
48
|
+
if (version === undefined) return false
|
|
49
|
+
const [major = 0, minor = 0] = version.split(".").map(Number)
|
|
50
|
+
return major < 1 || (major === 1 && minor < 4)
|
|
51
|
+
})()
|
|
52
|
+
|
|
53
|
+
/** `false` when the request carries a `Host` header that is not `host[:port]`. */
|
|
54
|
+
export function hasValidHost(req: Request): boolean {
|
|
55
|
+
const host = req.headers.get("host")
|
|
56
|
+
return host === null || isValidHost(host)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function hostOfUrl(url: string): string | null {
|
|
60
|
+
const start = url.indexOf("//")
|
|
61
|
+
if (start === -1) return null
|
|
62
|
+
let end = url.indexOf("/", start + 2)
|
|
63
|
+
if (end === -1) end = url.length
|
|
64
|
+
const host = url.slice(start + 2, end)
|
|
65
|
+
return host === "" ? null : host
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** The client as the connection shows it: the peer, the URL's host, the transport's scheme. */
|
|
69
|
+
export function directClientInfo(req: Request, peer: string | null): ClientInfo {
|
|
70
|
+
return {
|
|
71
|
+
host: hostOfUrl(req.url),
|
|
72
|
+
ip: peer === null ? null : canonicalIp(peer),
|
|
73
|
+
protocol: req.url.startsWith("https:") ? "https" : "http",
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function resolveClient(trust: TrustSetting, req: Request, peer: string | null): ClientInfo {
|
|
78
|
+
return trust.kind === "off" ? directClientInfo(req, peer) : trust.resolve(req, peer)
|
|
79
|
+
}
|