@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
|
@@ -0,0 +1,776 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { canonical, expandOptional, joinPatterns, parsePattern } from "./pattern.js";
|
|
4
|
+
import { quoteKey } from "./type-emitter.js";
|
|
5
|
+
/**
|
|
6
|
+
* The tsconfig that governs the entry: the nearest one walking up, but never past the
|
|
7
|
+
* project root (the nearest directory with a package.json) — a stray tsconfig in a parent
|
|
8
|
+
* directory or the home folder is not this project's.
|
|
9
|
+
*/
|
|
10
|
+
function findTsConfig(fromPath) {
|
|
11
|
+
let dir = dirname(resolve(fromPath));
|
|
12
|
+
let prev = "";
|
|
13
|
+
while (dir !== prev) {
|
|
14
|
+
const p = resolve(dir, "tsconfig.json");
|
|
15
|
+
if (existsSync(p))
|
|
16
|
+
return p;
|
|
17
|
+
if (existsSync(resolve(dir, "package.json")))
|
|
18
|
+
return undefined;
|
|
19
|
+
prev = dir;
|
|
20
|
+
dir = dirname(dir);
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
/* ts-morph bundles a different TS version — structurally identical at runtime */
|
|
25
|
+
function bridge(value) {
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Load the entry and find the app export: `export const app = …`, any other exported
|
|
30
|
+
* declaration of that name, or `export default honey()` for `exportName: "default"`.
|
|
31
|
+
*/
|
|
32
|
+
async function loadEntry(options) {
|
|
33
|
+
const { Project, ts: tsLib } = await import("ts-morph");
|
|
34
|
+
const tsConfigFilePath = options.tsconfigPath ?? findTsConfig(options.entryPath);
|
|
35
|
+
const project = new Project({ skipAddingFilesFromTsConfig: true, tsConfigFilePath });
|
|
36
|
+
project.addSourceFilesAtPaths(options.entryPath);
|
|
37
|
+
project.resolveSourceFileDependencies();
|
|
38
|
+
const sourceFile = project.getSourceFileOrThrow(options.entryPath);
|
|
39
|
+
const declarations = sourceFile.getExportedDeclarations().get(options.exportName);
|
|
40
|
+
const decl = declarations?.[0] ?? sourceFile.getVariableDeclaration(options.exportName);
|
|
41
|
+
if (!decl) {
|
|
42
|
+
throw new Error(`Export "${options.exportName}" not found in ${options.entryPath}`);
|
|
43
|
+
}
|
|
44
|
+
const checker = bridge(project.getTypeChecker().compilerObject);
|
|
45
|
+
const node = bridge(decl.compilerNode);
|
|
46
|
+
const compiler = bridge(tsLib);
|
|
47
|
+
/* `export default <expr>` declares an ExportAssignment; its type is the expression's */
|
|
48
|
+
const target = compiler.isExportAssignment(node) ? node.expression : node;
|
|
49
|
+
const appType = checker.getTypeAtLocation(target);
|
|
50
|
+
return { appType, checker, compiler, node: target, project, sourceFile };
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Uses ts-morph to extract the middleware context type from a Honey app export.
|
|
54
|
+
* Returns inline type strings so the gen file has zero imports from user code.
|
|
55
|
+
*/
|
|
56
|
+
export async function extractBaseCtx(options) {
|
|
57
|
+
const { appType, checker, compiler, node } = await loadEntry(options);
|
|
58
|
+
const ser = new Serializer(checker, node, compiler);
|
|
59
|
+
const typeOfProp = (name) => {
|
|
60
|
+
const sym = appType.getProperty(name);
|
|
61
|
+
return sym ? checker.getTypeOfSymbolAtLocation(sym, node) : null;
|
|
62
|
+
};
|
|
63
|
+
/* extract $env */
|
|
64
|
+
const envT = typeOfProp("$env");
|
|
65
|
+
const envType = envT ? ser.serialize(envT) : "Record<string, unknown>";
|
|
66
|
+
/* extract $ctx and isolate middleware additions */
|
|
67
|
+
const ctxType = typeOfProp("$ctx");
|
|
68
|
+
if (!ctxType) {
|
|
69
|
+
throw new Error(`Export "${options.exportName}" has no $ctx — not a Honey instance`);
|
|
70
|
+
}
|
|
71
|
+
const middlewareType = propsType(extractMiddlewareProps(ctxType, ser));
|
|
72
|
+
/* extract $taps — typed tap payloads declared via .taps<T>() */
|
|
73
|
+
let tapsType = null;
|
|
74
|
+
const tapsT = typeOfProp("$taps");
|
|
75
|
+
if (tapsT) {
|
|
76
|
+
const tapsStr = ser.serialize(tapsT);
|
|
77
|
+
if (tapsStr !== "{}" && tapsStr !== "Record<string, unknown>")
|
|
78
|
+
tapsType = tapsStr;
|
|
79
|
+
}
|
|
80
|
+
const sanitize = (s) => sanitizeImportPaths(s, options.outputDir);
|
|
81
|
+
return {
|
|
82
|
+
envType: sanitize(envType),
|
|
83
|
+
middlewareType: middlewareType ? sanitize(middlewareType) : null,
|
|
84
|
+
tapsType: tapsType ? sanitize(tapsType) : null,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/* properties that live on HoneyContext — everything else is middleware-added */
|
|
88
|
+
const HONEY_CTX_PROPS = new Set([
|
|
89
|
+
"background",
|
|
90
|
+
"cookies",
|
|
91
|
+
"env",
|
|
92
|
+
"errors",
|
|
93
|
+
"executionCtx",
|
|
94
|
+
"headers",
|
|
95
|
+
"meta",
|
|
96
|
+
"params",
|
|
97
|
+
"path",
|
|
98
|
+
"req",
|
|
99
|
+
"res",
|
|
100
|
+
"routePattern",
|
|
101
|
+
"search",
|
|
102
|
+
"searchAll",
|
|
103
|
+
"tap",
|
|
104
|
+
]);
|
|
105
|
+
function propsType(props) {
|
|
106
|
+
if (props.length === 0)
|
|
107
|
+
return null;
|
|
108
|
+
return `{ ${props.map((p) => `${quoteKey(p.name)}${p.opt ? "?" : ""}: ${p.type}`).join("; ")} }`;
|
|
109
|
+
}
|
|
110
|
+
/** Is a property name something a type literal can spell and a consumer can see? */
|
|
111
|
+
function isPublicName(name) {
|
|
112
|
+
/* `#secret` private fields surface as `__#123@#secret` — never part of a type */
|
|
113
|
+
return !name.startsWith("#") && !name.startsWith("__#");
|
|
114
|
+
}
|
|
115
|
+
function extractMiddlewareProps(ctxType, ser) {
|
|
116
|
+
const { checker, compiler, node } = ser;
|
|
117
|
+
const mwProps = ctxType.getProperties().filter((p) => {
|
|
118
|
+
const name = p.getName();
|
|
119
|
+
if (HONEY_CTX_PROPS.has(name))
|
|
120
|
+
return false;
|
|
121
|
+
/* skip internal/private properties (underscore-prefixed) */
|
|
122
|
+
if (name.startsWith("_"))
|
|
123
|
+
return false;
|
|
124
|
+
return isPublicName(name);
|
|
125
|
+
});
|
|
126
|
+
return mwProps.map((p) => {
|
|
127
|
+
const t = checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration ?? node);
|
|
128
|
+
const opt = (p.flags & compiler.SymbolFlags.Optional) !== 0;
|
|
129
|
+
/* 1. try declaration-site TypeReference (explicit annotation on property or variable) */
|
|
130
|
+
let typeStr;
|
|
131
|
+
const mwDecl = p.valueDeclaration ?? p.declarations?.[0];
|
|
132
|
+
typeStr = ser.refFromDeclaration(mwDecl);
|
|
133
|
+
/* 1b. shorthand property — trace to the underlying variable's type annotation */
|
|
134
|
+
if (!typeStr && mwDecl && compiler.isShorthandPropertyAssignment(mwDecl)) {
|
|
135
|
+
const varSym = checker.getShorthandAssignmentValueSymbol(mwDecl);
|
|
136
|
+
if (varSym) {
|
|
137
|
+
const varDecl = varSym.valueDeclaration ?? varSym.declarations?.[0];
|
|
138
|
+
typeStr = ser.refFromDeclaration(varDecl);
|
|
139
|
+
/* 1c. destructured binding (e.g. const { shardDb } = openShardSession(...))
|
|
140
|
+
* — trace through the function return type to find the original type annotation */
|
|
141
|
+
if (!typeStr && varDecl && compiler.isBindingElement(varDecl)) {
|
|
142
|
+
let parent = varDecl.parent;
|
|
143
|
+
while (parent && !compiler.isVariableDeclaration(parent))
|
|
144
|
+
parent = parent.parent;
|
|
145
|
+
if (parent && compiler.isVariableDeclaration(parent)) {
|
|
146
|
+
const initializer = parent.initializer;
|
|
147
|
+
if (initializer) {
|
|
148
|
+
const initType = checker.getTypeAtLocation(initializer);
|
|
149
|
+
const retProp = initType.getProperty(p.getName());
|
|
150
|
+
if (retProp?.valueDeclaration && compiler.isShorthandPropertyAssignment(retProp.valueDeclaration)) {
|
|
151
|
+
const innerSym = checker.getShorthandAssignmentValueSymbol(retProp.valueDeclaration);
|
|
152
|
+
if (innerSym) {
|
|
153
|
+
const innerDecl = innerSym.valueDeclaration ?? innerSym.declarations?.[0];
|
|
154
|
+
typeStr = ser.refFromDeclaration(innerDecl);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/* 2. a named type as an import() reference; 3. structural */
|
|
163
|
+
typeStr ??= ser.asRef(t) ?? ser.serialize(t);
|
|
164
|
+
return { name: p.getName(), opt, type: typeStr };
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/** Check if a symbol is exported from its source file */
|
|
168
|
+
function isExportedFromFile(sym, sf, checker) {
|
|
169
|
+
/* .d.ts module types are always accessible */
|
|
170
|
+
if (sf.isDeclarationFile)
|
|
171
|
+
return true;
|
|
172
|
+
const moduleSym = checker.getSymbolAtLocation(sf);
|
|
173
|
+
if (!moduleSym)
|
|
174
|
+
return false;
|
|
175
|
+
const exports = checker.getExportsOfModule(moduleSym);
|
|
176
|
+
return exports.some((e) => e.getName() === sym.getName());
|
|
177
|
+
}
|
|
178
|
+
/** Lib types every program has in scope; their names are written as is, never imported. */
|
|
179
|
+
function isLibFile(fileName) {
|
|
180
|
+
return /(?:^|[\\/])lib\.[\w.-]*\.d\.ts$/.test(fileName) || /[\\/]typescript[\\/]lib[\\/]/.test(fileName);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* TypeScript types → type source text.
|
|
184
|
+
*
|
|
185
|
+
* Named types become `import("…").Name<Args>` references when the declaring module exports
|
|
186
|
+
* them; everything else is written structurally. The structural writer is precise about the
|
|
187
|
+
* things a reader relies on: optional and rest parameters, generic signatures, tuple rest and
|
|
188
|
+
* optional elements, literal types (quoted), boolean literals, quoted keys, and precedence
|
|
189
|
+
* (`(() => void)[]`, `(A | B) & C`). A type it is still expanding when it meets itself again
|
|
190
|
+
* is written as `unknown` there, never expanded without end.
|
|
191
|
+
*/
|
|
192
|
+
class Serializer {
|
|
193
|
+
checker;
|
|
194
|
+
compiler;
|
|
195
|
+
node;
|
|
196
|
+
#active = new Set();
|
|
197
|
+
constructor(checker, node, compiler) {
|
|
198
|
+
this.checker = checker;
|
|
199
|
+
this.node = node;
|
|
200
|
+
this.compiler = compiler;
|
|
201
|
+
}
|
|
202
|
+
/** An `import()` reference with type arguments for an annotation like `x: Foo<Bar>`. */
|
|
203
|
+
refFromDeclaration(decl) {
|
|
204
|
+
const { checker, compiler } = this;
|
|
205
|
+
if (!decl)
|
|
206
|
+
return undefined;
|
|
207
|
+
const typeRef = decl.type;
|
|
208
|
+
if (!typeRef || !compiler.isTypeReferenceNode(typeRef))
|
|
209
|
+
return undefined;
|
|
210
|
+
let refSym = checker.getSymbolAtLocation(typeRef.typeName);
|
|
211
|
+
while (refSym && refSym.flags & compiler.SymbolFlags.Alias)
|
|
212
|
+
refSym = checker.getAliasedSymbol(refSym);
|
|
213
|
+
if (!refSym?.declarations?.length)
|
|
214
|
+
return undefined;
|
|
215
|
+
const srcFile = refSym.declarations[0].getSourceFile();
|
|
216
|
+
if (isLibFile(srcFile.fileName))
|
|
217
|
+
return undefined;
|
|
218
|
+
if (!isExportedFromFile(refSym, srcFile, checker))
|
|
219
|
+
return undefined;
|
|
220
|
+
const args = typeRef.typeArguments?.map((a) => {
|
|
221
|
+
const t = checker.getTypeFromTypeNode(a);
|
|
222
|
+
return this.asRef(t) ?? this.serialize(t);
|
|
223
|
+
});
|
|
224
|
+
const argText = args && args.length > 0 ? `<${args.join(", ")}>` : "";
|
|
225
|
+
return `import("${srcFile.fileName}").${refSym.getName()}${argText}`;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* `import("path").TypeName<Args>` for a named type whose module exports it, else null.
|
|
229
|
+
* Globals (Promise, Map, …) are left to `serialize`.
|
|
230
|
+
*/
|
|
231
|
+
asRef(type, depth = 0) {
|
|
232
|
+
const { checker, compiler } = this;
|
|
233
|
+
if (depth > 6)
|
|
234
|
+
return null;
|
|
235
|
+
/* union with never members (from intersection narrowing) — simplify first */
|
|
236
|
+
if (type.isUnion()) {
|
|
237
|
+
const nonNever = type.types.filter((t) => !(t.flags & compiler.TypeFlags.Never));
|
|
238
|
+
if (nonNever.length === 1)
|
|
239
|
+
return this.asRef(nonNever[0], depth);
|
|
240
|
+
}
|
|
241
|
+
const sym = type.aliasSymbol ?? type.getSymbol();
|
|
242
|
+
if (!sym)
|
|
243
|
+
return null;
|
|
244
|
+
const name = sym.getName();
|
|
245
|
+
if (!name || name.startsWith("__") || name === "Object")
|
|
246
|
+
return null;
|
|
247
|
+
const decls = sym.declarations;
|
|
248
|
+
if (!decls?.length)
|
|
249
|
+
return null;
|
|
250
|
+
const sf = decls[0].getSourceFile();
|
|
251
|
+
if (isLibFile(sf.fileName))
|
|
252
|
+
return null;
|
|
253
|
+
const named = (sym.flags &
|
|
254
|
+
(compiler.SymbolFlags.TypeAlias |
|
|
255
|
+
compiler.SymbolFlags.Interface |
|
|
256
|
+
compiler.SymbolFlags.Class |
|
|
257
|
+
compiler.SymbolFlags.Enum)) !==
|
|
258
|
+
0;
|
|
259
|
+
/* only reference .d.ts symbols or explicitly declared named types from .ts files */
|
|
260
|
+
if (!sf.isDeclarationFile && !named)
|
|
261
|
+
return null;
|
|
262
|
+
/* skip ambient .d.ts scripts (no exports) — import() can't resolve them */
|
|
263
|
+
if (sf.isDeclarationFile && !sf.externalModuleIndicator) {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
/* skip non-exported symbols — import() on them resolves to `any` */
|
|
267
|
+
if (!isExportedFromFile(sym, sf, checker))
|
|
268
|
+
return null;
|
|
269
|
+
const typeArgs = type.aliasSymbol ? type.aliasTypeArguments : type.typeArguments;
|
|
270
|
+
/* a class or interface reference carries its `this` type as a trailing argument */
|
|
271
|
+
const declared = sym.declarations?.[0];
|
|
272
|
+
const paramCount = declared && "typeParameters" in declared
|
|
273
|
+
? (declared.typeParameters?.length ?? 0)
|
|
274
|
+
: (typeArgs?.length ?? 0);
|
|
275
|
+
const args = (typeArgs ?? []).slice(0, paramCount);
|
|
276
|
+
if (args.length > 0) {
|
|
277
|
+
const text = args.map((arg) => this.asRef(arg, depth + 1) ?? this.serialize(arg));
|
|
278
|
+
return `import("${sf.fileName}").${name}<${text.join(", ")}>`;
|
|
279
|
+
}
|
|
280
|
+
return `import("${sf.fileName}").${name}`;
|
|
281
|
+
}
|
|
282
|
+
serialize(type) {
|
|
283
|
+
if (this.#active.has(type))
|
|
284
|
+
return "unknown";
|
|
285
|
+
this.#active.add(type);
|
|
286
|
+
try {
|
|
287
|
+
return this.#serialize(type);
|
|
288
|
+
}
|
|
289
|
+
finally {
|
|
290
|
+
this.#active.delete(type);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
#serialize(type) {
|
|
294
|
+
const { checker, compiler, node } = this;
|
|
295
|
+
const F = compiler.TypeFlags;
|
|
296
|
+
const next = (t) => this.serialize(t);
|
|
297
|
+
/* an enum is nominal: keep its name when it can be referenced */
|
|
298
|
+
const enumSym = type.getSymbol();
|
|
299
|
+
if (enumSym && enumSym.flags & compiler.SymbolFlags.Enum) {
|
|
300
|
+
const ref = this.asRef(type);
|
|
301
|
+
if (ref)
|
|
302
|
+
return ref;
|
|
303
|
+
}
|
|
304
|
+
/* primitives */
|
|
305
|
+
if (type.flags & F.String)
|
|
306
|
+
return "string";
|
|
307
|
+
if (type.flags & F.Number)
|
|
308
|
+
return "number";
|
|
309
|
+
if (type.flags & F.Boolean)
|
|
310
|
+
return "boolean";
|
|
311
|
+
if (type.flags & F.BigInt)
|
|
312
|
+
return "bigint";
|
|
313
|
+
if (type.flags & F.ESSymbol)
|
|
314
|
+
return "symbol";
|
|
315
|
+
if (type.flags & F.UniqueESSymbol)
|
|
316
|
+
return "symbol";
|
|
317
|
+
if (type.flags & F.Void)
|
|
318
|
+
return "void";
|
|
319
|
+
if (type.flags & F.Undefined)
|
|
320
|
+
return "undefined";
|
|
321
|
+
if (type.flags & F.Null)
|
|
322
|
+
return "null";
|
|
323
|
+
if (type.flags & F.Never)
|
|
324
|
+
return "never";
|
|
325
|
+
if (type.flags & F.Unknown)
|
|
326
|
+
return "unknown";
|
|
327
|
+
if (type.flags & F.Any)
|
|
328
|
+
return "unknown";
|
|
329
|
+
if (type.flags & F.NonPrimitive)
|
|
330
|
+
return "object";
|
|
331
|
+
/* literals */
|
|
332
|
+
if (type.isStringLiteral())
|
|
333
|
+
return JSON.stringify(type.value);
|
|
334
|
+
if (type.isNumberLiteral())
|
|
335
|
+
return `${type.value}`;
|
|
336
|
+
if (type.flags & F.BigIntLiteral) {
|
|
337
|
+
const v = type.value;
|
|
338
|
+
return `${v.negative ? "-" : ""}${v.base10Value}n`;
|
|
339
|
+
}
|
|
340
|
+
if (type.flags & F.BooleanLiteral)
|
|
341
|
+
return checker.typeToString(type);
|
|
342
|
+
if (type.flags & F.TemplateLiteral)
|
|
343
|
+
return "string";
|
|
344
|
+
/* a type parameter with no binding — its constraint, or unknown */
|
|
345
|
+
if (type.flags & F.TypeParameter) {
|
|
346
|
+
const constraint = checker.getBaseConstraintOfType(type);
|
|
347
|
+
return constraint && constraint !== type ? next(constraint) : "unknown";
|
|
348
|
+
}
|
|
349
|
+
/* union */
|
|
350
|
+
if (type.isUnion())
|
|
351
|
+
return unionText(type.types.map(next));
|
|
352
|
+
/* intersection */
|
|
353
|
+
if (type.isIntersection())
|
|
354
|
+
return intersectionText(type.types.map(next));
|
|
355
|
+
/* array */
|
|
356
|
+
if (checker.isArrayType(type)) {
|
|
357
|
+
const args = checker.getTypeArguments(type);
|
|
358
|
+
const readonlyArray = type.getSymbol()?.getName() === "ReadonlyArray";
|
|
359
|
+
const el = args.length > 0 ? arrayText(next(args[0])) : "unknown[]";
|
|
360
|
+
return readonlyArray ? `readonly ${el}` : el;
|
|
361
|
+
}
|
|
362
|
+
/* tuple — rest and optional elements kept */
|
|
363
|
+
if (checker.isTupleType(type)) {
|
|
364
|
+
const ref = type;
|
|
365
|
+
const args = checker.getTypeArguments(ref);
|
|
366
|
+
const target = ref.target;
|
|
367
|
+
const parts = args.map((arg, i) => {
|
|
368
|
+
const flags = target.elementFlags?.[i] ?? compiler.ElementFlags.Required;
|
|
369
|
+
if (flags & compiler.ElementFlags.Rest)
|
|
370
|
+
return `...${arrayText(next(arg))}`;
|
|
371
|
+
if (flags & compiler.ElementFlags.Variadic)
|
|
372
|
+
return `...${next(arg)}`;
|
|
373
|
+
if (flags & compiler.ElementFlags.Optional)
|
|
374
|
+
return `${next(arg)}?`;
|
|
375
|
+
return next(arg);
|
|
376
|
+
});
|
|
377
|
+
return `${target.readonly ? "readonly " : ""}[${parts.join(", ")}]`;
|
|
378
|
+
}
|
|
379
|
+
/* function (pure callable, no data properties) */
|
|
380
|
+
const sigs = type.getCallSignatures();
|
|
381
|
+
if (sigs.length > 0 && type.getProperties().length === 0) {
|
|
382
|
+
const parts = sigs.map((sig) => this.#signature(sig));
|
|
383
|
+
return parts.length === 1 ? parts[0] : parts.map((p) => `(${p})`).join(" & ");
|
|
384
|
+
}
|
|
385
|
+
/* well-known globals — keep name, serialize type args */
|
|
386
|
+
const sym = type.getSymbol();
|
|
387
|
+
if (sym) {
|
|
388
|
+
const name = sym.getName();
|
|
389
|
+
const decl = sym.declarations?.[0];
|
|
390
|
+
if (decl && isLibFile(decl.getSourceFile().fileName) && name !== "Object" && !name.startsWith("__")) {
|
|
391
|
+
const args = type.typeArguments ?? [];
|
|
392
|
+
const declaredParams = decl.typeParameters?.length ?? args.length;
|
|
393
|
+
const kept = args.slice(0, declaredParams);
|
|
394
|
+
return kept.length > 0 ? `${name}<${kept.map(next).join(", ")}>` : name;
|
|
395
|
+
}
|
|
396
|
+
/* named types — prefer import() reference over structural expansion */
|
|
397
|
+
if (name && !name.startsWith("__") && name !== "Object") {
|
|
398
|
+
const ref = this.asRef(type);
|
|
399
|
+
if (ref)
|
|
400
|
+
return ref;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
const aliasRef = type.aliasSymbol ? this.asRef(type) : null;
|
|
404
|
+
if (aliasRef)
|
|
405
|
+
return aliasRef;
|
|
406
|
+
/* Record<string, V> — index signature only */
|
|
407
|
+
const stringIdx = type.getStringIndexType();
|
|
408
|
+
if (stringIdx && type.getProperties().length === 0) {
|
|
409
|
+
return `Record<string, ${next(stringIdx)}>`;
|
|
410
|
+
}
|
|
411
|
+
/* object — expand to structural form */
|
|
412
|
+
const props = type.getProperties().filter((p) => isPublicName(p.getName()));
|
|
413
|
+
const entries = [];
|
|
414
|
+
for (const p of props) {
|
|
415
|
+
const decls = p.getDeclarations();
|
|
416
|
+
if (decls?.length) {
|
|
417
|
+
const flags = compiler.getCombinedModifierFlags(decls[0]);
|
|
418
|
+
if (flags & (compiler.ModifierFlags.Private | compiler.ModifierFlags.Protected))
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
const pt = checker.getTypeOfSymbolAtLocation(p, decls?.[0] ?? node);
|
|
422
|
+
const opt = (p.flags & compiler.SymbolFlags.Optional) !== 0;
|
|
423
|
+
const ro = decls?.some((d) => (compiler.getCombinedModifierFlags(d) & compiler.ModifierFlags.Readonly) !== 0) ?? false;
|
|
424
|
+
entries.push(`${ro ? "readonly " : ""}${quoteKey(p.getName())}${opt ? "?" : ""}: ${next(pt)}`);
|
|
425
|
+
}
|
|
426
|
+
if (stringIdx)
|
|
427
|
+
entries.push(`[key: string]: ${next(stringIdx)}`);
|
|
428
|
+
for (const sig of sigs)
|
|
429
|
+
entries.push(this.#signature(sig, true));
|
|
430
|
+
if (entries.length > 0)
|
|
431
|
+
return `{ ${entries.join("; ")} }`;
|
|
432
|
+
if (props.length === 0)
|
|
433
|
+
return "{}";
|
|
434
|
+
return "unknown";
|
|
435
|
+
}
|
|
436
|
+
/** `<T extends X>(a: A, b?: B, ...rest: C[]) => R`, or the call-signature member form */
|
|
437
|
+
#signature(sig, member = false) {
|
|
438
|
+
const { checker, compiler, node } = this;
|
|
439
|
+
const typeParams = sig.getTypeParameters() ?? [];
|
|
440
|
+
const tp = typeParams.length > 0
|
|
441
|
+
? `<${typeParams
|
|
442
|
+
.map((t) => {
|
|
443
|
+
const c = t.getConstraint();
|
|
444
|
+
return `${t.symbol.getName()}${c ? ` extends ${this.#typeParamText(c)}` : ""}`;
|
|
445
|
+
})
|
|
446
|
+
.join(", ")}>`
|
|
447
|
+
: "";
|
|
448
|
+
const params = sig.getParameters().map((p) => {
|
|
449
|
+
const pt = checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration ?? node);
|
|
450
|
+
const decl = p.valueDeclaration;
|
|
451
|
+
const param = decl && compiler.isParameter(decl) ? decl : undefined;
|
|
452
|
+
const isRest = param?.dotDotDotToken !== undefined;
|
|
453
|
+
const optional = !isRest && param !== undefined && checker.isOptionalParameter(param);
|
|
454
|
+
/* an optional parameter's type carries `| undefined`; `?` already says so */
|
|
455
|
+
const text = optional ? this.#typeParamText(checker.getNonNullableType(pt)) : this.#typeParamText(pt);
|
|
456
|
+
return `${isRest ? "..." : ""}${p.getName()}${optional ? "?" : ""}: ${text}`;
|
|
457
|
+
});
|
|
458
|
+
const ret = this.#typeParamText(checker.getReturnTypeOfSignature(sig));
|
|
459
|
+
return member ? `${tp}(${params.join(", ")}): ${ret}` : `${tp}(${params.join(", ")}) => ${ret}`;
|
|
460
|
+
}
|
|
461
|
+
/** A type inside a signature: a bare type parameter stays by name, bound by the signature. */
|
|
462
|
+
#typeParamText(t) {
|
|
463
|
+
if (t.flags & this.compiler.TypeFlags.TypeParameter)
|
|
464
|
+
return t.symbol.getName();
|
|
465
|
+
return this.asRef(t) ?? this.serialize(t);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Does `type` contain `token` outside every bracket and string? Used to parenthesize only
|
|
470
|
+
* where precedence needs it.
|
|
471
|
+
*/
|
|
472
|
+
function hasTopLevel(type, token) {
|
|
473
|
+
let depth = 0;
|
|
474
|
+
let quote = null;
|
|
475
|
+
for (let i = 0; i < type.length; i++) {
|
|
476
|
+
const c = type[i];
|
|
477
|
+
if (quote !== null) {
|
|
478
|
+
if (c === "\\")
|
|
479
|
+
i++;
|
|
480
|
+
else if (c === quote)
|
|
481
|
+
quote = null;
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
if (c === '"' || c === "'" || c === "`")
|
|
485
|
+
quote = c;
|
|
486
|
+
else if (c === "(" || c === "{" || c === "[" || c === "<")
|
|
487
|
+
depth++;
|
|
488
|
+
else if (c === ")" || c === "}" || c === "]" || (c === ">" && type[i - 1] !== "="))
|
|
489
|
+
depth--;
|
|
490
|
+
else if (depth === 0 && type.startsWith(token, i))
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
function arrayText(el) {
|
|
496
|
+
return hasTopLevel(el, "|") || hasTopLevel(el, "&") || hasTopLevel(el, "=>") || el.startsWith("readonly ")
|
|
497
|
+
? `(${el})[]`
|
|
498
|
+
: `${el}[]`;
|
|
499
|
+
}
|
|
500
|
+
function unionText(parts) {
|
|
501
|
+
return [...new Set(parts)].map((p) => (hasTopLevel(p, "=>") ? `(${p})` : p)).join(" | ");
|
|
502
|
+
}
|
|
503
|
+
function intersectionText(parts) {
|
|
504
|
+
return parts.map((p) => (hasTopLevel(p, "|") || hasTopLevel(p, "=>") ? `(${p})` : p)).join(" & ");
|
|
505
|
+
}
|
|
506
|
+
const packageCache = new Map();
|
|
507
|
+
function nearestPackage(fromFile) {
|
|
508
|
+
let dir = dirname(fromFile);
|
|
509
|
+
const visited = [];
|
|
510
|
+
let found = null;
|
|
511
|
+
let prev = "";
|
|
512
|
+
while (dir !== prev) {
|
|
513
|
+
const cached = packageCache.get(dir);
|
|
514
|
+
if (cached !== undefined) {
|
|
515
|
+
found = cached;
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
visited.push(dir);
|
|
519
|
+
const file = join(dir, "package.json");
|
|
520
|
+
if (existsSync(file)) {
|
|
521
|
+
try {
|
|
522
|
+
const json = JSON.parse(readFileSync(file, "utf8"));
|
|
523
|
+
/* a package.json without a name (a "type": "module" marker) is not a package boundary */
|
|
524
|
+
if (typeof json.name === "string") {
|
|
525
|
+
found = { dir, json };
|
|
526
|
+
break;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
catch {
|
|
530
|
+
/* unreadable — keep walking */
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
prev = dir;
|
|
534
|
+
dir = dirname(dir);
|
|
535
|
+
}
|
|
536
|
+
for (const d of visited)
|
|
537
|
+
packageCache.set(d, found);
|
|
538
|
+
return found;
|
|
539
|
+
}
|
|
540
|
+
/** Every file an `exports` value can point at, with the subpath that names it. */
|
|
541
|
+
function exportTargets(exports) {
|
|
542
|
+
const out = [];
|
|
543
|
+
const collect = (subpath, value) => {
|
|
544
|
+
if (typeof value === "string")
|
|
545
|
+
out.push({ subpath, target: value });
|
|
546
|
+
else if (Array.isArray(value))
|
|
547
|
+
for (const v of value)
|
|
548
|
+
collect(subpath, v);
|
|
549
|
+
else if (value !== null && typeof value === "object") {
|
|
550
|
+
for (const v of Object.values(value))
|
|
551
|
+
collect(subpath, v);
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
if (typeof exports === "string" || Array.isArray(exports))
|
|
555
|
+
collect(".", exports);
|
|
556
|
+
else if (exports !== null && typeof exports === "object") {
|
|
557
|
+
const entries = Object.entries(exports);
|
|
558
|
+
if (entries.length > 0 && entries.every(([k]) => !k.startsWith(".")))
|
|
559
|
+
collect(".", exports);
|
|
560
|
+
else
|
|
561
|
+
for (const [k, v] of entries)
|
|
562
|
+
collect(k, v);
|
|
563
|
+
}
|
|
564
|
+
return out;
|
|
565
|
+
}
|
|
566
|
+
function stripTypeExtension(path) {
|
|
567
|
+
return path
|
|
568
|
+
.replace(/\.d\.[mc]?ts$/, "")
|
|
569
|
+
.replace(/\.[mc]?tsx?$/, "")
|
|
570
|
+
.replace(/\.[mc]?js$/, "");
|
|
571
|
+
}
|
|
572
|
+
/** `@types/foo` types the `foo` package; `@types/scope__name` types `@scope/name`. */
|
|
573
|
+
function typedPackageName(name) {
|
|
574
|
+
if (!name.startsWith("@types/"))
|
|
575
|
+
return name;
|
|
576
|
+
const bare = name.slice("@types/".length);
|
|
577
|
+
return bare.includes("__") ? `@${bare.replace("__", "/")}` : bare;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* The specifier a generated file should use to import `filePath`.
|
|
581
|
+
*
|
|
582
|
+
* A file of another package is named through that package — its `exports` subpath when one
|
|
583
|
+
* points at the file (any condition: `types`, `default`, or a source condition), its `types`
|
|
584
|
+
* entry, or (no `exports` map) its path without extension; an `@types` package by the package it
|
|
585
|
+
* types. A file of the output's own package is a relative path. Lib files never get here.
|
|
586
|
+
*/
|
|
587
|
+
function moduleSpecifier(filePath, outputDir) {
|
|
588
|
+
const pkg = nearestPackage(filePath);
|
|
589
|
+
const ownPkg = outputDir ? nearestPackage(join(outputDir, "_")) : null;
|
|
590
|
+
const relativeSpecifier = () => {
|
|
591
|
+
if (!outputDir)
|
|
592
|
+
return filePath;
|
|
593
|
+
let rel = relative(outputDir, filePath).split(sep).join("/");
|
|
594
|
+
if (!rel.startsWith("."))
|
|
595
|
+
rel = `./${rel}`;
|
|
596
|
+
return rel;
|
|
597
|
+
};
|
|
598
|
+
if (!pkg || (ownPkg && pkg.dir === ownPkg.dir))
|
|
599
|
+
return relativeSpecifier();
|
|
600
|
+
const name = typedPackageName(String(pkg.json.name));
|
|
601
|
+
const rel = `./${relative(pkg.dir, filePath).split(sep).join("/")}`;
|
|
602
|
+
if (pkg.json.exports !== undefined) {
|
|
603
|
+
const match = exportTargets(pkg.json.exports).find((e) => e.target === rel || stripTypeExtension(e.target) === stripTypeExtension(rel));
|
|
604
|
+
if (match)
|
|
605
|
+
return match.subpath === "." ? name : `${name}/${match.subpath.replace(/^\.\//, "")}`;
|
|
606
|
+
/* the package does not export this file — a path into it would not resolve */
|
|
607
|
+
return relativeSpecifier();
|
|
608
|
+
}
|
|
609
|
+
const typesEntry = pkg.json.types ?? pkg.json.typings;
|
|
610
|
+
if (typeof typesEntry === "string" &&
|
|
611
|
+
stripTypeExtension(`./${typesEntry.replace(/^\.\//, "")}`) === stripTypeExtension(rel)) {
|
|
612
|
+
return name;
|
|
613
|
+
}
|
|
614
|
+
const sub = stripTypeExtension(rel.slice(2)).replace(/\/index$/, "");
|
|
615
|
+
return sub === "index" || sub === "" ? name : `${name}/${sub}`;
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Rewrite absolute `import("…")` paths into resolvable module specifiers, and drop the
|
|
619
|
+
* `import()` around lib types (`Date`, `Promise`), which are global.
|
|
620
|
+
*/
|
|
621
|
+
function sanitizeImportPaths(str, outputDir) {
|
|
622
|
+
return str.replace(/import\("([^"]+)"\)\./g, (_match, filePath) => {
|
|
623
|
+
if (isLibFile(filePath))
|
|
624
|
+
return "";
|
|
625
|
+
return `import("${moduleSpecifier(filePath, outputDir)}").`;
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
const HTTP_METHODS = new Set(["all", "delete", "get", "head", "options", "patch", "post", "put"]);
|
|
629
|
+
/**
|
|
630
|
+
* Extracts base ctx and per-route middleware additions from sub-chains.
|
|
631
|
+
*
|
|
632
|
+
* Every source file of the program is scanned for HTTP method calls (`.get()`, `.post()`, …)
|
|
633
|
+
* on a Honey instance. A route is keyed by its full path — the receiver's `$basePath` type
|
|
634
|
+
* joined with the literal path, exactly as the router registers it — so `v1.get("/items")`
|
|
635
|
+
* and `pub.get("/items")` never share an entry. A receiver whose base path is not a literal
|
|
636
|
+
* type cannot be keyed and is skipped: a route without an entry gets the base ctx, never
|
|
637
|
+
* another route's.
|
|
638
|
+
*/
|
|
639
|
+
export async function extractChainTypes(options) {
|
|
640
|
+
const { appType, checker, compiler, node: baseNode, project } = await loadEntry(options);
|
|
641
|
+
const ser = new Serializer(checker, baseNode, compiler);
|
|
642
|
+
function getCtxType(tsType, locationNode) {
|
|
643
|
+
const sym = tsType.getProperty("$ctx");
|
|
644
|
+
if (!sym)
|
|
645
|
+
return null;
|
|
646
|
+
return checker.getTypeOfSymbolAtLocation(sym, locationNode ?? sym.valueDeclaration ?? baseNode);
|
|
647
|
+
}
|
|
648
|
+
function basePathOf(tsType, locationNode) {
|
|
649
|
+
const sym = tsType.getProperty("$basePath");
|
|
650
|
+
if (!sym)
|
|
651
|
+
return null;
|
|
652
|
+
const t = checker.getTypeOfSymbolAtLocation(sym, locationNode);
|
|
653
|
+
return t.isStringLiteral() ? t.value : null;
|
|
654
|
+
}
|
|
655
|
+
/* extract base ctx */
|
|
656
|
+
let envType = "Record<string, unknown>";
|
|
657
|
+
const envSym = appType.getProperty("$env");
|
|
658
|
+
if (envSym)
|
|
659
|
+
envType = ser.serialize(checker.getTypeOfSymbolAtLocation(envSym, baseNode));
|
|
660
|
+
const baseCtxType = getCtxType(appType, baseNode);
|
|
661
|
+
if (!baseCtxType) {
|
|
662
|
+
throw new Error(`Export "${options.exportName}" has no $ctx — not a Honey instance`);
|
|
663
|
+
}
|
|
664
|
+
const baseMwProps = extractMiddlewareProps(baseCtxType, ser);
|
|
665
|
+
const baseMiddlewareType = propsType(baseMwProps);
|
|
666
|
+
/* build name→type map for reusing base type references in route middleware */
|
|
667
|
+
const basePropTypeByName = new Map();
|
|
668
|
+
for (const p of baseMwProps)
|
|
669
|
+
basePropTypeByName.set(p.name, p.type);
|
|
670
|
+
/* collect base middleware property names for diffing */
|
|
671
|
+
const baseMwPropNames = new Set();
|
|
672
|
+
for (const p of baseCtxType.getProperties()) {
|
|
673
|
+
const name = p.getName();
|
|
674
|
+
if (!HONEY_CTX_PROPS.has(name) && !name.startsWith("_"))
|
|
675
|
+
baseMwPropNames.add(name);
|
|
676
|
+
}
|
|
677
|
+
const sanitize = (s) => sanitizeImportPaths(s, options.outputDir);
|
|
678
|
+
const routeMiddleware = Object.create(null);
|
|
679
|
+
const routeMiddlewareProps = Object.create(null);
|
|
680
|
+
function visitNode(node) {
|
|
681
|
+
if (compiler.isCallExpression(node) && compiler.isPropertyAccessExpression(node.expression)) {
|
|
682
|
+
const methodName = node.expression.name.text;
|
|
683
|
+
const pathArg = node.arguments[0];
|
|
684
|
+
if (HTTP_METHODS.has(methodName) && pathArg && compiler.isStringLiteralLike(pathArg)) {
|
|
685
|
+
const receiverExpr = node.expression.expression;
|
|
686
|
+
const receiverType = checker.getTypeAtLocation(receiverExpr);
|
|
687
|
+
const ctxType = getCtxType(receiverType, receiverExpr);
|
|
688
|
+
const basePath = ctxType ? basePathOf(receiverType, receiverExpr) : null;
|
|
689
|
+
if (ctxType && basePath !== null) {
|
|
690
|
+
for (const variant of fullPaths(basePath, pathArg.text))
|
|
691
|
+
recordRoute(`${methodName} ${variant}`, ctxType);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
compiler.forEachChild(node, visitNode);
|
|
696
|
+
}
|
|
697
|
+
/** The paths the router serves for this registration — an optional last param yields two. */
|
|
698
|
+
function fullPaths(basePath, path) {
|
|
699
|
+
try {
|
|
700
|
+
return expandOptional(parsePattern(joinPatterns(basePath, path))).map((segments) => canonical(segments));
|
|
701
|
+
}
|
|
702
|
+
catch {
|
|
703
|
+
/* a pattern the router would refuse registers nothing */
|
|
704
|
+
return [];
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
function recordRoute(key, ctxType) {
|
|
708
|
+
/* extract extra middleware props by iterating intersection MEMBERS individually.
|
|
709
|
+
* This preserves source-level declarations (e.g. ShorthandPropertyAssignment)
|
|
710
|
+
* that get lost when extracting from the flattened intersection. */
|
|
711
|
+
const extraEntries = [];
|
|
712
|
+
const dupeNames = new Set();
|
|
713
|
+
const members = ctxType.isIntersection() ? ctxType.types : [ctxType];
|
|
714
|
+
for (const member of members) {
|
|
715
|
+
for (const rp of extractMiddlewareProps(member, ser)) {
|
|
716
|
+
if (baseMwPropNames.has(rp.name))
|
|
717
|
+
continue;
|
|
718
|
+
if (extraEntries.some((e) => e.name === rp.name)) {
|
|
719
|
+
dupeNames.add(rp.name);
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
extraEntries.push(rp);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
/* a property in several intersection members (e.g. auth narrowed by a later middleware)
|
|
726
|
+
* is read from the flattened intersection, so TypeScript computes the intersected type */
|
|
727
|
+
for (const dupeName of dupeNames) {
|
|
728
|
+
const sym = ctxType.getProperty(dupeName);
|
|
729
|
+
if (!sym)
|
|
730
|
+
continue;
|
|
731
|
+
const t = checker.getTypeOfSymbolAtLocation(sym, sym.valueDeclaration ?? baseNode);
|
|
732
|
+
const typeStr = ser.asRef(t) ?? ser.serialize(t);
|
|
733
|
+
const idx = extraEntries.findIndex((e) => e.name === dupeName);
|
|
734
|
+
if (idx !== -1)
|
|
735
|
+
extraEntries[idx] = { ...extraEntries[idx], type: typeStr };
|
|
736
|
+
}
|
|
737
|
+
if (extraEntries.length === 0)
|
|
738
|
+
return;
|
|
739
|
+
/* reuse compact base type references when the route has the same property
|
|
740
|
+
* (e.g. shardDb: ShardDb from base → reuse import ref instead of structural expansion) */
|
|
741
|
+
const entries = extraEntries.map((e) => {
|
|
742
|
+
const baseRef = basePropTypeByName.get(e.name);
|
|
743
|
+
return baseRef && baseRef.length < e.type.length ? { ...e, type: baseRef } : e;
|
|
744
|
+
});
|
|
745
|
+
routeMiddleware[key] = sanitize(propsType(entries) ?? "{}");
|
|
746
|
+
routeMiddlewareProps[key] = entries.map((e) => ({ name: e.name, opt: e.opt, type: sanitize(e.type) }));
|
|
747
|
+
}
|
|
748
|
+
/* every source file of the program, not only the entry: routes are often registered in
|
|
749
|
+
modules the entry imports */
|
|
750
|
+
for (const sf of project.getSourceFiles()) {
|
|
751
|
+
const compilerSf = bridge(sf.compilerNode);
|
|
752
|
+
if (compilerSf.isDeclarationFile)
|
|
753
|
+
continue;
|
|
754
|
+
if (/[\\/]node_modules[\\/]/.test(compilerSf.fileName))
|
|
755
|
+
continue;
|
|
756
|
+
visitNode(compilerSf);
|
|
757
|
+
}
|
|
758
|
+
/* extract $taps */
|
|
759
|
+
let tapsType = null;
|
|
760
|
+
const tapsSym = appType.getProperty("$taps");
|
|
761
|
+
if (tapsSym) {
|
|
762
|
+
const tapsStr = ser.serialize(checker.getTypeOfSymbolAtLocation(tapsSym, baseNode));
|
|
763
|
+
if (tapsStr !== "{}" && tapsStr !== "Record<string, unknown>")
|
|
764
|
+
tapsType = tapsStr;
|
|
765
|
+
}
|
|
766
|
+
return {
|
|
767
|
+
base: {
|
|
768
|
+
envType: sanitize(envType),
|
|
769
|
+
middlewareType: baseMiddlewareType ? sanitize(baseMiddlewareType) : null,
|
|
770
|
+
tapsType: tapsType ? sanitize(tapsType) : null,
|
|
771
|
+
},
|
|
772
|
+
routeMiddleware: { ...routeMiddleware },
|
|
773
|
+
routeMiddlewareProps: { ...routeMiddlewareProps },
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
//# sourceMappingURL=type-extractor.js.map
|