@lovrozagar/honey 0.6.8 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +514 -192
- package/bin/honey.js +25 -0
- package/dist/accepts.d.ts +7 -1
- package/dist/accepts.d.ts.map +1 -1
- package/dist/accepts.js +126 -0
- package/dist/accepts.js.map +1 -0
- package/dist/body-kind.d.ts +26 -0
- package/dist/body-kind.d.ts.map +1 -0
- package/dist/body-kind.js +70 -0
- package/dist/body-kind.js.map +1 -0
- package/dist/body-limit.d.ts +5 -1
- package/dist/body-limit.d.ts.map +1 -1
- package/dist/body-limit.js +126 -0
- package/dist/body-limit.js.map +1 -0
- package/dist/build/index.d.ts +19 -3
- package/dist/build/index.d.ts.map +1 -1
- package/dist/build/index.js +173 -0
- package/dist/build/index.js.map +1 -0
- package/dist/cli-args.d.ts +33 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +102 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli-go/auth.go +26 -0
- package/dist/cli-go/config.go +192 -0
- package/dist/cli-go/errors.go +75 -0
- package/dist/cli-go/multipart.go +79 -0
- package/dist/cli-go/output.go +163 -0
- package/dist/cli-go/root.go +30 -0
- package/dist/cli-go/stream.go +88 -0
- package/dist/cli-go/version.go +5 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +209 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/defaults.js +48 -0
- package/dist/client/defaults.js.map +1 -0
- package/dist/client/error.d.ts +35 -0
- package/dist/client/error.d.ts.map +1 -1
- package/dist/client/error.js +71 -0
- package/dist/client/error.js.map +1 -0
- package/dist/client/http.d.ts +67 -8
- package/dist/client/http.d.ts.map +1 -1
- package/dist/client/http.js +571 -0
- package/dist/client/http.js.map +1 -0
- package/dist/client/index.d.ts +3 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +95 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/path.d.ts +26 -0
- package/dist/client/path.d.ts.map +1 -0
- package/dist/client/path.js +163 -0
- package/dist/client/path.js.map +1 -0
- package/dist/client/redirect-policy.d.ts +12 -0
- package/dist/client/redirect-policy.d.ts.map +1 -0
- package/dist/client/redirect-policy.js +20 -0
- package/dist/client/redirect-policy.js.map +1 -0
- package/dist/client/sdk.d.ts +36 -0
- package/dist/client/sdk.d.ts.map +1 -1
- package/dist/client/sdk.js +292 -0
- package/dist/client/sdk.js.map +1 -0
- package/dist/client/sse.d.ts +13 -0
- package/dist/client/sse.d.ts.map +1 -1
- package/dist/client/sse.js +129 -0
- package/dist/client/sse.js.map +1 -0
- package/dist/client/types.js +2 -0
- package/dist/client/types.js.map +1 -0
- package/dist/client/ws.d.ts +9 -2
- package/dist/client/ws.d.ts.map +1 -1
- package/dist/client/ws.js +112 -0
- package/dist/client/ws.js.map +1 -0
- package/dist/client-go/errors.go +236 -0
- package/dist/client-go/export.go +44 -0
- package/dist/client-go/invalidation.go +371 -0
- package/dist/client-go/nullable.go +62 -0
- package/dist/client-go/realtime.go +354 -0
- package/dist/client-go/result.go +20 -0
- package/dist/client-go/runtime.go +975 -0
- package/dist/client-go/sse.go +159 -0
- package/dist/client-go/transport.go +495 -0
- package/dist/client-go/ws.go +128 -0
- package/dist/client-info.d.ts +36 -0
- package/dist/client-info.d.ts.map +1 -0
- package/dist/client-info.js +53 -0
- package/dist/client-info.js.map +1 -0
- package/dist/client-mcp/README.md +10 -0
- package/dist/client-mcp/server.ts +221 -0
- package/dist/client-mcp/types.ts +19 -0
- package/dist/client-python/_errors.py +115 -0
- package/dist/client-python/_invalidation.py +494 -0
- package/dist/client-python/_realtime.py +179 -0
- package/dist/client-python/_runtime.py +860 -0
- package/dist/client-python/_sse.py +155 -0
- package/dist/client-python/_transport.py +366 -0
- package/dist/client-python/_ws.py +159 -0
- package/dist/client-python/py.typed +0 -0
- package/dist/client-rust/errors.rs +220 -0
- package/dist/client-rust/invalidation.rs +412 -0
- package/dist/client-rust/invalidation_sync.rs +93 -0
- package/dist/client-rust/nullable.rs +17 -0
- package/dist/client-rust/realtime.rs +702 -0
- package/dist/client-rust/result.rs +22 -0
- package/dist/client-rust/runtime.rs +980 -0
- package/dist/client-rust/runtime_sync.rs +484 -0
- package/dist/client-rust/sse.rs +188 -0
- package/dist/client-rust/ws.rs +167 -0
- package/dist/codegen-go-cli.d.ts.map +1 -1
- package/dist/codegen-go-cli.js +964 -0
- package/dist/codegen-go-cli.js.map +1 -0
- package/dist/codegen-go.d.ts +15 -3
- package/dist/codegen-go.d.ts.map +1 -1
- package/dist/codegen-go.js +872 -0
- package/dist/codegen-go.js.map +1 -0
- package/dist/codegen-hash.js +9 -0
- package/dist/codegen-hash.js.map +1 -0
- package/dist/codegen-ir.d.ts +69 -2
- package/dist/codegen-ir.d.ts.map +1 -1
- package/dist/codegen-ir.js +661 -0
- package/dist/codegen-ir.js.map +1 -0
- package/dist/codegen-lang.d.ts +65 -0
- package/dist/codegen-lang.d.ts.map +1 -0
- package/dist/codegen-lang.js +526 -0
- package/dist/codegen-lang.js.map +1 -0
- package/dist/codegen-load.d.ts +31 -0
- package/dist/codegen-load.d.ts.map +1 -0
- package/dist/codegen-load.js +138 -0
- package/dist/codegen-load.js.map +1 -0
- package/dist/codegen-loaders.js +55 -0
- package/dist/codegen-loaders.js.map +1 -0
- package/dist/codegen-mcp.d.ts.map +1 -1
- package/dist/codegen-mcp.js +368 -0
- package/dist/codegen-mcp.js.map +1 -0
- package/dist/codegen-python.d.ts +13 -1
- package/dist/codegen-python.d.ts.map +1 -1
- package/dist/codegen-python.js +828 -0
- package/dist/codegen-python.js.map +1 -0
- package/dist/codegen-route-tree-intern.d.ts +15 -5
- package/dist/codegen-route-tree-intern.d.ts.map +1 -1
- package/dist/codegen-route-tree-intern.js +221 -0
- package/dist/codegen-route-tree-intern.js.map +1 -0
- package/dist/codegen-rust.d.ts.map +1 -1
- package/dist/codegen-rust.js +1293 -0
- package/dist/codegen-rust.js.map +1 -0
- package/dist/codegen-sanitize.d.ts.map +1 -1
- package/dist/codegen-sanitize.js +56 -0
- package/dist/codegen-sanitize.js.map +1 -0
- package/dist/codegen-schema-naming.d.ts +5 -0
- package/dist/codegen-schema-naming.d.ts.map +1 -1
- package/dist/codegen-schema-naming.js +150 -0
- package/dist/codegen-schema-naming.js.map +1 -0
- package/dist/codegen-sdk-model.d.ts +71 -0
- package/dist/codegen-sdk-model.d.ts.map +1 -0
- package/dist/codegen-sdk-model.js +179 -0
- package/dist/codegen-sdk-model.js.map +1 -0
- package/dist/codegen.d.ts +41 -23
- package/dist/codegen.d.ts.map +1 -1
- package/dist/codegen.js +4610 -0
- package/dist/codegen.js.map +1 -0
- package/dist/context.d.ts +36 -6
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +242 -0
- package/dist/context.js.map +1 -0
- package/dist/cookie-sign.d.ts +16 -2
- package/dist/cookie-sign.d.ts.map +1 -1
- package/dist/cookie-sign.js +104 -0
- package/dist/cookie-sign.js.map +1 -0
- package/dist/cookie.d.ts +12 -0
- package/dist/cookie.d.ts.map +1 -1
- package/dist/cookie.js +138 -0
- package/dist/cookie.js.map +1 -0
- package/dist/cors.d.ts +1 -0
- package/dist/cors.d.ts.map +1 -1
- package/dist/cors.js +87 -0
- package/dist/cors.js.map +1 -0
- package/dist/crypto.d.ts +6 -1
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +38 -0
- package/dist/crypto.js.map +1 -0
- package/dist/csrf.d.ts +19 -0
- package/dist/csrf.d.ts.map +1 -1
- package/dist/csrf.js +79 -0
- package/dist/csrf.js.map +1 -0
- package/dist/curl-logger.d.ts +14 -3
- package/dist/curl-logger.d.ts.map +1 -1
- package/dist/curl-logger.js +199 -0
- package/dist/curl-logger.js.map +1 -0
- package/dist/detect-runtime.js +13 -0
- package/dist/detect-runtime.js.map +1 -0
- package/dist/dict.d.ts +11 -0
- package/dist/dict.d.ts.map +1 -0
- package/dist/dict.js +13 -0
- package/dist/dict.js.map +1 -0
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +44 -0
- package/dist/error.js.map +1 -0
- package/dist/errors.js +39 -0
- package/dist/errors.js.map +1 -0
- package/dist/etag.d.ts +2 -0
- package/dist/etag.d.ts.map +1 -1
- package/dist/etag.js +82 -0
- package/dist/etag.js.map +1 -0
- package/dist/feature-detect.d.ts +25 -0
- package/dist/feature-detect.d.ts.map +1 -0
- package/dist/feature-detect.js +144 -0
- package/dist/feature-detect.js.map +1 -0
- package/dist/feature-load.js +36 -0
- package/dist/feature-load.js.map +1 -0
- package/dist/feature-slots.d.ts +44 -0
- package/dist/feature-slots.d.ts.map +1 -0
- package/dist/feature-slots.js +48 -0
- package/dist/feature-slots.js.map +1 -0
- package/dist/fetch-request.d.ts +10 -0
- package/dist/fetch-request.d.ts.map +1 -0
- package/dist/fetch-request.js +13 -0
- package/dist/fetch-request.js.map +1 -0
- package/dist/gen-process.d.ts +15 -0
- package/dist/gen-process.d.ts.map +1 -0
- package/dist/gen-process.js +43 -0
- package/dist/gen-process.js.map +1 -0
- package/dist/gen-write.d.ts +19 -0
- package/dist/gen-write.d.ts.map +1 -0
- package/dist/gen-write.js +120 -0
- package/dist/gen-write.js.map +1 -0
- package/dist/glob.d.ts +21 -0
- package/dist/glob.d.ts.map +1 -0
- package/dist/glob.js +115 -0
- package/dist/glob.js.map +1 -0
- package/dist/go-type-emitter.d.ts +18 -4
- package/dist/go-type-emitter.d.ts.map +1 -1
- package/dist/go-type-emitter.js +594 -0
- package/dist/go-type-emitter.js.map +1 -0
- package/dist/honey-response.d.ts.map +1 -1
- package/dist/honey-response.js +338 -0
- package/dist/honey-response.js.map +1 -0
- package/dist/i18n-slot.d.ts +8 -0
- package/dist/i18n-slot.d.ts.map +1 -1
- package/dist/i18n-slot.js +14 -0
- package/dist/i18n-slot.js.map +1 -0
- package/dist/i18n.d.ts +3 -0
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +250 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +408 -148
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2324 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +3 -5
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +140 -0
- package/dist/init.js.map +1 -0
- package/dist/input.js +4 -0
- package/dist/input.js.map +1 -0
- package/dist/invalidate-check.d.ts +11 -0
- package/dist/invalidate-check.d.ts.map +1 -1
- package/dist/invalidate-check.js +163 -0
- package/dist/invalidate-check.js.map +1 -0
- package/dist/invoke-user.d.ts +35 -0
- package/dist/invoke-user.d.ts.map +1 -0
- package/dist/invoke-user.js +73 -0
- package/dist/invoke-user.js.map +1 -0
- package/dist/ip-restrict.d.ts +13 -1
- package/dist/ip-restrict.d.ts.map +1 -1
- package/dist/ip-restrict.js +60 -0
- package/dist/ip-restrict.js.map +1 -0
- package/dist/ip.d.ts +39 -0
- package/dist/ip.d.ts.map +1 -0
- package/dist/ip.js +209 -0
- package/dist/ip.js.map +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +113 -0
- package/dist/logger.js.map +1 -0
- package/dist/media-type.d.ts +30 -0
- package/dist/media-type.d.ts.map +1 -0
- package/dist/media-type.js +97 -0
- package/dist/media-type.js.map +1 -0
- package/dist/meta-spec-merge.d.ts +32 -0
- package/dist/meta-spec-merge.d.ts.map +1 -0
- package/dist/meta-spec-merge.js +68 -0
- package/dist/meta-spec-merge.js.map +1 -0
- package/dist/meta-spec.d.ts +16 -3
- package/dist/meta-spec.d.ts.map +1 -1
- package/dist/meta-spec.js +535 -0
- package/dist/meta-spec.js.map +1 -0
- package/dist/middleware.d.ts +23 -6
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +253 -0
- package/dist/middleware.js.map +1 -0
- package/dist/node-request.d.ts +57 -12
- package/dist/node-request.d.ts.map +1 -1
- package/dist/node-request.js +407 -0
- package/dist/node-request.js.map +1 -0
- package/dist/node.d.ts +20 -3
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +396 -0
- package/dist/node.js.map +1 -0
- package/dist/openapi/collect.d.ts +6 -3
- package/dist/openapi/collect.d.ts.map +1 -1
- package/dist/openapi/collect.js +30 -0
- package/dist/openapi/collect.js.map +1 -0
- package/dist/openapi/docs-page.d.ts +42 -0
- package/dist/openapi/docs-page.d.ts.map +1 -0
- package/dist/openapi/docs-page.js +80 -0
- package/dist/openapi/docs-page.js.map +1 -0
- package/dist/openapi/document.d.ts +4 -0
- package/dist/openapi/document.d.ts.map +1 -1
- package/dist/openapi/document.js +785 -0
- package/dist/openapi/document.js.map +1 -0
- package/dist/openapi/json-schema-slot.d.ts +7 -0
- package/dist/openapi/json-schema-slot.d.ts.map +1 -1
- package/dist/openapi/json-schema-slot.js +38 -0
- package/dist/openapi/json-schema-slot.js.map +1 -0
- package/dist/openapi/register.d.ts.map +1 -1
- package/dist/openapi/register.js +20 -0
- package/dist/openapi/register.js.map +1 -0
- package/dist/openapi/scalar.d.ts +3 -1
- package/dist/openapi/scalar.d.ts.map +1 -1
- package/dist/openapi/scalar.js +21 -0
- package/dist/openapi/scalar.js.map +1 -0
- package/dist/openapi/serve.d.ts +9 -0
- package/dist/openapi/serve.d.ts.map +1 -0
- package/dist/openapi/serve.js +36 -0
- package/dist/openapi/serve.js.map +1 -0
- package/dist/openapi/spec-factory.d.ts +30 -1
- package/dist/openapi/spec-factory.d.ts.map +1 -1
- package/dist/openapi/spec-factory.js +52 -0
- package/dist/openapi/spec-factory.js.map +1 -0
- package/dist/openapi/spec.d.ts +14 -5
- package/dist/openapi/spec.d.ts.map +1 -1
- package/dist/openapi/spec.js +50 -0
- package/dist/openapi/spec.js.map +1 -0
- package/dist/openapi/swagger.d.ts +3 -1
- package/dist/openapi/swagger.d.ts.map +1 -1
- package/dist/openapi/swagger.js +22 -0
- package/dist/openapi/swagger.js.map +1 -0
- package/dist/pattern.d.ts +71 -0
- package/dist/pattern.d.ts.map +1 -0
- package/dist/pattern.js +239 -0
- package/dist/pattern.js.map +1 -0
- package/dist/peer.d.ts +17 -0
- package/dist/peer.d.ts.map +1 -0
- package/dist/peer.js +50 -0
- package/dist/peer.js.map +1 -0
- package/dist/plugin.d.ts +67 -16
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +649 -0
- package/dist/plugin.js.map +1 -0
- package/dist/powered-by.d.ts.map +1 -1
- package/dist/powered-by.js +11 -0
- package/dist/powered-by.js.map +1 -0
- package/dist/pretty-json.d.ts.map +1 -1
- package/dist/pretty-json.js +47 -0
- package/dist/pretty-json.js.map +1 -0
- package/dist/producer-stream.d.ts +47 -0
- package/dist/producer-stream.d.ts.map +1 -0
- package/dist/producer-stream.js +267 -0
- package/dist/producer-stream.js.map +1 -0
- package/dist/proxy.d.ts +47 -8
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +274 -0
- package/dist/proxy.js.map +1 -0
- package/dist/python-type-emitter.d.ts +14 -1
- package/dist/python-type-emitter.d.ts.map +1 -1
- package/dist/python-type-emitter.js +157 -0
- package/dist/python-type-emitter.js.map +1 -0
- package/dist/realtime/bus.d.ts +17 -1
- package/dist/realtime/bus.d.ts.map +1 -1
- package/dist/realtime/bus.js +112 -0
- package/dist/realtime/bus.js.map +1 -0
- package/dist/realtime/register.d.ts +3 -0
- package/dist/realtime/register.d.ts.map +1 -0
- package/dist/realtime/register.js +10 -0
- package/dist/realtime/register.js.map +1 -0
- package/dist/realtime/route.d.ts +65 -26
- package/dist/realtime/route.d.ts.map +1 -1
- package/dist/realtime/route.js +72 -0
- package/dist/realtime/route.js.map +1 -0
- package/dist/realtime/server.d.ts +43 -0
- package/dist/realtime/server.d.ts.map +1 -0
- package/dist/realtime/server.js +255 -0
- package/dist/realtime/server.js.map +1 -0
- package/dist/request-id.d.ts +7 -0
- package/dist/request-id.d.ts.map +1 -1
- package/dist/request-id.js +16 -0
- package/dist/request-id.js.map +1 -0
- package/dist/request-limits.d.ts +3 -0
- package/dist/request-limits.d.ts.map +1 -0
- package/dist/request-limits.js +3 -0
- package/dist/request-limits.js.map +1 -0
- package/dist/request-path.d.ts +33 -0
- package/dist/request-path.d.ts.map +1 -0
- package/dist/request-path.js +178 -0
- package/dist/request-path.js.map +1 -0
- package/dist/request-to-curl.d.ts +7 -1
- package/dist/request-to-curl.d.ts.map +1 -1
- package/dist/request-to-curl.js +48 -0
- package/dist/request-to-curl.js.map +1 -0
- package/dist/response.d.ts +25 -2
- package/dist/response.d.ts.map +1 -1
- package/dist/response.js +313 -0
- package/dist/response.js.map +1 -0
- package/dist/rust-type-emitter.d.ts +14 -2
- package/dist/rust-type-emitter.d.ts.map +1 -1
- package/dist/rust-type-emitter.js +463 -0
- package/dist/rust-type-emitter.js.map +1 -0
- package/dist/secure-headers.d.ts.map +1 -1
- package/dist/secure-headers.js +53 -0
- package/dist/secure-headers.js.map +1 -0
- package/dist/serve-register.d.ts +4 -0
- package/dist/serve-register.d.ts.map +1 -1
- package/dist/serve-register.js +9 -0
- package/dist/serve-register.js.map +1 -0
- package/dist/serve-slot.d.ts +3 -0
- package/dist/serve-slot.d.ts.map +1 -1
- package/dist/serve-slot.js +52 -0
- package/dist/serve-slot.js.map +1 -0
- package/dist/serve.d.ts +18 -1
- package/dist/serve.d.ts.map +1 -1
- package/dist/serve.js +157 -0
- package/dist/serve.js.map +1 -0
- package/dist/server-timing.d.ts.map +1 -1
- package/dist/server-timing.js +51 -0
- package/dist/server-timing.js.map +1 -0
- package/dist/static.d.ts +9 -0
- package/dist/static.d.ts.map +1 -1
- package/dist/static.js +102 -0
- package/dist/static.js.map +1 -0
- package/dist/telemetry/otel.d.ts +2 -0
- package/dist/telemetry/otel.d.ts.map +1 -1
- package/dist/telemetry/otel.js +135 -0
- package/dist/telemetry/otel.js.map +1 -0
- package/dist/testing.d.ts +12 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +124 -0
- package/dist/testing.js.map +1 -0
- package/dist/timeout.d.ts +6 -0
- package/dist/timeout.d.ts.map +1 -1
- package/dist/timeout.js +36 -0
- package/dist/timeout.js.map +1 -0
- package/dist/tree.d.ts +133 -36
- package/dist/tree.d.ts.map +1 -1
- package/dist/tree.js +437 -0
- package/dist/tree.js.map +1 -0
- package/dist/trust.d.ts +21 -0
- package/dist/trust.d.ts.map +1 -0
- package/dist/trust.js +100 -0
- package/dist/trust.js.map +1 -0
- package/dist/ts-type-emitter.d.ts.map +1 -1
- package/dist/ts-type-emitter.js +150 -0
- package/dist/ts-type-emitter.js.map +1 -0
- package/dist/type-emitter.d.ts +16 -2
- package/dist/type-emitter.d.ts.map +1 -1
- package/dist/type-emitter.js +729 -0
- package/dist/type-emitter.js.map +1 -0
- package/dist/type-extractor.d.ts +8 -4
- package/dist/type-extractor.d.ts.map +1 -1
- package/dist/type-extractor.js +819 -0
- package/dist/type-extractor.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +96 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +14 -2
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +335 -0
- package/dist/validation.js.map +1 -0
- package/dist/with-headers.d.ts +15 -0
- package/dist/with-headers.d.ts.map +1 -0
- package/dist/with-headers.js +45 -0
- package/dist/with-headers.js.map +1 -0
- package/dist/ws/bun.d.ts +11 -5
- package/dist/ws/bun.d.ts.map +1 -1
- package/dist/ws/bun.js +82 -0
- package/dist/ws/bun.js.map +1 -0
- package/dist/ws/cloudflare.d.ts +25 -3
- package/dist/ws/cloudflare.d.ts.map +1 -1
- package/dist/ws/cloudflare.js +117 -0
- package/dist/ws/cloudflare.js.map +1 -0
- package/dist/ws/deno.d.ts +4 -4
- package/dist/ws/deno.d.ts.map +1 -1
- package/dist/ws/deno.js +133 -0
- package/dist/ws/deno.js.map +1 -0
- package/dist/ws/node.d.ts +20 -3
- package/dist/ws/node.d.ts.map +1 -1
- package/dist/ws/node.js +173 -0
- package/dist/ws/node.js.map +1 -0
- package/dist/ws/session.d.ts +11 -0
- package/dist/ws/session.d.ts.map +1 -0
- package/dist/ws/session.js +60 -0
- package/dist/ws/session.js.map +1 -0
- package/dist/ws/shared.d.ts +65 -0
- package/dist/ws/shared.d.ts.map +1 -0
- package/dist/ws/shared.js +103 -0
- package/dist/ws/shared.js.map +1 -0
- package/dist/ws-origin.d.ts +20 -0
- package/dist/ws-origin.d.ts.map +1 -0
- package/dist/ws-origin.js +41 -0
- package/dist/ws-origin.js.map +1 -0
- package/dist/yaml.d.ts +15 -1
- package/dist/yaml.d.ts.map +1 -1
- package/dist/yaml.js +101 -0
- package/dist/yaml.js.map +1 -0
- package/docs/invalidate-spec.md +13 -1
- package/docs/meta-spec.md +36 -12
- package/docs/packaging.md +43 -24
- package/docs/regression-matrix/README.md +32 -0
- package/docs/regression-matrix/review.md +44 -0
- package/docs/regression-matrix/ws1-3.md +97 -0
- package/docs/regression-matrix/ws4-8.md +107 -0
- package/docs/regression-matrix/ws9-12.md +266 -0
- package/docs/sdk.md +102 -52
- package/package.json +183 -52
- package/src/accepts.ts +91 -33
- package/src/body-kind.ts +67 -0
- package/src/body-limit.ts +102 -87
- package/src/build/index.ts +104 -54
- package/src/cli-args.ts +123 -0
- package/src/cli-go/auth.go +12 -1
- package/src/cli-go/config.go +29 -2
- package/src/cli-go/errors.go +28 -10
- package/src/cli-go/multipart.go +51 -27
- package/src/cli-go/output.go +58 -4
- package/src/cli-go/root.go +1 -1
- package/src/cli-go/version.go +2 -2
- package/src/cli.ts +154 -148
- package/src/client/error.ts +56 -1
- package/src/client/http.ts +479 -256
- package/src/client/index.ts +55 -17
- package/src/client/path.ts +169 -0
- package/src/client/redirect-policy.ts +19 -0
- package/src/client/sdk.ts +180 -101
- package/src/client/sse.ts +92 -66
- package/src/client/ws.ts +67 -31
- package/src/client-go/errors.go +41 -12
- package/src/client-go/export.go +44 -0
- package/src/client-go/invalidation.go +52 -54
- package/src/client-go/nullable.go +62 -0
- package/src/client-go/realtime.go +147 -110
- package/src/client-go/runtime.go +646 -88
- package/src/client-go/sse.go +104 -94
- package/src/client-go/transport.go +67 -27
- package/src/client-go/ws.go +49 -25
- package/src/client-info.ts +79 -0
- package/src/client-mcp/server.ts +133 -3
- package/src/client-python/_invalidation.py +207 -291
- package/src/client-python/_realtime.py +63 -40
- package/src/client-python/_runtime.py +501 -119
- package/src/client-python/_sse.py +130 -74
- package/src/client-python/_transport.py +37 -9
- package/src/client-python/_ws.py +50 -22
- package/src/client-rust/errors.rs +21 -1
- package/src/client-rust/invalidation.rs +202 -231
- package/src/client-rust/invalidation_sync.rs +16 -229
- package/src/client-rust/nullable.rs +17 -0
- package/src/client-rust/realtime.rs +217 -217
- package/src/client-rust/runtime.rs +602 -177
- package/src/client-rust/runtime_sync.rs +169 -145
- package/src/client-rust/sse.rs +142 -121
- package/src/client-rust/ws.rs +61 -37
- package/src/codegen-go-cli.ts +607 -728
- package/src/codegen-go.ts +710 -770
- package/src/codegen-ir.ts +381 -75
- package/src/codegen-lang.ts +517 -0
- package/src/codegen-load.ts +150 -0
- package/src/codegen-mcp.ts +207 -108
- package/src/codegen-python.ts +684 -816
- package/src/codegen-route-tree-intern.ts +51 -25
- package/src/codegen-rust.ts +946 -1240
- package/src/codegen-sanitize.ts +0 -4
- package/src/codegen-schema-naming.ts +19 -6
- package/src/codegen-sdk-model.ts +228 -0
- package/src/codegen.ts +1488 -1140
- package/src/context.ts +130 -11
- package/src/cookie-sign.ts +85 -16
- package/src/cookie.ts +66 -11
- package/src/cors.ts +55 -54
- package/src/crypto.ts +27 -5
- package/src/csrf.ts +57 -25
- package/src/curl-logger.ts +155 -114
- package/src/dict.ts +12 -0
- package/src/error.ts +4 -2
- package/src/etag.ts +58 -34
- package/src/feature-detect.ts +147 -0
- package/src/feature-slots.ts +70 -0
- package/src/fetch-request.ts +13 -0
- package/src/gen-process.ts +42 -0
- package/src/gen-write.ts +127 -0
- package/src/glob.ts +109 -0
- package/src/go-type-emitter.ts +406 -155
- package/src/honey-response.ts +36 -9
- package/src/i18n-slot.ts +10 -0
- package/src/i18n.ts +98 -23
- package/src/index.ts +1887 -1756
- package/src/init.ts +40 -28
- package/src/invalidate-check.ts +42 -4
- package/src/invoke-user.ts +95 -0
- package/src/ip-restrict.ts +47 -161
- package/src/ip.ts +194 -0
- package/src/logger.ts +65 -36
- package/src/media-type.ts +104 -0
- package/src/meta-spec-merge.ts +80 -0
- package/src/meta-spec.ts +0 -0
- package/src/middleware.ts +112 -12
- package/src/node-request.ts +242 -52
- package/src/node.ts +318 -75
- package/src/openapi/collect.ts +19 -44
- package/src/openapi/docs-page.ts +89 -0
- package/src/openapi/document.ts +503 -224
- package/src/openapi/json-schema-slot.ts +40 -0
- package/src/openapi/register.ts +7 -2
- package/src/openapi/scalar.ts +11 -10
- package/src/openapi/serve.ts +39 -0
- package/src/openapi/spec-factory.ts +50 -1
- package/src/openapi/spec.ts +53 -30
- package/src/openapi/swagger.ts +12 -11
- package/src/pattern.ts +245 -0
- package/src/peer.ts +53 -0
- package/src/plugin.ts +270 -185
- package/src/powered-by.ts +2 -2
- package/src/pretty-json.ts +25 -9
- package/src/producer-stream.ts +296 -0
- package/src/proxy.ts +253 -55
- package/src/python-type-emitter.ts +68 -56
- package/src/realtime/bus.ts +56 -9
- package/src/realtime/register.ts +13 -0
- package/src/realtime/route.ts +129 -80
- package/src/realtime/server.ts +298 -0
- package/src/request-id.ts +13 -3
- package/src/request-limits.ts +2 -0
- package/src/request-path.ts +165 -0
- package/src/request-to-curl.ts +28 -7
- package/src/response.ts +143 -103
- package/src/rust-type-emitter.ts +265 -170
- package/src/secure-headers.ts +8 -4
- package/src/serve-register.ts +4 -0
- package/src/serve-slot.ts +38 -0
- package/src/serve.ts +113 -25
- package/src/server-timing.ts +11 -7
- package/src/static.ts +85 -32
- package/src/telemetry/otel.ts +29 -7
- package/src/testing.ts +76 -14
- package/src/timeout.ts +15 -7
- package/src/tree.ts +405 -333
- package/src/trust.ts +117 -0
- package/src/ts-type-emitter.ts +18 -12
- package/src/type-emitter.ts +227 -89
- package/src/type-extractor.ts +603 -423
- package/src/types.ts +8 -0
- package/src/validation.ts +221 -96
- package/src/with-headers.ts +45 -0
- package/src/ws/bun.ts +53 -15
- package/src/ws/cloudflare.ts +81 -19
- package/src/ws/deno.ts +124 -36
- package/src/ws/node.ts +173 -79
- package/src/ws/session.ts +73 -0
- package/src/ws/shared.ts +140 -0
- package/src/ws-origin.ts +53 -0
- package/src/yaml.ts +45 -22
- package/dist/client-mcp/server.d.ts +0 -10
- package/dist/client-mcp/server.d.ts.map +0 -1
- package/dist/client-mcp/types.d.ts +0 -16
- package/dist/client-mcp/types.d.ts.map +0 -1
- package/dist/cloudflare/realtime.d.ts +0 -30
- package/dist/cloudflare/realtime.d.ts.map +0 -1
- package/dist/realtime/buffer.d.ts +0 -18
- package/dist/realtime/buffer.d.ts.map +0 -1
- package/dist/realtime/longpoll.d.ts +0 -23
- package/dist/realtime/longpoll.d.ts.map +0 -1
- package/dist/realtime/protocol.d.ts +0 -50
- package/dist/realtime/protocol.d.ts.map +0 -1
- package/dist/realtime/runtime.d.ts +0 -74
- package/dist/realtime/runtime.d.ts.map +0 -1
- package/src/cloudflare/realtime.ts +0 -234
- package/src/realtime/buffer.ts +0 -101
- package/src/realtime/longpoll.ts +0 -148
- package/src/realtime/protocol.ts +0 -128
- package/src/realtime/runtime.ts +0 -427
package/src/codegen-ir.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { OpenApiSpecInput } from "./codegen.ts"
|
|
2
|
+
import { cmpCodeUnit, pascalWords } from "./codegen-lang.ts"
|
|
2
3
|
|
|
3
4
|
export type IRScalarType = "string" | "number" | "integer" | "boolean" | "null"
|
|
4
5
|
|
|
5
6
|
export type IRSchema =
|
|
6
7
|
| { kind: "scalar"; type: IRScalarType; format?: string; enum?: (string | number | boolean)[] }
|
|
7
|
-
| {
|
|
8
|
+
| {
|
|
9
|
+
kind: "const"
|
|
10
|
+
value: string | number | boolean
|
|
11
|
+
/** the declared `type`, when the schema has one */ type?: IRScalarType
|
|
12
|
+
}
|
|
8
13
|
| { kind: "object"; fields: IRField[]; additional?: IRSchema | false }
|
|
9
14
|
| { kind: "array"; items: IRSchema }
|
|
10
15
|
| { kind: "tuple"; items: IRSchema[] }
|
|
@@ -31,6 +36,12 @@ export type IRParam = {
|
|
|
31
36
|
name: string
|
|
32
37
|
schema: IRSchema
|
|
33
38
|
description?: string
|
|
39
|
+
/** Path params are always required. */
|
|
40
|
+
required?: boolean
|
|
41
|
+
/** A path param that may span segments (`x-honey-wildcard`). */
|
|
42
|
+
wildcard?: true
|
|
43
|
+
/** `schema.default` as declared. */
|
|
44
|
+
default?: unknown
|
|
34
45
|
}
|
|
35
46
|
|
|
36
47
|
export type IRMultipartPart = {
|
|
@@ -48,6 +59,8 @@ export type IRBody =
|
|
|
48
59
|
contentType: "multipart/form-data"
|
|
49
60
|
parts: IRMultipartPart[]
|
|
50
61
|
required: boolean
|
|
62
|
+
/** The whole form object, for emitters that type the form as one value. */
|
|
63
|
+
schema?: IRSchema
|
|
51
64
|
}
|
|
52
65
|
|
|
53
66
|
export type IRResponse = {
|
|
@@ -71,12 +84,18 @@ export type IROperation = {
|
|
|
71
84
|
method: string /* upper-cased HTTP method */
|
|
72
85
|
path: string /* OpenAPI path template, {param} preserved */
|
|
73
86
|
description?: string
|
|
87
|
+
summary?: string
|
|
74
88
|
params: {
|
|
75
89
|
path: IRParam[]
|
|
76
90
|
query: IRParam[]
|
|
77
91
|
header: IRParam[]
|
|
92
|
+
/** Cookie params. Most SDKs leave them to per-call options; the TypeScript SDK types them. */
|
|
93
|
+
cookie?: IRParam[]
|
|
78
94
|
}
|
|
95
|
+
/** The preferred request body: JSON first, then form, multipart, raw bytes. */
|
|
79
96
|
body?: IRBody
|
|
97
|
+
/** Every declared request body, one per content type, in the same preference order. */
|
|
98
|
+
bodies?: IRBody[]
|
|
80
99
|
responses: Record<string, IRResponse>
|
|
81
100
|
extensions: IROperationExtensions
|
|
82
101
|
}
|
|
@@ -87,24 +106,33 @@ export type IRNamespace = {
|
|
|
87
106
|
entries: Map<string, IRTreeEntry>
|
|
88
107
|
}
|
|
89
108
|
|
|
109
|
+
/** How a client authenticates: the header it sends and the prefix before the token. */
|
|
110
|
+
export type IRAuth = { headerName: string; prefix: string }
|
|
111
|
+
|
|
112
|
+
export type IRInfo = { title?: string; description?: string; version?: string }
|
|
113
|
+
|
|
90
114
|
export type IR = {
|
|
91
115
|
operations: IROperation[]
|
|
92
116
|
schemas: Record<string, IRSchema>
|
|
117
|
+
/** `description` of each component schema that has one. */
|
|
118
|
+
schemaDescriptions: Record<string, string>
|
|
93
119
|
tree: IRNamespace
|
|
120
|
+
auth: IRAuth
|
|
121
|
+
info: IRInfo
|
|
94
122
|
}
|
|
95
123
|
|
|
96
124
|
export function methodsOf(ns: IRNamespace): Array<[string, IROperation]> {
|
|
97
125
|
return [...ns.entries.entries()]
|
|
98
126
|
.filter((e): e is [string, Extract<IRTreeEntry, { kind: "method" }>] => e[1].kind === "method")
|
|
99
127
|
.map(([k, v]): [string, IROperation] => [k, v.op])
|
|
100
|
-
.sort(([a], [b]) => a
|
|
128
|
+
.sort(([a], [b]) => cmpCodeUnit(a, b))
|
|
101
129
|
}
|
|
102
130
|
|
|
103
131
|
export function namespacesOf(ns: IRNamespace): Array<[string, IRNamespace]> {
|
|
104
132
|
return [...ns.entries.entries()]
|
|
105
133
|
.filter((e): e is [string, Extract<IRTreeEntry, { kind: "namespace" }>] => e[1].kind === "namespace")
|
|
106
134
|
.map(([k, v]): [string, IRNamespace] => [k, v.ns])
|
|
107
|
-
.sort(([a], [b]) => a
|
|
135
|
+
.sort(([a], [b]) => cmpCodeUnit(a, b))
|
|
108
136
|
}
|
|
109
137
|
|
|
110
138
|
function firstDescendantId(ns: IRNamespace): string {
|
|
@@ -215,7 +243,10 @@ export function schemaToIR(schema: Record<string, unknown> | undefined): IRSchem
|
|
|
215
243
|
if (schema.const !== undefined) {
|
|
216
244
|
const v = schema.const
|
|
217
245
|
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
|
|
218
|
-
|
|
246
|
+
const out: Extract<IRSchema, { kind: "const" }> = { kind: "const", value: v }
|
|
247
|
+
const t = schema.type
|
|
248
|
+
if (t === "string" || t === "integer" || t === "number" || t === "boolean") out.type = t
|
|
249
|
+
return out
|
|
219
250
|
}
|
|
220
251
|
}
|
|
221
252
|
|
|
@@ -344,15 +375,68 @@ export function schemaToIR(schema: Record<string, unknown> | undefined): IRSchem
|
|
|
344
375
|
|
|
345
376
|
const HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options"] as const
|
|
346
377
|
|
|
378
|
+
export type IRPathSegment = { kind: "literal"; text: string } | { kind: "param"; name: string }
|
|
379
|
+
|
|
380
|
+
/** Splits an OpenAPI path template into literal and `{param}` pieces. Any text between braces is a name. */
|
|
381
|
+
export function parseOpenApiPath(path: string): IRPathSegment[] {
|
|
382
|
+
const out: IRPathSegment[] = []
|
|
383
|
+
const re = /\{([^{}]+)\}/g
|
|
384
|
+
let last = 0
|
|
385
|
+
let match: RegExpExecArray | null = re.exec(path)
|
|
386
|
+
while (match !== null) {
|
|
387
|
+
if (match.index > last) out.push({ kind: "literal", text: path.slice(last, match.index) })
|
|
388
|
+
out.push({ kind: "param", name: match[1] })
|
|
389
|
+
last = match.index + match[0].length
|
|
390
|
+
match = re.exec(path)
|
|
391
|
+
}
|
|
392
|
+
if (last < path.length) out.push({ kind: "literal", text: path.slice(last) })
|
|
393
|
+
return out
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
export function openApiPathParams(path: string): string[] {
|
|
397
|
+
const names: string[] = []
|
|
398
|
+
for (const seg of parseOpenApiPath(path)) {
|
|
399
|
+
if (seg.kind === "param" && !names.includes(seg.name)) names.push(seg.name)
|
|
400
|
+
}
|
|
401
|
+
return names
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
type Components = Record<string, Record<string, unknown>>
|
|
405
|
+
|
|
406
|
+
/** Follows a component `$ref` on a parameter, request body or response object (not on schemas). */
|
|
407
|
+
function deref(value: unknown, components: Components, depth = 0): Record<string, unknown> | undefined {
|
|
408
|
+
if (!value || typeof value !== "object") return undefined
|
|
409
|
+
const obj = value as Record<string, unknown>
|
|
410
|
+
if (typeof obj.$ref !== "string" || depth > 16) return obj
|
|
411
|
+
const parts = obj.$ref.replace(/^#\//, "").split("/")
|
|
412
|
+
if (parts[0] !== "components" || parts.length !== 3) return undefined
|
|
413
|
+
const target = Object.hasOwn(components, parts[1]) ? components[parts[1]] : undefined
|
|
414
|
+
const next = target && Object.hasOwn(target, parts[2]) ? target[parts[2]] : undefined
|
|
415
|
+
return deref(next, components, depth + 1)
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/** Resolves a top-level schema `$ref` against `components.schemas`, for shape checks only. */
|
|
419
|
+
function resolveSchemaShallow(
|
|
420
|
+
schema: Record<string, unknown> | undefined,
|
|
421
|
+
components: Components,
|
|
422
|
+
depth = 0,
|
|
423
|
+
): Record<string, unknown> | undefined {
|
|
424
|
+
if (!schema || typeof schema.$ref !== "string" || depth > 16) return schema
|
|
425
|
+
const name = schema.$ref.split("/").pop() ?? ""
|
|
426
|
+
const schemas = components.schemas ?? {}
|
|
427
|
+
const next = Object.hasOwn(schemas, name) ? (schemas[name] as Record<string, unknown>) : undefined
|
|
428
|
+
return resolveSchemaShallow(next, components, depth + 1)
|
|
429
|
+
}
|
|
430
|
+
|
|
347
431
|
/** Detect whether a multipart/form-data schema has at least one binary (file) property. */
|
|
348
|
-
function hasBinaryMultipartPart(
|
|
349
|
-
const schema = mediaType?.schema as Record<string, unknown> | undefined
|
|
432
|
+
function hasBinaryMultipartPart(schema: Record<string, unknown> | undefined, components: Components): boolean {
|
|
350
433
|
const props = schema?.properties as Record<string, Record<string, unknown>> | undefined
|
|
351
434
|
if (!props) return false
|
|
352
|
-
for (const
|
|
353
|
-
|
|
354
|
-
if (prop
|
|
355
|
-
|
|
435
|
+
for (const raw of Object.values(props)) {
|
|
436
|
+
const prop = resolveSchemaShallow(raw, components)
|
|
437
|
+
if (prop?.format === "binary") return true
|
|
438
|
+
if (prop?.type === "array") {
|
|
439
|
+
const items = resolveSchemaShallow(prop.items as Record<string, unknown> | undefined, components)
|
|
356
440
|
if (items?.format === "binary") return true
|
|
357
441
|
}
|
|
358
442
|
}
|
|
@@ -360,147 +444,369 @@ function hasBinaryMultipartPart(mediaType: Record<string, unknown> | undefined):
|
|
|
360
444
|
}
|
|
361
445
|
|
|
362
446
|
/** Normalise a multipart/form-data object schema into typed parts. */
|
|
363
|
-
function extractMultipartParts(
|
|
364
|
-
const schema = mediaType?.schema as Record<string, unknown> | undefined
|
|
447
|
+
function extractMultipartParts(schema: Record<string, unknown> | undefined, components: Components): IRMultipartPart[] {
|
|
365
448
|
const props = schema?.properties as Record<string, Record<string, unknown>> | undefined
|
|
366
449
|
if (!props) return []
|
|
367
450
|
const parts: IRMultipartPart[] = []
|
|
368
451
|
for (const [name, propSchema] of Object.entries(props)) {
|
|
369
|
-
const
|
|
370
|
-
const
|
|
371
|
-
|
|
452
|
+
const resolved = resolveSchemaShallow(propSchema, components)
|
|
453
|
+
const resolvedItems =
|
|
454
|
+
resolved?.type === "array"
|
|
455
|
+
? resolveSchemaShallow(resolved.items as Record<string, unknown> | undefined, components)
|
|
456
|
+
: undefined
|
|
457
|
+
const isBinary = resolved?.format === "binary" || resolvedItems?.format === "binary"
|
|
458
|
+
parts.push({ name, schema: schemaToIR(propSchema), type: isBinary ? "file" : "text" })
|
|
372
459
|
}
|
|
373
460
|
return parts
|
|
374
461
|
}
|
|
375
462
|
|
|
376
|
-
|
|
463
|
+
/* JSON first, then the structured kinds, then whatever the spec lists first. */
|
|
464
|
+
const BODY_PREFERENCE = [
|
|
465
|
+
"application/json",
|
|
466
|
+
"application/x-www-form-urlencoded",
|
|
467
|
+
"multipart/form-data",
|
|
468
|
+
"application/octet-stream",
|
|
469
|
+
]
|
|
470
|
+
|
|
471
|
+
function isJsonMediaType(ct: string): boolean {
|
|
472
|
+
const essence = ct.split(";")[0]?.trim().toLowerCase() ?? ""
|
|
473
|
+
return essence === "application/json" || essence.endsWith("+json")
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function contentTypeRank(ct: string): number {
|
|
477
|
+
const essence = ct.split(";")[0]?.trim().toLowerCase() ?? ""
|
|
478
|
+
const i = BODY_PREFERENCE.indexOf(essence)
|
|
479
|
+
if (i >= 0) return i
|
|
480
|
+
return isJsonMediaType(ct) ? BODY_PREFERENCE.length : BODY_PREFERENCE.length + 1
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/** Content types in preference order; ties keep the order the spec lists them in. */
|
|
484
|
+
function orderedContentTypes(content: Record<string, unknown>): string[] {
|
|
485
|
+
return Object.keys(content)
|
|
486
|
+
.map((ct, i) => ({ ct, i, rank: contentTypeRank(ct) }))
|
|
487
|
+
.sort((a, b) => a.rank - b.rank || a.i - b.i)
|
|
488
|
+
.map((x) => x.ct)
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function preferredContentType(content: Record<string, unknown>): string | undefined {
|
|
492
|
+
return orderedContentTypes(content)[0]
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function bodyFor(
|
|
496
|
+
ct: string,
|
|
497
|
+
mediaType: Record<string, unknown> | undefined,
|
|
498
|
+
required: boolean,
|
|
499
|
+
components: Components,
|
|
500
|
+
): IRBody {
|
|
501
|
+
const rawSchema = mediaType?.schema as Record<string, unknown> | undefined
|
|
502
|
+
const essence = ct.split(";")[0]?.trim().toLowerCase()
|
|
503
|
+
if (essence === "application/octet-stream") {
|
|
504
|
+
return { contentType: "application/octet-stream", kind: "stream", required }
|
|
505
|
+
}
|
|
506
|
+
if (
|
|
507
|
+
essence === "multipart/form-data" &&
|
|
508
|
+
hasBinaryMultipartPart(resolveSchemaShallow(rawSchema, components), components)
|
|
509
|
+
) {
|
|
510
|
+
const body: IRBody = {
|
|
511
|
+
contentType: "multipart/form-data",
|
|
512
|
+
kind: "multipart",
|
|
513
|
+
parts: extractMultipartParts(resolveSchemaShallow(rawSchema, components), components),
|
|
514
|
+
required,
|
|
515
|
+
}
|
|
516
|
+
if (rawSchema) body.schema = schemaToIR(rawSchema)
|
|
517
|
+
return body
|
|
518
|
+
}
|
|
519
|
+
const bodySchema = rawSchema ? schemaToIR(rawSchema) : { kind: "unknown" as const }
|
|
520
|
+
return { contentType: ct, kind: "raw", required, schema: bodySchema }
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
function buildOperation(
|
|
524
|
+
id: string,
|
|
525
|
+
method: string,
|
|
526
|
+
path: string,
|
|
527
|
+
op: Record<string, unknown>,
|
|
528
|
+
pathItem: Record<string, unknown>,
|
|
529
|
+
components: Components,
|
|
530
|
+
): IROperation {
|
|
377
531
|
const upperMethod = method.toUpperCase()
|
|
378
532
|
|
|
379
|
-
|
|
533
|
+
/* path-item parameters apply to every operation unless the operation overrides (same name + in) */
|
|
534
|
+
const opParams = ((op.parameters as unknown[] | undefined) ?? []).map((p) => deref(p, components))
|
|
535
|
+
const itemParams = ((pathItem.parameters as unknown[] | undefined) ?? []).map((p) => deref(p, components))
|
|
536
|
+
const declaredParams: Record<string, unknown>[] = []
|
|
537
|
+
for (const p of opParams) if (p) declaredParams.push(p)
|
|
538
|
+
for (const p of itemParams) {
|
|
539
|
+
if (!p) continue
|
|
540
|
+
if (!declaredParams.some((d) => d.name === p.name && d.in === p.in)) declaredParams.push(p)
|
|
541
|
+
}
|
|
542
|
+
|
|
380
543
|
const pathParams: IRParam[] = []
|
|
381
544
|
const queryParams: IRParam[] = []
|
|
382
545
|
const headerParams: IRParam[] = []
|
|
383
|
-
const
|
|
546
|
+
const cookieParams: IRParam[] = []
|
|
547
|
+
const templateNames = openApiPathParams(path)
|
|
384
548
|
|
|
385
549
|
for (const p of declaredParams) {
|
|
386
550
|
const pIn = p.in as string
|
|
387
|
-
const pName = p.name
|
|
551
|
+
const pName = String(p.name)
|
|
388
552
|
const pSchema = p.schema
|
|
389
553
|
? schemaToIR(p.schema as Record<string, unknown>)
|
|
390
554
|
: { kind: "scalar" as const, type: "string" as const }
|
|
391
|
-
const param: IRParam = { name: pName, schema: pSchema }
|
|
555
|
+
const param: IRParam = { name: pName, required: pIn === "path" || p.required === true, schema: pSchema }
|
|
392
556
|
if (typeof p.description === "string") param.description = p.description
|
|
557
|
+
if (p["x-honey-wildcard"] === true) param.wildcard = true
|
|
558
|
+
const pDefault = (p.schema as Record<string, unknown> | undefined)?.default
|
|
559
|
+
if (pDefault !== undefined) param.default = pDefault
|
|
393
560
|
if (pIn === "path") {
|
|
394
|
-
|
|
395
|
-
|
|
561
|
+
/* a declared path param missing from the template cannot be sent */
|
|
562
|
+
if (templateNames.includes(pName)) pathParams.push(param)
|
|
396
563
|
} else if (pIn === "query") {
|
|
397
564
|
queryParams.push(param)
|
|
398
565
|
} else if (pIn === "header") {
|
|
399
566
|
headerParams.push(param)
|
|
567
|
+
} else if (pIn === "cookie") {
|
|
568
|
+
cookieParams.push(param)
|
|
400
569
|
}
|
|
401
|
-
/* cookie params discarded per OpenAPI client convention */
|
|
402
570
|
}
|
|
403
571
|
|
|
404
|
-
/* back-fill
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
572
|
+
/* path params in template order; back-fill the ones absent from parameters[] */
|
|
573
|
+
const orderedPath: IRParam[] = []
|
|
574
|
+
for (const name of templateNames) {
|
|
575
|
+
orderedPath.push(
|
|
576
|
+
pathParams.find((p) => p.name === name) ?? { name, required: true, schema: { kind: "scalar", type: "string" } },
|
|
577
|
+
)
|
|
409
578
|
}
|
|
410
579
|
|
|
411
580
|
let body: IRBody | undefined
|
|
412
|
-
const
|
|
581
|
+
const bodies: IRBody[] = []
|
|
582
|
+
const requestBody = deref(op.requestBody, components)
|
|
413
583
|
if (requestBody) {
|
|
414
584
|
const content = requestBody.content as Record<string, Record<string, unknown>> | undefined
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
const required = requestBody.required === true
|
|
419
|
-
|
|
420
|
-
if (firstCt === "application/octet-stream") {
|
|
421
|
-
body = { contentType: "application/octet-stream", kind: "stream", required }
|
|
422
|
-
} else if (firstCt === "multipart/form-data" && hasBinaryMultipartPart(mediaType)) {
|
|
423
|
-
body = {
|
|
424
|
-
contentType: "multipart/form-data",
|
|
425
|
-
kind: "multipart",
|
|
426
|
-
parts: extractMultipartParts(mediaType),
|
|
427
|
-
required,
|
|
428
|
-
}
|
|
429
|
-
} else {
|
|
430
|
-
const bodySchema = mediaType?.schema
|
|
431
|
-
? schemaToIR(mediaType.schema as Record<string, unknown>)
|
|
432
|
-
: { kind: "unknown" as const }
|
|
433
|
-
body = { contentType: firstCt, kind: "raw", required, schema: bodySchema }
|
|
434
|
-
}
|
|
585
|
+
const required = requestBody.required === true
|
|
586
|
+
for (const ct of content ? orderedContentTypes(content) : []) {
|
|
587
|
+
bodies.push(bodyFor(ct, content?.[ct], required, components))
|
|
435
588
|
}
|
|
589
|
+
body = bodies[0]
|
|
436
590
|
}
|
|
437
591
|
|
|
438
592
|
const responses: Record<string, IRResponse> = {}
|
|
439
593
|
const extensions: IROperationExtensions = {}
|
|
440
594
|
|
|
441
|
-
const rawResponses = op.responses as Record<string,
|
|
595
|
+
const rawResponses = op.responses as Record<string, unknown> | undefined
|
|
442
596
|
if (rawResponses) {
|
|
443
|
-
for (const [status,
|
|
597
|
+
for (const [status, rawResponse] of Object.entries(rawResponses)) {
|
|
598
|
+
const response = deref(rawResponse, components) ?? {}
|
|
444
599
|
const content = response.content as Record<string, Record<string, unknown>> | undefined
|
|
445
600
|
if (!content || Object.keys(content).length === 0) {
|
|
446
601
|
responses[status] = { status }
|
|
447
|
-
|
|
448
|
-
const firstCt = Object.keys(content)[0]
|
|
449
|
-
/* SSE detected by response content-type, not a request extension */
|
|
450
|
-
if (firstCt === "text/event-stream") extensions.sse = true
|
|
451
|
-
const mediaType = content[firstCt]
|
|
452
|
-
const respSchema = mediaType?.schema ? schemaToIR(mediaType.schema as Record<string, unknown>) : undefined
|
|
453
|
-
const resp: IRResponse = { contentType: firstCt, status }
|
|
454
|
-
if (respSchema !== undefined) resp.schema = respSchema
|
|
455
|
-
responses[status] = resp
|
|
602
|
+
continue
|
|
456
603
|
}
|
|
604
|
+
/* SSE detected by response content-type, not a request extension */
|
|
605
|
+
if (Object.keys(content).some((k) => k.split(";")[0]?.trim().toLowerCase() === "text/event-stream")) {
|
|
606
|
+
extensions.sse = true
|
|
607
|
+
}
|
|
608
|
+
const ct = preferredContentType(content) ?? Object.keys(content)[0]
|
|
609
|
+
const mediaType = content[ct]
|
|
610
|
+
const respSchema = mediaType?.schema ? schemaToIR(mediaType.schema as Record<string, unknown>) : undefined
|
|
611
|
+
const resp: IRResponse = { contentType: ct, status }
|
|
612
|
+
if (respSchema !== undefined) resp.schema = respSchema
|
|
613
|
+
responses[status] = resp
|
|
457
614
|
}
|
|
458
615
|
}
|
|
459
616
|
|
|
460
617
|
if (op["x-websocket"] === true) extensions.websocket = true
|
|
461
618
|
if (op["x-realtime"] === true) extensions.realtime = true
|
|
462
|
-
if (op["x-deprecated"] === true) extensions.deprecated = true
|
|
619
|
+
if (op["x-deprecated"] === true || op.deprecated === true) extensions.deprecated = true
|
|
463
620
|
if (op["x-idempotency-key"] === true) extensions.idempotencyKey = true
|
|
464
621
|
if (op["x-mcp"] === true) extensions.mcp = true
|
|
465
|
-
if (Array.isArray(op["x-invalidate"]))
|
|
622
|
+
if (Array.isArray(op["x-invalidate"])) {
|
|
623
|
+
extensions.invalidates = (op["x-invalidate"] as unknown[]).filter((x): x is string => typeof x === "string")
|
|
624
|
+
}
|
|
466
625
|
|
|
467
626
|
const operation: IROperation = {
|
|
468
627
|
extensions,
|
|
469
628
|
id,
|
|
470
629
|
method: upperMethod,
|
|
471
|
-
params: { header: headerParams, path:
|
|
630
|
+
params: { header: headerParams, path: orderedPath, query: queryParams },
|
|
472
631
|
path,
|
|
473
632
|
responses,
|
|
474
633
|
}
|
|
634
|
+
if (cookieParams.length > 0) operation.params.cookie = cookieParams
|
|
475
635
|
if (body) operation.body = body
|
|
636
|
+
if (bodies.length > 1) operation.bodies = bodies
|
|
476
637
|
if (typeof op.description === "string") operation.description = op.description
|
|
638
|
+
if (typeof op.summary === "string") operation.summary = op.summary
|
|
477
639
|
|
|
478
640
|
return operation
|
|
479
641
|
}
|
|
480
642
|
|
|
481
|
-
|
|
482
|
-
|
|
643
|
+
/** Deterministic id for an operation without an `operationId`: `GET /users/{id}` → `getUsersById`. */
|
|
644
|
+
export function deriveOperationId(method: string, path: string): string {
|
|
645
|
+
const literal: string[] = []
|
|
646
|
+
const params: string[] = []
|
|
647
|
+
for (const seg of parseOpenApiPath(path)) {
|
|
648
|
+
if (seg.kind === "param") params.push(pascalWords(seg.name))
|
|
649
|
+
else literal.push(pascalWords(seg.text))
|
|
650
|
+
}
|
|
651
|
+
const base = `${method.toLowerCase()}${literal.join("")}${params.length > 0 ? `By${params.join("And")}` : ""}`
|
|
652
|
+
return base === method.toLowerCase() ? `${base}Root` : base
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
export type ToIROptions = {
|
|
656
|
+
/** Give operations without an `operationId` a derived one instead of dropping them, and disambiguate
|
|
657
|
+
* a shared `operationId` by method. The non-TypeScript SDK emitters use this. */
|
|
658
|
+
deriveOperationIds?: boolean
|
|
659
|
+
/** A shared `operationId`: `"suffix"` disambiguates by method (default with `deriveOperationIds`),
|
|
660
|
+
* `"throw"` refuses the document (default otherwise; the TypeScript SDK always refuses). */
|
|
661
|
+
duplicateOperationIds?: "suffix" | "throw"
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
export function toIR(spec: OpenApiSpecInput, options: ToIROptions = {}): IR {
|
|
483
665
|
const schemas: Record<string, IRSchema> = {}
|
|
484
666
|
for (const [name, schema] of Object.entries(spec.components?.schemas ?? {})) {
|
|
485
667
|
schemas[name] = schemaToIR(schema)
|
|
486
668
|
}
|
|
487
669
|
|
|
488
|
-
const
|
|
670
|
+
const components = (spec.components ?? {}) as Components
|
|
489
671
|
const operations: IROperation[] = []
|
|
490
672
|
const seen = new Set<string>()
|
|
491
|
-
|
|
492
|
-
|
|
673
|
+
const pending: Array<{
|
|
674
|
+
method: string
|
|
675
|
+
op: Record<string, unknown>
|
|
676
|
+
path: string
|
|
677
|
+
pathItem: Record<string, unknown>
|
|
678
|
+
}> = []
|
|
679
|
+
|
|
680
|
+
for (const [path, pathItem] of Object.entries(spec.paths ?? {})) {
|
|
493
681
|
for (const method of HTTP_METHODS) {
|
|
494
|
-
const op = pathItem[method] as Record<string, unknown> | undefined
|
|
682
|
+
const op = (pathItem as Record<string, unknown>)[method] as Record<string, unknown> | undefined
|
|
495
683
|
if (!op) continue
|
|
496
684
|
const id = op.operationId as string | undefined
|
|
497
|
-
if (!id)
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
685
|
+
if (!id) {
|
|
686
|
+
if (options.deriveOperationIds)
|
|
687
|
+
pending.push({ method, op, path, pathItem: pathItem as Record<string, unknown> })
|
|
688
|
+
continue
|
|
689
|
+
}
|
|
690
|
+
let finalId = id
|
|
691
|
+
if (seen.has(id)) {
|
|
692
|
+
const onDuplicate = options.duplicateOperationIds ?? (options.deriveOperationIds ? "suffix" : "throw")
|
|
693
|
+
if (onDuplicate === "throw") throw new Error(`Duplicate operationId: "${id}"`)
|
|
694
|
+
finalId = `${id}${pascalWords(method)}`
|
|
695
|
+
for (let i = 2; seen.has(finalId); i++) finalId = `${id}${pascalWords(method)}${i}`
|
|
696
|
+
}
|
|
697
|
+
seen.add(finalId)
|
|
698
|
+
operations.push(buildOperation(finalId, method, path, op, pathItem as Record<string, unknown>, components))
|
|
501
699
|
}
|
|
502
700
|
}
|
|
503
701
|
|
|
702
|
+
/* derived ids after explicit ones, so an explicit id always keeps its name */
|
|
703
|
+
const namespaceRoots = new Set(operations.map((o) => o.id.split(".")[0] ?? o.id))
|
|
704
|
+
for (const { method, op, path, pathItem } of pending) {
|
|
705
|
+
const base = deriveOperationId(method, path)
|
|
706
|
+
let id = base
|
|
707
|
+
for (let i = 2; seen.has(id) || namespaceRoots.has(id); i++) id = `${base}${i}`
|
|
708
|
+
seen.add(id)
|
|
709
|
+
operations.push(buildOperation(id, method, path, op, pathItem, components))
|
|
710
|
+
}
|
|
711
|
+
|
|
504
712
|
const tree = buildResourceTree(operations)
|
|
505
|
-
|
|
713
|
+
const schemaDescriptions: Record<string, string> = {}
|
|
714
|
+
for (const [name, schema] of Object.entries(spec.components?.schemas ?? {})) {
|
|
715
|
+
if (typeof schema.description === "string") schemaDescriptions[name] = schema.description
|
|
716
|
+
}
|
|
717
|
+
return { auth: specAuth(spec), info: infoOf(spec), operations, schemaDescriptions, schemas, tree }
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* The first security scheme (code-unit order) decides the header: http basic → `Basic `, other
|
|
722
|
+
* http → `Bearer `, a header apiKey → its name, with a prefix when its description says
|
|
723
|
+
* `Format: <prefix> {token}`. Anything else, or no scheme, is `Authorization: Bearer`.
|
|
724
|
+
*/
|
|
725
|
+
export function specAuth(spec: OpenApiSpecInput): IRAuth {
|
|
726
|
+
const components = (spec.components ?? {}) as Record<string, unknown>
|
|
727
|
+
const schemes = (components.securitySchemes ?? {}) as Record<string, Record<string, unknown>>
|
|
728
|
+
const keys = Object.keys(schemes).sort(cmpCodeUnit)
|
|
729
|
+
const fallback = { headerName: "Authorization", prefix: "Bearer " }
|
|
730
|
+
const scheme = keys.length > 0 ? schemes[keys[0]] : undefined
|
|
731
|
+
if (!scheme) return fallback
|
|
732
|
+
const type = String(scheme.type ?? "")
|
|
733
|
+
if (type === "http") {
|
|
734
|
+
const httpScheme = String(scheme.scheme ?? "").toLowerCase()
|
|
735
|
+
return { headerName: "Authorization", prefix: httpScheme === "basic" ? "Basic " : "Bearer " }
|
|
736
|
+
}
|
|
737
|
+
if (type === "apiKey" && scheme.in === "header") {
|
|
738
|
+
const headerName = String(scheme.name ?? "Authorization")
|
|
739
|
+
const match = /Format:\s*(\S+)\s+\{/i.exec(String(scheme.description ?? ""))
|
|
740
|
+
return { headerName, prefix: match ? `${match[1]} ` : "" }
|
|
741
|
+
}
|
|
742
|
+
return fallback
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
function infoOf(spec: OpenApiSpecInput): IRInfo {
|
|
746
|
+
const info = ((spec as { info?: unknown }).info ?? {}) as Record<string, unknown>
|
|
747
|
+
const out: IRInfo = {}
|
|
748
|
+
for (const key of ["title", "description", "version"] as const) {
|
|
749
|
+
if (typeof info[key] === "string") out[key] = info[key] as string
|
|
750
|
+
}
|
|
751
|
+
return out
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/** Every request body an operation declares, preferred first. */
|
|
755
|
+
export function bodiesOf(op: IROperation): IRBody[] {
|
|
756
|
+
return op.bodies ?? (op.body ? [op.body] : [])
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/** Follows `ref` nodes to their component schema; an unknown ref resolves to `unknown`. */
|
|
760
|
+
export function irResolver(schemas: Record<string, IRSchema>): (schema: IRSchema) => IRSchema {
|
|
761
|
+
return (schema) => {
|
|
762
|
+
let cur = schema
|
|
763
|
+
for (let i = 0; i < 32 && cur.kind === "ref"; i++) {
|
|
764
|
+
const next = Object.hasOwn(schemas, cur.name) ? schemas[cur.name] : undefined
|
|
765
|
+
if (!next) return { kind: "unknown" }
|
|
766
|
+
cur = next
|
|
767
|
+
}
|
|
768
|
+
return cur
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
function isStringSchema(s: IRSchema | undefined): boolean {
|
|
773
|
+
return s?.kind === "scalar" && s.type === "string"
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* Honey's standard error envelope (`success: false`, `error_key` enum, one `status`), read from the IR.
|
|
778
|
+
* Returns its error keys and status, or null for any other shape.
|
|
779
|
+
*/
|
|
780
|
+
export function irErrorEnvelope(
|
|
781
|
+
schema: IRSchema,
|
|
782
|
+
resolve: (schema: IRSchema) => IRSchema,
|
|
783
|
+
): { keys: string[]; status: number } | null {
|
|
784
|
+
const obj = resolve(schema)
|
|
785
|
+
if (obj.kind !== "object") return null
|
|
786
|
+
const field = (o: Extract<IRSchema, { kind: "object" }>, name: string): IRSchema | undefined => {
|
|
787
|
+
const f = o.fields.find((x) => x.name === name)
|
|
788
|
+
return f ? resolve(f.schema) : undefined
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
const success = field(obj, "success")
|
|
792
|
+
if (success?.kind !== "const" || success.value !== false) return null
|
|
793
|
+
if (!isStringSchema(field(obj, "message")) || !isStringSchema(field(obj, "status_key"))) return null
|
|
794
|
+
|
|
795
|
+
const fields = field(obj, "fields")
|
|
796
|
+
if (fields?.kind !== "object" || !fields.additional) return null
|
|
797
|
+
const list = resolve(fields.additional)
|
|
798
|
+
if (list.kind !== "array") return null
|
|
799
|
+
const item = resolve(list.items)
|
|
800
|
+
if (item.kind !== "object") return null
|
|
801
|
+
for (const k of ["error_key", "message", "path"]) if (!isStringSchema(field(item, k))) return null
|
|
802
|
+
|
|
803
|
+
const status = field(obj, "status")
|
|
804
|
+
if (status?.kind !== "scalar" || !status.enum || status.enum.length !== 1) return null
|
|
805
|
+
const statusVal = status.enum[0]
|
|
806
|
+
if (typeof statusVal !== "number") return null
|
|
807
|
+
|
|
808
|
+
const key = field(obj, "error_key")
|
|
809
|
+
if (key?.kind !== "scalar" || !key.enum || key.enum.length === 0) return null
|
|
810
|
+
if (!key.enum.every((k) => typeof k === "string")) return null
|
|
811
|
+
return { keys: key.enum as string[], status: statusVal }
|
|
506
812
|
}
|