@lovrozagar/honey 0.6.5 → 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 +410 -149
- 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 +1893 -1761
- 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 +271 -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/serve-slot.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
import { detectRuntime } from "./detect-runtime.ts"
|
|
1
2
|
import type { HoneyServeOptions, ServeHandle } from "./serve.ts"
|
|
2
3
|
|
|
3
4
|
export type ServeStart = (app: unknown, options?: HoneyServeOptions) => Promise<ServeHandle>
|
|
4
5
|
|
|
5
6
|
const MISSING = 'Honey.serve() requires `import "@lovrozagar/honey/serve"` in the app entry.'
|
|
6
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Set while codegen evaluates an app module. A global, not a module variable: the app may load a
|
|
10
|
+
* different copy of this module than the generator (jiti instance, source vs compiled build).
|
|
11
|
+
*/
|
|
12
|
+
const CODEGEN = Symbol.for("@lovrozagar/honey.codegen")
|
|
13
|
+
|
|
7
14
|
let runtime: ServeStart | undefined
|
|
8
15
|
|
|
9
16
|
export function registerServeRuntime(next: ServeStart): void {
|
|
@@ -15,6 +22,37 @@ export function resetServeRuntime(): void {
|
|
|
15
22
|
}
|
|
16
23
|
|
|
17
24
|
export function getServeRuntime(): ServeStart {
|
|
25
|
+
if (isCodegenProcess()) return codegenServe
|
|
18
26
|
if (!runtime) throw new Error(MISSING)
|
|
19
27
|
return runtime
|
|
20
28
|
}
|
|
29
|
+
|
|
30
|
+
/** Marks this process as running codegen: `app.serve()` resolves without listening. */
|
|
31
|
+
export function setCodegenProcess(active: boolean): void {
|
|
32
|
+
const slot = globalThis as unknown as Record<symbol, unknown>
|
|
33
|
+
if (active) slot[CODEGEN] = true
|
|
34
|
+
else delete slot[CODEGEN]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function isCodegenProcess(): boolean {
|
|
38
|
+
return (globalThis as unknown as Record<symbol, unknown>)[CODEGEN] === true
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* codegen loads the app to read its routes; a top-level `await app.serve()` must not bind a port */
|
|
42
|
+
const codegenServe: ServeStart = async (_app, options = {}) => {
|
|
43
|
+
let detected = options.runtime
|
|
44
|
+
try {
|
|
45
|
+
detected ??= detectRuntime()
|
|
46
|
+
} catch {
|
|
47
|
+
detected = "node"
|
|
48
|
+
}
|
|
49
|
+
const hostname = options.hostname ?? "127.0.0.1"
|
|
50
|
+
const port = options.port ?? 3000
|
|
51
|
+
return {
|
|
52
|
+
async close() {},
|
|
53
|
+
hostname,
|
|
54
|
+
port,
|
|
55
|
+
runtime: detected === "cloudflare" ? "node" : detected,
|
|
56
|
+
url: `http://${hostname}:${port}`,
|
|
57
|
+
}
|
|
58
|
+
}
|
package/src/serve.ts
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import type { Honey } from "./index.ts"
|
|
2
2
|
import { cors, type CORSOptions } from "./cors.ts"
|
|
3
3
|
import { detectRuntime, type ServeRuntime } from "./detect-runtime.ts"
|
|
4
|
+
import { DEFAULT_MAX_REQUEST_BODY } from "./request-limits.ts"
|
|
5
|
+
import { setPeerAddress } from "./peer.ts"
|
|
6
|
+
import { hasValidHost } from "./client-info.ts"
|
|
7
|
+
import type { WSAdapter } from "./ws/cloudflare.ts"
|
|
4
8
|
|
|
5
9
|
export type { ServeRuntime }
|
|
6
10
|
export { detectRuntime }
|
|
7
11
|
|
|
8
12
|
export type ServeHandle = {
|
|
9
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Stop accepting connections, close WebSockets with 1001, and let in-flight requests finish
|
|
15
|
+
* for up to `timeout` ms (default 1000); then every connection is cut. Same on Node, Bun and Deno.
|
|
16
|
+
*/
|
|
17
|
+
close(timeout?: number): Promise<void>
|
|
10
18
|
hostname: string
|
|
11
19
|
port: number
|
|
12
20
|
runtime: Exclude<ServeRuntime, "cloudflare">
|
|
@@ -19,6 +27,41 @@ export type HoneyServeOptions = {
|
|
|
19
27
|
hostname?: string
|
|
20
28
|
port?: number
|
|
21
29
|
runtime?: ServeRuntime
|
|
30
|
+
/**
|
|
31
|
+
* Largest request body, in bytes; a bigger one is answered 413. Default 128 MiB on Node and
|
|
32
|
+
* Bun. Deno has no cap of its own.
|
|
33
|
+
*/
|
|
34
|
+
maxRequestBodySize?: number
|
|
35
|
+
/** Node only: `server.headersTimeout`, ms. */
|
|
36
|
+
headersTimeout?: number
|
|
37
|
+
/** Node only: `server.requestTimeout`, ms. */
|
|
38
|
+
requestTimeout?: number
|
|
39
|
+
/** Node only: `server.keepAliveTimeout`, ms. */
|
|
40
|
+
keepAliveTimeout?: number
|
|
41
|
+
/** Node only: how long an upgrade request may take to become a WebSocket, ms (default 30 000). */
|
|
42
|
+
upgradeTimeout?: number
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const DEFAULT_CLOSE_TIMEOUT = 1_000
|
|
46
|
+
|
|
47
|
+
type AppInternals = { _graph: { settings: { wsAdapter: WSAdapter | null } } }
|
|
48
|
+
|
|
49
|
+
/** The adapter the app already has (`app.wsAdapter(...)`), if any: serve() keeps it. */
|
|
50
|
+
function ownAdapter(app: Honey<Record<string, unknown>>): WSAdapter | null {
|
|
51
|
+
return (app as unknown as AppInternals)._graph.settings.wsAdapter
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Settle with `work`, or with `"timeout"` after `ms`; the timer never outlives the race. */
|
|
55
|
+
async function within(work: Promise<unknown>, ms: number): Promise<"done" | "timeout"> {
|
|
56
|
+
let timer: ReturnType<typeof setTimeout> | undefined
|
|
57
|
+
const timeout = new Promise<"timeout">((r) => {
|
|
58
|
+
timer = setTimeout(() => r("timeout"), ms)
|
|
59
|
+
})
|
|
60
|
+
try {
|
|
61
|
+
return await Promise.race([work.then(() => "done" as const), timeout])
|
|
62
|
+
} finally {
|
|
63
|
+
clearTimeout(timer)
|
|
64
|
+
}
|
|
22
65
|
}
|
|
23
66
|
|
|
24
67
|
const CF_SERVE_ERROR =
|
|
@@ -40,31 +83,51 @@ export async function startHoneyServer(
|
|
|
40
83
|
throw new Error(CF_SERVE_ERROR)
|
|
41
84
|
}
|
|
42
85
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
86
|
+
const listening: Honey<Record<string, unknown>> = app
|
|
87
|
+
/* app-wide: every route, 404, 405 and preflight run it first — replaced, not stacked, on a re-serve */
|
|
88
|
+
const corsMw = options.cors ? cors(options.cors === true ? undefined : options.cors) : null
|
|
89
|
+
;(app as unknown as { _setGlobal(key: string, mw: unknown): void })._setGlobal("serve:cors", corsMw)
|
|
48
90
|
|
|
49
91
|
const hostname = options.hostname ?? (runtime === "deno" ? "127.0.0.1" : "0.0.0.0")
|
|
50
92
|
const port = options.port ?? 3000
|
|
51
93
|
const env = (options.env ?? {}) as Record<string, unknown>
|
|
52
94
|
|
|
53
95
|
if (runtime === "bun") {
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
96
|
+
const existing = ownAdapter(listening)
|
|
97
|
+
let bunWs: BunWSAdapter
|
|
98
|
+
if (existing === null) {
|
|
99
|
+
const { bunWebSocket } = await import("./ws/bun.ts")
|
|
100
|
+
bunWs = bunWebSocket()
|
|
101
|
+
listening.wsAdapter(bunWs)
|
|
102
|
+
} else if ("websocket" in existing) {
|
|
103
|
+
bunWs = existing as BunWSAdapter
|
|
104
|
+
} else {
|
|
105
|
+
throw new Error("serve() on Bun needs a bunWebSocket() adapter, but app.wsAdapter() was given another one")
|
|
106
|
+
}
|
|
57
107
|
const BunNs = (globalThis as unknown as { Bun: { serve: (opts: Record<string, unknown>) => BunServer } }).Bun
|
|
108
|
+
/* `server` is the same object for every request: build the env once */
|
|
109
|
+
let envWithServer: Record<string, unknown> | null = null
|
|
58
110
|
const server = BunNs.serve({
|
|
59
|
-
fetch: (req: Request,
|
|
111
|
+
fetch: (req: Request, srv: unknown) => {
|
|
112
|
+
if (envWithServer === null) envWithServer = { ...env, server: srv }
|
|
113
|
+
return listening.fetch(req, envWithServer)
|
|
114
|
+
},
|
|
60
115
|
hostname,
|
|
116
|
+
maxRequestBodySize: options.maxRequestBodySize ?? DEFAULT_MAX_REQUEST_BODY,
|
|
61
117
|
port,
|
|
62
118
|
websocket: bunWs.websocket,
|
|
63
119
|
})
|
|
64
120
|
const bound = server.port
|
|
65
121
|
return {
|
|
66
|
-
async close() {
|
|
67
|
-
|
|
122
|
+
async close(timeout = DEFAULT_CLOSE_TIMEOUT) {
|
|
123
|
+
bunWs.closeAll?.(1001, "server shutting down")
|
|
124
|
+
/* graceful first: in-flight requests finish; then cut what is left. Bun before 1.4 keeps
|
|
125
|
+
* idle keep-alive connections serving after stop(false), so close those explicitly,
|
|
126
|
+
* now and again once in-flight requests have finished and left theirs idle. */
|
|
127
|
+
const graceful = Promise.resolve(server.stop(false))
|
|
128
|
+
server.closeIdleConnections?.()
|
|
129
|
+
if ((await within(graceful, timeout)) === "timeout") await Promise.resolve(server.stop(true))
|
|
130
|
+
server.closeIdleConnections?.()
|
|
68
131
|
},
|
|
69
132
|
hostname,
|
|
70
133
|
port: bound,
|
|
@@ -74,29 +137,40 @@ export async function startHoneyServer(
|
|
|
74
137
|
}
|
|
75
138
|
|
|
76
139
|
if (runtime === "deno") {
|
|
77
|
-
|
|
78
|
-
|
|
140
|
+
if (ownAdapter(listening) === null) {
|
|
141
|
+
const { denoWebSocket } = await import("./ws/deno.ts")
|
|
142
|
+
listening.wsAdapter(denoWebSocket())
|
|
143
|
+
}
|
|
79
144
|
const DenoNs = (
|
|
80
145
|
globalThis as unknown as {
|
|
81
146
|
Deno: {
|
|
82
147
|
serve: (
|
|
83
148
|
opts: { hostname: string; port: number; signal?: AbortSignal },
|
|
84
|
-
handler: (req: Request) => Response | Promise<Response>,
|
|
149
|
+
handler: (req: Request, info: { remoteAddr?: { hostname?: string } }) => Response | Promise<Response>,
|
|
85
150
|
) => { addr?: { port?: number }; finished?: Promise<void>; shutdown?: () => Promise<void> }
|
|
86
151
|
}
|
|
87
152
|
}
|
|
88
153
|
).Deno
|
|
89
154
|
const ac = new AbortController()
|
|
90
|
-
const server = DenoNs.serve({ hostname, port, signal: ac.signal }, (req) =>
|
|
155
|
+
const server = DenoNs.serve({ hostname, port, signal: ac.signal }, (req, info) => {
|
|
156
|
+
/* Deno builds req.url from Host and the target: a `Host: x/admin?` would pick the path */
|
|
157
|
+
if (!hasValidHost(req)) return (listening as unknown as { _badRequestTarget(): Response })._badRequestTarget()
|
|
158
|
+
const peer = info?.remoteAddr?.hostname
|
|
159
|
+
if (typeof peer === "string") setPeerAddress(req, peer)
|
|
160
|
+
return listening.fetch(req, env)
|
|
161
|
+
})
|
|
91
162
|
const bound = server.addr?.port ?? port
|
|
92
163
|
return {
|
|
93
|
-
async close() {
|
|
94
|
-
|
|
164
|
+
async close(timeout = DEFAULT_CLOSE_TIMEOUT) {
|
|
165
|
+
ownAdapter(listening)?.closeAll?.(1001, "server shutting down")
|
|
95
166
|
if (server.shutdown) {
|
|
96
|
-
|
|
167
|
+
/* graceful: in-flight requests finish. Deno has no forced close, so a request still
|
|
168
|
+
* running after `timeout` ends on its own (aborting the signal now would throw) */
|
|
169
|
+
await within(server.shutdown(), timeout)
|
|
97
170
|
return
|
|
98
171
|
}
|
|
99
|
-
|
|
172
|
+
ac.abort()
|
|
173
|
+
await within(server.finished ?? Promise.resolve(), timeout)
|
|
100
174
|
},
|
|
101
175
|
hostname,
|
|
102
176
|
port: bound,
|
|
@@ -105,10 +179,21 @@ export async function startHoneyServer(
|
|
|
105
179
|
}
|
|
106
180
|
}
|
|
107
181
|
|
|
108
|
-
const { nodeWebSocket } = await import("./ws/node.ts")
|
|
109
182
|
const { serve } = await import("./node.ts")
|
|
110
|
-
|
|
111
|
-
|
|
183
|
+
if (ownAdapter(listening) === null) {
|
|
184
|
+
const { nodeWebSocket } = await import("./ws/node.ts")
|
|
185
|
+
listening.wsAdapter(nodeWebSocket())
|
|
186
|
+
}
|
|
187
|
+
const server = serve(listening as never, {
|
|
188
|
+
env,
|
|
189
|
+
headersTimeout: options.headersTimeout,
|
|
190
|
+
hostname,
|
|
191
|
+
keepAliveTimeout: options.keepAliveTimeout,
|
|
192
|
+
maxRequestBodySize: options.maxRequestBodySize,
|
|
193
|
+
port,
|
|
194
|
+
requestTimeout: options.requestTimeout,
|
|
195
|
+
upgradeTimeout: options.upgradeTimeout,
|
|
196
|
+
})
|
|
112
197
|
await new Promise<void>((resolve, reject) => {
|
|
113
198
|
server.once("listening", () => resolve())
|
|
114
199
|
server.once("error", reject)
|
|
@@ -116,8 +201,8 @@ export async function startHoneyServer(
|
|
|
116
201
|
const addr = server.address()
|
|
117
202
|
const bound = typeof addr === "object" && addr !== null ? addr.port : port
|
|
118
203
|
return {
|
|
119
|
-
async close() {
|
|
120
|
-
await server.shutdown(
|
|
204
|
+
async close(timeout = DEFAULT_CLOSE_TIMEOUT) {
|
|
205
|
+
await server.shutdown(timeout)
|
|
121
206
|
},
|
|
122
207
|
hostname,
|
|
123
208
|
port: bound,
|
|
@@ -126,7 +211,10 @@ export async function startHoneyServer(
|
|
|
126
211
|
}
|
|
127
212
|
}
|
|
128
213
|
|
|
214
|
+
type BunWSAdapter = WSAdapter & { websocket: Record<string, unknown> }
|
|
215
|
+
|
|
129
216
|
type BunServer = {
|
|
217
|
+
closeIdleConnections?(): void
|
|
130
218
|
port: number
|
|
131
219
|
stop(closeActiveConnections?: boolean): void | Promise<void>
|
|
132
220
|
}
|
package/src/server-timing.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { namedMiddleware } from "./middleware.ts"
|
|
2
2
|
import type { MiddlewareFn } from "./middleware.ts"
|
|
3
|
+
import { withHeaders } from "./with-headers.ts"
|
|
3
4
|
|
|
4
5
|
export type Timing = {
|
|
5
6
|
end(name: string): void
|
|
@@ -12,14 +13,17 @@ type TimingEntry = {
|
|
|
12
13
|
start: number
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
const
|
|
16
|
+
/* metric names are RFC 9110 tokens; anything else becomes `_` */
|
|
17
|
+
const nonTokenRe = /[^!#$%&'*+.^`|~\w-]/g
|
|
17
18
|
function sanitizeName(name: string): string {
|
|
18
|
-
|
|
19
|
+
const token = name.replace(nonTokenRe, "_")
|
|
20
|
+
return token.length > 0 ? token : "_"
|
|
19
21
|
}
|
|
20
22
|
|
|
23
|
+
/* descriptions are quoted-strings: latin1 only, no controls, `\` and `"` escaped */
|
|
24
|
+
const nonQuotableRe = /[^\t\x20-\x7e\x80-\xff]/g
|
|
21
25
|
function escapeDescription(desc: string): string {
|
|
22
|
-
return desc.replace(
|
|
26
|
+
return desc.replace(nonQuotableRe, "?").replace(/[\\"]/g, "\\$&")
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
export function serverTiming(): MiddlewareFn<{}, { timing: Timing }> {
|
|
@@ -58,9 +62,9 @@ export function serverTiming(): MiddlewareFn<{}, { timing: Timing }> {
|
|
|
58
62
|
const totalDur = (performance.now() - requestStart).toFixed(2)
|
|
59
63
|
parts.push(`total;dur=${totalDur}`)
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return response
|
|
65
|
+
/* append: an upstream or handler Server-Timing is kept */
|
|
66
|
+
const value = parts.join(", ")
|
|
67
|
+
return withHeaders(response, (headers) => headers.append("server-timing", value))
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
return namedMiddleware("serverTiming", mw)
|
package/src/static.ts
CHANGED
|
@@ -1,58 +1,111 @@
|
|
|
1
1
|
import { namedMiddleware } from "./middleware.ts"
|
|
2
2
|
import type { MiddlewareFn } from "./middleware.ts"
|
|
3
|
+
import { normalizePath, pathOfUrl } from "./request-path.ts"
|
|
4
|
+
import { withHeaders } from "./with-headers.ts"
|
|
3
5
|
|
|
4
6
|
type StaticConfig<TCtx> = {
|
|
7
|
+
/**
|
|
8
|
+
* Returns the file for `filePath`, or `null` to fall through to the next handler.
|
|
9
|
+
* `filePath` starts with `/`, is decoded once, and has no `.`, `..`, empty, NUL, `:` or
|
|
10
|
+
* separator-bearing segments — joining it onto a root directory cannot leave that root,
|
|
11
|
+
* on POSIX or Windows.
|
|
12
|
+
*/
|
|
5
13
|
resolve: (ctx: TCtx, filePath: string) => Response | null | Promise<Response | null>
|
|
14
|
+
/** Mount point, matched on whole segments: `/assets` serves `/assets/x`, never `/assets-private/x`. */
|
|
6
15
|
prefix?: string
|
|
16
|
+
/** Extra response headers; a function receives the same `filePath` that `resolve` got. */
|
|
7
17
|
headers?: Record<string, string> | ((filePath: string) => Record<string, string>)
|
|
18
|
+
/** Rewrites the decoded file path before `resolve`. The result is checked again. */
|
|
8
19
|
rewritePath?: (filePath: string, ctx: TCtx) => string
|
|
9
20
|
}
|
|
10
21
|
|
|
11
|
-
|
|
22
|
+
function normalizePrefix(prefix: string): string {
|
|
23
|
+
const normalized = normalizePath(prefix.startsWith("/") ? prefix : `/${prefix}`)
|
|
24
|
+
if (normalized === null) throw new Error(`staticFiles: invalid prefix ${JSON.stringify(prefix)}`)
|
|
25
|
+
return normalized.length > 1 && normalized.endsWith("/") ? normalized.slice(0, -1) : normalized
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* `/`-joined decoded segments, or `null` when any segment is malformed percent-encoding or
|
|
30
|
+
* decodes to something a file system treats specially (`.`, `..`, empty, a separator, NUL, `:`).
|
|
31
|
+
*/
|
|
32
|
+
function safeFilePath(encoded: string): string | null {
|
|
33
|
+
const parts = encoded.split("/")
|
|
34
|
+
const out: string[] = []
|
|
35
|
+
for (let i = 0; i < parts.length; i++) {
|
|
36
|
+
const part = parts[i]
|
|
37
|
+
if (part === "") {
|
|
38
|
+
/* the leading slash, and a trailing one (a directory request) */
|
|
39
|
+
if (i === 0 || i === parts.length - 1) continue
|
|
40
|
+
return null
|
|
41
|
+
}
|
|
42
|
+
let seg: string
|
|
43
|
+
try {
|
|
44
|
+
seg = decodeURIComponent(part)
|
|
45
|
+
} catch {
|
|
46
|
+
return null
|
|
47
|
+
}
|
|
48
|
+
if (!isSafeSegment(seg)) return null
|
|
49
|
+
out.push(seg)
|
|
50
|
+
}
|
|
51
|
+
const joined = `/${out.join("/")}`
|
|
52
|
+
return out.length > 0 && encoded.endsWith("/") ? `${joined}/` : joined
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function isSafeSegment(seg: string): boolean {
|
|
56
|
+
if (seg === "" || seg === "." || seg === "..") return false
|
|
57
|
+
/* `:` makes a Windows drive (`C:`) or alternate data stream (`a.txt::$DATA`) */
|
|
58
|
+
return !seg.includes("/") && !seg.includes("\\") && !seg.includes("\0") && !seg.includes(":")
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Re-checks a `rewritePath` result: it must be the same safe shape `resolve` would get without one. */
|
|
62
|
+
function safeRewrite(path: string): string | null {
|
|
63
|
+
if (!path.startsWith("/")) return null
|
|
64
|
+
const parts = path.split("/")
|
|
65
|
+
for (let i = 1; i < parts.length; i++) {
|
|
66
|
+
if (parts[i] === "" && i === parts.length - 1) continue
|
|
67
|
+
if (!isSafeSegment(parts[i])) return null
|
|
68
|
+
}
|
|
69
|
+
return path
|
|
70
|
+
}
|
|
12
71
|
|
|
13
72
|
export function staticFiles<TCtx extends { req: Request }>(config: StaticConfig<TCtx>): MiddlewareFn<TCtx, {}> {
|
|
14
|
-
const prefix = config.prefix ?? "/"
|
|
73
|
+
const prefix = normalizePrefix(config.prefix ?? "/")
|
|
15
74
|
|
|
16
75
|
const mw: MiddlewareFn<TCtx, {}> = async (ctx, next) => {
|
|
17
76
|
const method = ctx.req.method
|
|
18
77
|
if (method !== "GET" && method !== "HEAD") return next()
|
|
19
78
|
|
|
20
|
-
/*
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
let
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
} else if (
|
|
29
|
-
|
|
79
|
+
/* the normalized path the router matched — never the raw request target */
|
|
80
|
+
const fromCtx = (ctx as { path?: unknown }).path
|
|
81
|
+
const path = typeof fromCtx === "string" && fromCtx !== "" ? fromCtx : normalizePath(pathOfUrl(ctx.req.url))
|
|
82
|
+
if (path === null) return next()
|
|
83
|
+
|
|
84
|
+
let rest: string
|
|
85
|
+
if (prefix === "/") {
|
|
86
|
+
rest = path
|
|
87
|
+
} else if (path === prefix) {
|
|
88
|
+
rest = "/"
|
|
89
|
+
} else if (path.startsWith(prefix) && path.charCodeAt(prefix.length) === 47) {
|
|
90
|
+
rest = path.substring(prefix.length)
|
|
30
91
|
} else {
|
|
31
|
-
|
|
92
|
+
return next()
|
|
32
93
|
}
|
|
33
94
|
|
|
34
|
-
|
|
95
|
+
const decoded = safeFilePath(rest)
|
|
96
|
+
if (decoded === null) return next()
|
|
97
|
+
const filePath = config.rewritePath ? safeRewrite(config.rewritePath(decoded, ctx)) : decoded
|
|
98
|
+
if (filePath === null) return next()
|
|
35
99
|
|
|
36
|
-
const
|
|
37
|
-
const filePath = stripped === "" ? "/" : stripped
|
|
38
|
-
|
|
39
|
-
/* path traversal guard — reject encoded and literal .. segments */
|
|
40
|
-
const decoded = decodeURIComponent(filePath)
|
|
41
|
-
if (TRAVERSAL.test(decoded)) return next()
|
|
42
|
-
|
|
43
|
-
const resolved = config.rewritePath ? config.rewritePath(filePath, ctx) : filePath
|
|
44
|
-
const response = await config.resolve(ctx, resolved)
|
|
100
|
+
const response = await config.resolve(ctx, filePath)
|
|
45
101
|
if (response === null) return next()
|
|
46
102
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return response
|
|
103
|
+
if (!config.headers) return response
|
|
104
|
+
/* a resolver's Response can have immutable headers (`fetch()`, a Workers ASSETS binding) */
|
|
105
|
+
const extra = typeof config.headers === "function" ? config.headers(filePath) : config.headers
|
|
106
|
+
return withHeaders(response, (headers) => {
|
|
107
|
+
for (const key of Object.keys(extra)) headers.set(key, extra[key])
|
|
108
|
+
})
|
|
56
109
|
}
|
|
57
110
|
|
|
58
111
|
return namedMiddleware("staticFiles", mw)
|
package/src/telemetry/otel.ts
CHANGED
|
@@ -12,13 +12,32 @@ type Tracer = {
|
|
|
12
12
|
|
|
13
13
|
type TelemetryAdapter = {
|
|
14
14
|
onError?(ctx: { duration: number; error: HoneyError; method: string; path: string }): void
|
|
15
|
-
onHandler?(ctx: { duration: number; method: string; path: string; status: number }): void
|
|
15
|
+
onHandler?(ctx: { duration: number; method: string; path: string; route?: string; status: number }): void
|
|
16
16
|
onMethodNotAllowed?(ctx: { allowed: string[]; method: string; path: string; req: Request }): void
|
|
17
17
|
onMiddleware?(ctx: { duration: number; error?: unknown; name: string }): void
|
|
18
18
|
onNotFound?(ctx: { method: string; path: string; req: Request }): void
|
|
19
19
|
onRequest?(ctx: { env: unknown; req: Request }): void
|
|
20
20
|
onResponse?(ctx: { duration: number; req: Request; status: number }): void
|
|
21
|
-
onRoute?(ctx: { method: string; params: Record<string, string>; path: string; req: Request }): void
|
|
21
|
+
onRoute?(ctx: { method: string; params: Record<string, string>; path: string; req: Request; route?: string }): void
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The request URL without its query string or fragment: queries carry tokens and session ids,
|
|
26
|
+
* and attribute values are exported to whatever backend the tracer feeds.
|
|
27
|
+
*/
|
|
28
|
+
function urlWithoutQuery(url: string): string {
|
|
29
|
+
const q = url.indexOf("?")
|
|
30
|
+
const h = url.indexOf("#")
|
|
31
|
+
const end = q === -1 ? h : h === -1 ? q : Math.min(q, h)
|
|
32
|
+
return end === -1 ? url : url.slice(0, end)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Path part of an absolute URL, without the query. */
|
|
36
|
+
function pathOf(url: string): string {
|
|
37
|
+
const bare = urlWithoutQuery(url)
|
|
38
|
+
const scheme = bare.indexOf("//")
|
|
39
|
+
const start = scheme === -1 ? 0 : bare.indexOf("/", scheme + 2)
|
|
40
|
+
return start === -1 ? "/" : bare.slice(start)
|
|
22
41
|
}
|
|
23
42
|
|
|
24
43
|
export function otelAdapter(options: { tracer: Tracer }): TelemetryAdapter {
|
|
@@ -45,7 +64,8 @@ export function otelAdapter(options: { tracer: Tracer }): TelemetryAdapter {
|
|
|
45
64
|
try {
|
|
46
65
|
const span = options.tracer.startSpan("http.handler")
|
|
47
66
|
span.setAttribute("http.method", ctx.method)
|
|
48
|
-
|
|
67
|
+
/* the pattern, never the request path: one series per route, not per id */
|
|
68
|
+
if (ctx.route !== undefined && ctx.route !== "") span.setAttribute("http.route", ctx.route)
|
|
49
69
|
span.setAttribute("http.status_code", ctx.status)
|
|
50
70
|
span.setAttribute("http.duration_ms", ctx.duration)
|
|
51
71
|
span.end()
|
|
@@ -61,7 +81,7 @@ export function otelAdapter(options: { tracer: Tracer }): TelemetryAdapter {
|
|
|
61
81
|
span.addEvent("method_not_allowed", {
|
|
62
82
|
"http.allowed_methods": ctx.allowed.join(", "),
|
|
63
83
|
"http.method": ctx.method,
|
|
64
|
-
"
|
|
84
|
+
"url.path": ctx.path,
|
|
65
85
|
})
|
|
66
86
|
}
|
|
67
87
|
} catch {
|
|
@@ -87,7 +107,7 @@ export function otelAdapter(options: { tracer: Tracer }): TelemetryAdapter {
|
|
|
87
107
|
if (span) {
|
|
88
108
|
span.addEvent("not_found", {
|
|
89
109
|
"http.method": ctx.method,
|
|
90
|
-
"
|
|
110
|
+
"url.path": ctx.path,
|
|
91
111
|
})
|
|
92
112
|
}
|
|
93
113
|
} catch {
|
|
@@ -98,7 +118,9 @@ export function otelAdapter(options: { tracer: Tracer }): TelemetryAdapter {
|
|
|
98
118
|
onRequest(ctx) {
|
|
99
119
|
try {
|
|
100
120
|
const span = options.tracer.startSpan("http.request")
|
|
101
|
-
span.setAttribute("http.
|
|
121
|
+
span.setAttribute("http.method", ctx.req.method)
|
|
122
|
+
span.setAttribute("http.url", urlWithoutQuery(ctx.req.url))
|
|
123
|
+
span.setAttribute("url.path", pathOf(ctx.req.url))
|
|
102
124
|
spans.set(ctx.req, span)
|
|
103
125
|
} catch {
|
|
104
126
|
/* swallow */
|
|
@@ -124,7 +146,7 @@ export function otelAdapter(options: { tracer: Tracer }): TelemetryAdapter {
|
|
|
124
146
|
const span = spans.get(ctx.req)
|
|
125
147
|
if (span) {
|
|
126
148
|
span.setAttribute("http.method", ctx.method)
|
|
127
|
-
span.setAttribute("http.route", ctx.
|
|
149
|
+
if (ctx.route !== undefined && ctx.route !== "") span.setAttribute("http.route", ctx.route)
|
|
128
150
|
}
|
|
129
151
|
} catch {
|
|
130
152
|
/* swallow */
|