ts-procedures 8.5.0 → 9.0.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 +166 -101
- package/agent_config/claude-code/.claude-plugin/plugin.json +1 -1
- package/agent_config/claude-code/agents/ts-procedures-architect.md +11 -10
- package/agent_config/claude-code/skills/ts-procedures/SKILL.md +25 -12
- package/agent_config/claude-code/skills/ts-procedures/anti-patterns.md +10 -12
- package/agent_config/claude-code/skills/ts-procedures/api-reference.md +141 -45
- package/agent_config/claude-code/skills/ts-procedures/checklist.md +7 -6
- package/agent_config/claude-code/skills/ts-procedures/patterns.md +45 -6
- package/agent_config/claude-code/skills/ts-procedures/templates/client.md +1 -1
- package/agent_config/claude-code/skills/ts-procedures/templates/hono.md +1 -1
- package/agent_config/copilot/copilot-instructions.md +50 -33
- package/agent_config/cursor/cursorrules +50 -33
- package/build/adapters/astro/astro-context.js.map +1 -0
- package/build/adapters/astro/create-handler.js.map +1 -0
- package/build/adapters/astro/index.js.map +1 -0
- package/build/{implementations/http → adapters}/astro/index.test.js +1 -1
- package/build/adapters/astro/index.test.js.map +1 -0
- package/build/adapters/astro/rewrite-request.js.map +1 -0
- package/build/adapters/hono/envelope-parity.test.js +98 -0
- package/build/adapters/hono/envelope-parity.test.js.map +1 -0
- package/build/{implementations/http → adapters}/hono/handlers/http-stream.d.ts +1 -1
- package/build/adapters/hono/handlers/http-stream.js +55 -0
- package/build/adapters/hono/handlers/http-stream.js.map +1 -0
- package/build/{implementations/http → adapters}/hono/handlers/http-stream.test.js +1 -1
- package/build/adapters/hono/handlers/http-stream.test.js.map +1 -0
- package/build/{implementations/http → adapters}/hono/handlers/http.d.ts +1 -1
- package/build/adapters/hono/handlers/http.js +50 -0
- package/build/adapters/hono/handlers/http.js.map +1 -0
- package/build/{implementations/http → adapters}/hono/handlers/http.test.js +1 -1
- package/build/adapters/hono/handlers/http.test.js.map +1 -0
- package/build/{implementations/http → adapters}/hono/handlers/rpc.d.ts +2 -2
- package/build/adapters/hono/handlers/rpc.js +23 -0
- package/build/adapters/hono/handlers/rpc.js.map +1 -0
- package/build/{implementations/http → adapters}/hono/handlers/rpc.test.js +1 -1
- package/build/adapters/hono/handlers/rpc.test.js.map +1 -0
- package/build/adapters/hono/handlers/stream.d.ts +12 -0
- package/build/adapters/hono/handlers/stream.js +89 -0
- package/build/adapters/hono/handlers/stream.js.map +1 -0
- package/build/{implementations/http → adapters}/hono/handlers/stream.test.js +3 -2
- package/build/adapters/hono/handlers/stream.test.js.map +1 -0
- package/build/{implementations/http → adapters}/hono/index.d.ts +24 -12
- package/build/{implementations/http → adapters}/hono/index.js +19 -8
- package/build/adapters/hono/index.js.map +1 -0
- package/build/{implementations/http → adapters}/hono/index.test.js +2 -4
- package/build/adapters/hono/index.test.js.map +1 -0
- package/build/{implementations/http → adapters/hono}/on-request-error.test.js +2 -2
- package/build/adapters/hono/on-request-error.test.js.map +1 -0
- package/build/adapters/hono/request.d.ts +7 -0
- package/build/adapters/hono/request.js +22 -0
- package/build/adapters/hono/request.js.map +1 -0
- package/build/{implementations/http → adapters/hono}/route-errors.test.js +4 -4
- package/build/adapters/hono/route-errors.test.js.map +1 -0
- package/build/adapters/hono/types.d.ts +55 -0
- package/build/adapters/hono/types.js +19 -0
- package/build/adapters/hono/types.js.map +1 -0
- package/build/client/freeze.test.js +39 -0
- package/build/client/freeze.test.js.map +1 -0
- package/build/client/typed-error-dispatch.test.js +2 -2
- package/build/client/typed-error-dispatch.test.js.map +1 -1
- package/build/codegen/__fixtures__/make-envelope.d.ts +1 -1
- package/build/codegen/bin/cli.d.ts +5 -0
- package/build/codegen/bin/cli.js +139 -182
- package/build/codegen/bin/cli.js.map +1 -1
- package/build/codegen/bin/cli.test.js +12 -2
- package/build/codegen/bin/cli.test.js.map +1 -1
- package/build/codegen/bin/flag-specs.d.ts +9 -0
- package/build/codegen/bin/flag-specs.js +33 -31
- package/build/codegen/bin/flag-specs.js.map +1 -1
- package/build/codegen/bin/flag-specs.test.js +14 -1
- package/build/codegen/bin/flag-specs.test.js.map +1 -1
- package/build/codegen/collect-models.d.ts +1 -1
- package/build/codegen/emit/api-route.d.ts +8 -0
- package/build/codegen/emit/api-route.js +156 -0
- package/build/codegen/emit/api-route.js.map +1 -0
- package/build/codegen/emit/context.d.ts +30 -0
- package/build/codegen/emit/context.js +2 -0
- package/build/codegen/emit/context.js.map +1 -0
- package/build/codegen/emit/declarations.d.ts +24 -0
- package/build/codegen/emit/declarations.js +48 -0
- package/build/codegen/emit/declarations.js.map +1 -0
- package/build/codegen/emit/format-types.d.ts +61 -0
- package/build/codegen/emit/format-types.js +188 -0
- package/build/codegen/emit/format-types.js.map +1 -0
- package/build/codegen/emit/http-stream-route.d.ts +7 -0
- package/build/codegen/emit/http-stream-route.js +138 -0
- package/build/codegen/emit/http-stream-route.js.map +1 -0
- package/build/codegen/emit/route-shared.d.ts +35 -0
- package/build/codegen/emit/route-shared.js +88 -0
- package/build/codegen/emit/route-shared.js.map +1 -0
- package/build/codegen/emit/rpc-route.d.ts +7 -0
- package/build/codegen/emit/rpc-route.js +37 -0
- package/build/codegen/emit/rpc-route.js.map +1 -0
- package/build/codegen/emit/scope-file.d.ts +39 -0
- package/build/codegen/emit/scope-file.js +166 -0
- package/build/codegen/emit/scope-file.js.map +1 -0
- package/build/codegen/emit/stream-route.d.ts +7 -0
- package/build/codegen/emit/stream-route.js +62 -0
- package/build/codegen/emit/stream-route.js.map +1 -0
- package/build/codegen/emit-errors.d.ts +1 -1
- package/build/codegen/emit-errors.integration.test.js +1 -1
- package/build/codegen/emit-errors.integration.test.js.map +1 -1
- package/build/codegen/emit-index.js +13 -0
- package/build/codegen/emit-index.js.map +1 -1
- package/build/codegen/emit-index.test.js +25 -0
- package/build/codegen/emit-index.test.js.map +1 -1
- package/build/codegen/emit-scope.d.ts +13 -30
- package/build/codegen/emit-scope.js +15 -807
- package/build/codegen/emit-scope.js.map +1 -1
- package/build/codegen/emit-scope.test.js +86 -4
- package/build/codegen/emit-scope.test.js.map +1 -1
- package/build/codegen/goldens.test.js +69 -0
- package/build/codegen/goldens.test.js.map +1 -0
- package/build/codegen/group-routes.d.ts +1 -1
- package/build/codegen/pipeline.d.ts +1 -1
- package/build/codegen/resolve-envelope.d.ts +1 -1
- package/build/codegen/targets/_shared/error-schemas.d.ts +1 -1
- package/build/codegen/targets/_shared/route-slots.d.ts +1 -1
- package/build/codegen/targets/_shared/target-run.d.ts +1 -1
- package/build/codegen/targets/kotlin/emit-route-kotlin.d.ts +1 -1
- package/build/codegen/targets/swift/emit-route-swift.d.ts +1 -1
- package/build/core/create-http-stream.d.ts +50 -0
- package/build/core/create-http-stream.js +108 -0
- package/build/core/create-http-stream.js.map +1 -0
- package/build/{create-http-stream.test.js → core/create-http-stream.test.js} +1 -1
- package/build/core/create-http-stream.test.js.map +1 -0
- package/build/core/create-http.d.ts +51 -0
- package/build/core/create-http.js +65 -0
- package/build/core/create-http.js.map +1 -0
- package/build/{create-http.test.js → core/create-http.test.js} +13 -4
- package/build/core/create-http.test.js.map +1 -0
- package/build/core/create-stream.d.ts +26 -0
- package/build/core/create-stream.js +80 -0
- package/build/core/create-stream.js.map +1 -0
- package/build/{create-stream.test.js → core/create-stream.test.js} +23 -28
- package/build/core/create-stream.test.js.map +1 -0
- package/build/core/create.d.ts +22 -0
- package/build/core/create.js +71 -0
- package/build/core/create.js.map +1 -0
- package/build/{create.test.js → core/create.test.js} +25 -46
- package/build/core/create.test.js.map +1 -0
- package/build/core/definition-site.d.ts +24 -0
- package/build/{stack-utils.js → core/definition-site.js} +20 -20
- package/build/core/definition-site.js.map +1 -0
- package/build/{stack-utils.test.js → core/definition-site.test.js} +12 -3
- package/build/core/definition-site.test.js.map +1 -0
- package/build/{errors.d.ts → core/errors.d.ts} +19 -8
- package/build/{errors.js → core/errors.js} +21 -26
- package/build/core/errors.js.map +1 -0
- package/build/core/errors.test.js.map +1 -0
- package/build/core/factory-options.test.js +82 -0
- package/build/core/factory-options.test.js.map +1 -0
- package/build/core/http-route.d.ts +13 -0
- package/build/core/http-route.js +54 -0
- package/build/core/http-route.js.map +1 -0
- package/build/core/internal.d.ts +72 -0
- package/build/core/internal.js +128 -0
- package/build/core/internal.js.map +1 -0
- package/build/{migration.test.js → core/migration.test.js} +17 -1
- package/build/core/migration.test.js.map +1 -0
- package/build/core/procedures.d.ts +143 -0
- package/build/core/procedures.js +64 -0
- package/build/core/procedures.js.map +1 -0
- package/build/{index.test.js → core/procedures.test.js} +14 -11
- package/build/core/procedures.test.js.map +1 -0
- package/build/core/types.d.ts +182 -0
- package/build/{schema → core}/types.js.map +1 -1
- package/build/exports.d.ts +31 -11
- package/build/exports.js +23 -8
- package/build/exports.js.map +1 -1
- package/build/schema/adapter.d.ts +35 -0
- package/build/schema/adapter.js +13 -0
- package/build/schema/adapter.js.map +1 -0
- package/build/schema/adapter.test.js +53 -0
- package/build/schema/adapter.test.js.map +1 -0
- package/build/schema/compile.d.ts +37 -0
- package/build/schema/compile.js +38 -0
- package/build/schema/compile.js.map +1 -0
- package/build/schema/compile.test.js +78 -0
- package/build/schema/compile.test.js.map +1 -0
- package/build/schema/compute-schema.d.ts +47 -37
- package/build/schema/compute-schema.js +86 -29
- package/build/schema/compute-schema.js.map +1 -1
- package/build/schema/compute-schema.test.js +158 -40
- package/build/schema/compute-schema.test.js.map +1 -1
- package/build/schema/json-schema.d.ts +17 -0
- package/build/schema/json-schema.js +2 -0
- package/build/schema/json-schema.js.map +1 -0
- package/build/schema/typebox.d.ts +11 -0
- package/build/schema/typebox.js +24 -0
- package/build/schema/typebox.js.map +1 -0
- package/build/schema/typebox.test.js +34 -0
- package/build/schema/typebox.test.js.map +1 -0
- package/build/server/context.d.ts +8 -0
- package/build/server/context.js +7 -0
- package/build/server/context.js.map +1 -0
- package/build/server/context.test.js +16 -0
- package/build/server/context.test.js.map +1 -0
- package/build/{doc-envelope.d.ts → server/doc-envelope.d.ts} +1 -1
- package/build/server/doc-envelope.js.map +1 -0
- package/build/server/doc-envelope.test.d.ts +1 -0
- package/build/server/doc-envelope.test.js.map +1 -0
- package/build/{implementations/http → server}/doc-registry.d.ts +7 -2
- package/build/{implementations/http → server}/doc-registry.js +9 -5
- package/build/server/doc-registry.js.map +1 -0
- package/build/server/doc-registry.test.d.ts +1 -0
- package/build/{implementations/http → server}/doc-registry.test.js +27 -24
- package/build/server/doc-registry.test.js.map +1 -0
- package/build/server/docs/docs.test.d.ts +1 -0
- package/build/server/docs/docs.test.js +237 -0
- package/build/server/docs/docs.test.js.map +1 -0
- package/build/{implementations/http/hono → server}/docs/http-doc.d.ts +2 -2
- package/build/{implementations/http/hono → server}/docs/http-doc.js +1 -1
- package/build/server/docs/http-doc.js.map +1 -0
- package/build/{implementations/http/hono → server}/docs/http-stream-doc.d.ts +2 -2
- package/build/{implementations/http/hono → server}/docs/http-stream-doc.js +1 -1
- package/build/server/docs/http-stream-doc.js.map +1 -0
- package/build/{implementations/http/hono → server}/docs/rpc-doc.d.ts +2 -2
- package/build/{implementations/http/hono → server}/docs/rpc-doc.js +1 -1
- package/build/server/docs/rpc-doc.js.map +1 -0
- package/build/{implementations/http/hono → server}/docs/stream-doc.d.ts +2 -2
- package/build/{implementations/http/hono → server}/docs/stream-doc.js +1 -1
- package/build/server/docs/stream-doc.js.map +1 -0
- package/build/server/errors/dispatch.d.ts +96 -0
- package/build/{implementations/http/error-dispatch.js → server/errors/dispatch.js} +20 -10
- package/build/server/errors/dispatch.js.map +1 -0
- package/build/server/errors/dispatch.test.d.ts +1 -0
- package/build/server/errors/dispatch.test.js +418 -0
- package/build/server/errors/dispatch.test.js.map +1 -0
- package/build/{implementations/http/error-taxonomy.d.ts → server/errors/taxonomy.d.ts} +8 -17
- package/build/{implementations/http/error-taxonomy.js → server/errors/taxonomy.js} +6 -15
- package/build/server/errors/taxonomy.js.map +1 -0
- package/build/server/errors/taxonomy.test.d.ts +1 -0
- package/build/{implementations/http/error-taxonomy.test.js → server/errors/taxonomy.test.js} +45 -39
- package/build/server/errors/taxonomy.test.js.map +1 -0
- package/build/server/index.d.ts +29 -0
- package/build/server/index.js +27 -0
- package/build/server/index.js.map +1 -0
- package/build/server/no-framework-imports.test.d.ts +1 -0
- package/build/server/no-framework-imports.test.js +40 -0
- package/build/server/no-framework-imports.test.js.map +1 -0
- package/build/{implementations/http/hono/path.d.ts → server/paths.d.ts} +2 -3
- package/build/{implementations/http/hono/path.js → server/paths.js} +1 -1
- package/build/server/paths.js.map +1 -0
- package/build/server/paths.test.d.ts +1 -0
- package/build/server/paths.test.js +111 -0
- package/build/server/paths.test.js.map +1 -0
- package/build/server/request/params.d.ts +29 -0
- package/build/server/request/params.js +43 -0
- package/build/server/request/params.js.map +1 -0
- package/build/server/request/params.test.d.ts +1 -0
- package/build/server/request/params.test.js +91 -0
- package/build/server/request/params.test.js.map +1 -0
- package/build/server/request/query.d.ts +9 -0
- package/build/server/request/query.js +22 -0
- package/build/server/request/query.js.map +1 -0
- package/build/server/request/query.test.d.ts +1 -0
- package/build/server/request/query.test.js +60 -0
- package/build/server/request/query.test.js.map +1 -0
- package/build/server/sse.d.ts +70 -0
- package/build/server/sse.js +94 -0
- package/build/server/sse.js.map +1 -0
- package/build/server/sse.test.d.ts +1 -0
- package/build/server/sse.test.js +98 -0
- package/build/server/sse.test.js.map +1 -0
- package/build/{implementations → server}/types.d.ts +17 -15
- package/build/{implementations → server}/types.js.map +1 -1
- package/docs/astro-adapter.md +8 -9
- package/docs/client-and-codegen.md +4 -4
- package/docs/client-error-handling.md +92 -5
- package/docs/codegen-kotlin.md +2 -3
- package/docs/codegen-swift.md +1 -2
- package/docs/core.md +135 -54
- package/docs/http-integrations.md +83 -6
- package/docs/migration-v8-to-v9.md +192 -0
- package/docs/plans/2026-06-09-v9-rewrite.md +130 -0
- package/docs/specs/2026-06-09-v9-rewrite-design.md +221 -0
- package/docs/streaming.md +12 -0
- package/package.json +23 -47
- package/src/{implementations/http → adapters}/astro/index.test.ts +2 -2
- package/src/adapters/hono/__fixtures__/parity-envelope.json +389 -0
- package/src/adapters/hono/envelope-parity.test.ts +126 -0
- package/src/{implementations/http → adapters}/hono/handlers/http-stream.test.ts +1 -1
- package/src/adapters/hono/handlers/http-stream.ts +73 -0
- package/src/{implementations/http → adapters}/hono/handlers/http.test.ts +1 -1
- package/src/adapters/hono/handlers/http.ts +70 -0
- package/src/{implementations/http → adapters}/hono/handlers/rpc.test.ts +2 -2
- package/src/adapters/hono/handlers/rpc.ts +39 -0
- package/src/{implementations/http → adapters}/hono/handlers/stream.test.ts +4 -3
- package/src/{implementations/http → adapters}/hono/handlers/stream.ts +19 -92
- package/src/{implementations/http → adapters}/hono/index.test.ts +14 -16
- package/src/{implementations/http → adapters}/hono/index.ts +35 -30
- package/src/{implementations/http → adapters/hono}/on-request-error.test.ts +3 -3
- package/src/adapters/hono/request.ts +28 -0
- package/src/{implementations/http → adapters/hono}/route-errors.test.ts +5 -5
- package/src/{implementations/http → adapters}/hono/types.ts +43 -20
- package/src/client/freeze.test.ts +41 -0
- package/src/client/typed-error-dispatch.test.ts +3 -3
- package/src/codegen/__fixtures__/make-envelope.ts +1 -1
- package/src/codegen/__fixtures__/models-envelope.json +310 -0
- package/src/codegen/__fixtures__/users-envelope.json +9 -0
- package/src/codegen/__goldens__/MANIFEST.json +85 -0
- package/src/codegen/__goldens__/kotlin-default--models/Billing.kt +112 -0
- package/src/codegen/__goldens__/kotlin-default--models/BillingReports.kt +26 -0
- package/src/codegen/__goldens__/kotlin-default--models/Orders.kt +88 -0
- package/src/codegen/__goldens__/kotlin-default--users/Users.kt +189 -0
- package/src/codegen/__goldens__/swift-default--models/Billing.swift +97 -0
- package/src/codegen/__goldens__/swift-default--models/BillingReports.swift +20 -0
- package/src/codegen/__goldens__/swift-default--models/Orders.swift +81 -0
- package/src/codegen/__goldens__/swift-default--users/Users.swift +204 -0
- package/src/codegen/__goldens__/ts-default--models/_client.ts +1319 -0
- package/src/codegen/__goldens__/ts-default--models/_errors.ts +90 -0
- package/src/codegen/__goldens__/ts-default--models/_models.ts +10 -0
- package/src/codegen/__goldens__/ts-default--models/_types.ts +502 -0
- package/src/codegen/__goldens__/ts-default--models/billing-reports.ts +29 -0
- package/src/codegen/__goldens__/ts-default--models/billing.ts +67 -0
- package/src/codegen/__goldens__/ts-default--models/index.ts +48 -0
- package/src/codegen/__goldens__/ts-default--models/orders.ts +80 -0
- package/src/codegen/__goldens__/ts-default--users/_client.ts +1319 -0
- package/src/codegen/__goldens__/ts-default--users/_errors.ts +90 -0
- package/src/codegen/__goldens__/ts-default--users/_types.ts +502 -0
- package/src/codegen/__goldens__/ts-default--users/index.ts +38 -0
- package/src/codegen/__goldens__/ts-default--users/users.ts +169 -0
- package/src/codegen/__goldens__/ts-external-runtime--models/_errors.ts +90 -0
- package/src/codegen/__goldens__/ts-external-runtime--models/_models.ts +10 -0
- package/src/codegen/__goldens__/ts-external-runtime--models/billing-reports.ts +29 -0
- package/src/codegen/__goldens__/ts-external-runtime--models/billing.ts +67 -0
- package/src/codegen/__goldens__/ts-external-runtime--models/index.ts +48 -0
- package/src/codegen/__goldens__/ts-external-runtime--models/orders.ts +80 -0
- package/src/codegen/__goldens__/ts-external-runtime--users/_errors.ts +90 -0
- package/src/codegen/__goldens__/ts-external-runtime--users/index.ts +38 -0
- package/src/codegen/__goldens__/ts-external-runtime--users/users.ts +169 -0
- package/src/codegen/__goldens__/ts-flat--models/_client.ts +1319 -0
- package/src/codegen/__goldens__/ts-flat--models/_errors.ts +87 -0
- package/src/codegen/__goldens__/ts-flat--models/_models.ts +10 -0
- package/src/codegen/__goldens__/ts-flat--models/_types.ts +502 -0
- package/src/codegen/__goldens__/ts-flat--models/billing-reports.ts +28 -0
- package/src/codegen/__goldens__/ts-flat--models/billing.ts +51 -0
- package/src/codegen/__goldens__/ts-flat--models/index.ts +42 -0
- package/src/codegen/__goldens__/ts-flat--models/orders.ts +73 -0
- package/src/codegen/__goldens__/ts-flat--users/_client.ts +1319 -0
- package/src/codegen/__goldens__/ts-flat--users/_errors.ts +87 -0
- package/src/codegen/__goldens__/ts-flat--users/_types.ts +502 -0
- package/src/codegen/__goldens__/ts-flat--users/index.ts +34 -0
- package/src/codegen/__goldens__/ts-flat--users/users.ts +126 -0
- package/src/codegen/__goldens__/ts-no-share-models--models/_client.ts +1319 -0
- package/src/codegen/__goldens__/ts-no-share-models--models/_errors.ts +90 -0
- package/src/codegen/__goldens__/ts-no-share-models--models/_types.ts +502 -0
- package/src/codegen/__goldens__/ts-no-share-models--models/billing-reports.ts +29 -0
- package/src/codegen/__goldens__/ts-no-share-models--models/billing.ts +111 -0
- package/src/codegen/__goldens__/ts-no-share-models--models/index.ts +48 -0
- package/src/codegen/__goldens__/ts-no-share-models--models/orders.ts +112 -0
- package/src/codegen/__goldens__/ts-no-share-models--users/_client.ts +1319 -0
- package/src/codegen/__goldens__/ts-no-share-models--users/_errors.ts +90 -0
- package/src/codegen/__goldens__/ts-no-share-models--users/_types.ts +502 -0
- package/src/codegen/__goldens__/ts-no-share-models--users/index.ts +38 -0
- package/src/codegen/__goldens__/ts-no-share-models--users/users.ts +169 -0
- package/src/codegen/__goldens__/ts-shared-models-module--models/_client.ts +1319 -0
- package/src/codegen/__goldens__/ts-shared-models-module--models/_errors.ts +90 -0
- package/src/codegen/__goldens__/ts-shared-models-module--models/_models.ts +7 -0
- package/src/codegen/__goldens__/ts-shared-models-module--models/_types.ts +502 -0
- package/src/codegen/__goldens__/ts-shared-models-module--models/billing-reports.ts +29 -0
- package/src/codegen/__goldens__/ts-shared-models-module--models/billing.ts +67 -0
- package/src/codegen/__goldens__/ts-shared-models-module--models/index.ts +48 -0
- package/src/codegen/__goldens__/ts-shared-models-module--models/orders.ts +80 -0
- package/src/codegen/bin/cli.test.ts +13 -2
- package/src/codegen/bin/cli.ts +181 -144
- package/src/codegen/bin/flag-specs.test.ts +16 -1
- package/src/codegen/bin/flag-specs.ts +43 -31
- package/src/codegen/bundle-size.test.ts +1 -1
- package/src/codegen/collect-models.ts +1 -1
- package/src/codegen/e2e.test.ts +1 -1
- package/src/codegen/emit/api-route.ts +184 -0
- package/src/codegen/emit/context.ts +32 -0
- package/src/codegen/emit/declarations.ts +49 -0
- package/src/codegen/emit/format-types.ts +232 -0
- package/src/codegen/emit/http-stream-route.ts +162 -0
- package/src/codegen/emit/route-shared.ts +102 -0
- package/src/codegen/emit/rpc-route.ts +49 -0
- package/src/codegen/emit/scope-file.ts +226 -0
- package/src/codegen/emit/stream-route.ts +81 -0
- package/src/codegen/emit-errors.integration.test.ts +2 -2
- package/src/codegen/emit-errors.test.ts +1 -1
- package/src/codegen/emit-errors.ts +1 -1
- package/src/codegen/emit-index.test.ts +34 -0
- package/src/codegen/emit-index.ts +19 -0
- package/src/codegen/emit-scope.test.ts +96 -6
- package/src/codegen/emit-scope.ts +15 -1003
- package/src/codegen/goldens.test.ts +89 -0
- package/src/codegen/group-routes.test.ts +1 -1
- package/src/codegen/group-routes.ts +1 -1
- package/src/codegen/pipeline.test.ts +1 -1
- package/src/codegen/pipeline.ts +1 -1
- package/src/codegen/resolve-envelope.test.ts +1 -1
- package/src/codegen/resolve-envelope.ts +1 -1
- package/src/codegen/targets/_shared/error-schemas.test.ts +1 -1
- package/src/codegen/targets/_shared/error-schemas.ts +1 -1
- package/src/codegen/targets/_shared/route-slots.test.ts +1 -1
- package/src/codegen/targets/_shared/route-slots.ts +1 -1
- package/src/codegen/targets/_shared/target-run.ts +1 -1
- package/src/codegen/targets/kotlin/__fixtures__/users-golden.kt +6 -0
- package/src/codegen/targets/kotlin/emit-route-kotlin.test.ts +1 -1
- package/src/codegen/targets/kotlin/emit-route-kotlin.ts +1 -1
- package/src/codegen/targets/kotlin/emit-scope-kotlin.test.ts +1 -1
- package/src/codegen/targets/swift/__fixtures__/users-golden.swift +6 -0
- package/src/codegen/targets/swift/access-level.test.ts +1 -1
- package/src/codegen/targets/swift/emit-route-swift.test.ts +1 -1
- package/src/codegen/targets/swift/emit-route-swift.ts +1 -1
- package/src/codegen/targets/swift/emit-scope-swift.test.ts +1 -1
- package/src/codegen/targets/ts/shared-models.test.ts +1 -1
- package/src/{create-http-stream.test.ts → core/create-http-stream.test.ts} +1 -1
- package/src/core/create-http-stream.ts +207 -0
- package/src/{create-http.test.ts → core/create-http.test.ts} +15 -4
- package/src/core/create-http.ts +126 -0
- package/src/{create-stream.test.ts → core/create-stream.test.ts} +28 -31
- package/src/core/create-stream.ts +142 -0
- package/src/{create.test.ts → core/create.test.ts} +25 -57
- package/src/core/create.ts +121 -0
- package/src/{stack-utils.test.ts → core/definition-site.test.ts} +14 -3
- package/src/{stack-utils.ts → core/definition-site.ts} +20 -23
- package/src/{errors.test.ts → core/errors.test.ts} +1 -1
- package/src/{errors.ts → core/errors.ts} +30 -28
- package/src/core/factory-options.test.ts +112 -0
- package/src/core/http-route.ts +73 -0
- package/src/core/internal.ts +203 -0
- package/src/{migration.test.ts → core/migration.test.ts} +23 -1
- package/src/{index.test.ts → core/procedures.test.ts} +13 -11
- package/src/core/procedures.ts +75 -0
- package/src/core/types.ts +195 -0
- package/src/exports.ts +60 -11
- package/src/schema/adapter.test.ts +58 -0
- package/src/schema/adapter.ts +45 -0
- package/src/schema/compile.test.ts +95 -0
- package/src/schema/compile.ts +64 -0
- package/src/schema/compute-schema.test.ts +222 -41
- package/src/schema/compute-schema.ts +145 -71
- package/src/schema/json-schema.ts +21 -0
- package/src/schema/typebox.test.ts +40 -0
- package/src/schema/typebox.ts +27 -0
- package/src/server/context.test.ts +22 -0
- package/src/server/context.ts +18 -0
- package/src/{doc-envelope.test.ts → server/doc-envelope.test.ts} +2 -2
- package/src/{doc-envelope.ts → server/doc-envelope.ts} +1 -1
- package/src/{implementations/http → server}/doc-registry.test.ts +32 -26
- package/src/{implementations/http → server}/doc-registry.ts +11 -7
- package/src/server/docs/docs.test.ts +287 -0
- package/src/{implementations/http/hono → server}/docs/http-doc.ts +3 -3
- package/src/{implementations/http/hono → server}/docs/http-stream-doc.ts +3 -3
- package/src/{implementations/http/hono → server}/docs/rpc-doc.ts +3 -3
- package/src/{implementations/http/hono → server}/docs/stream-doc.ts +3 -3
- package/src/server/errors/dispatch.test.ts +450 -0
- package/src/server/errors/dispatch.ts +189 -0
- package/src/{implementations/http/error-taxonomy.test.ts → server/errors/taxonomy.test.ts} +45 -39
- package/src/{implementations/http/error-taxonomy.ts → server/errors/taxonomy.ts} +8 -17
- package/src/server/index.ts +29 -0
- package/src/server/no-framework-imports.test.ts +43 -0
- package/src/server/paths.test.ts +141 -0
- package/src/{implementations/http/hono/path.ts → server/paths.ts} +2 -13
- package/src/server/request/params.test.ts +143 -0
- package/src/server/request/params.ts +68 -0
- package/src/server/request/query.test.ts +70 -0
- package/src/server/request/query.ts +24 -0
- package/src/server/sse.test.ts +113 -0
- package/src/server/sse.ts +117 -0
- package/src/{implementations → server}/types.ts +17 -16
- package/build/create-http-stream.d.ts +0 -58
- package/build/create-http-stream.js +0 -122
- package/build/create-http-stream.js.map +0 -1
- package/build/create-http-stream.test.js.map +0 -1
- package/build/create-http.d.ts +0 -49
- package/build/create-http.js +0 -108
- package/build/create-http.js.map +0 -1
- package/build/create-http.test.js.map +0 -1
- package/build/create-stream.d.ts +0 -35
- package/build/create-stream.js +0 -123
- package/build/create-stream.js.map +0 -1
- package/build/create-stream.test.js.map +0 -1
- package/build/create.d.ts +0 -28
- package/build/create.js +0 -82
- package/build/create.js.map +0 -1
- package/build/create.test.js.map +0 -1
- package/build/doc-envelope.js.map +0 -1
- package/build/doc-envelope.test.js.map +0 -1
- package/build/errors.js.map +0 -1
- package/build/errors.test.js.map +0 -1
- package/build/implementations/http/astro/astro-context.js.map +0 -1
- package/build/implementations/http/astro/create-handler.js.map +0 -1
- package/build/implementations/http/astro/index.js.map +0 -1
- package/build/implementations/http/astro/index.test.js.map +0 -1
- package/build/implementations/http/astro/rewrite-request.js.map +0 -1
- package/build/implementations/http/doc-registry.js.map +0 -1
- package/build/implementations/http/doc-registry.test.js.map +0 -1
- package/build/implementations/http/error-dispatch.d.ts +0 -76
- package/build/implementations/http/error-dispatch.js.map +0 -1
- package/build/implementations/http/error-dispatch.test.js +0 -254
- package/build/implementations/http/error-dispatch.test.js.map +0 -1
- package/build/implementations/http/error-taxonomy.js.map +0 -1
- package/build/implementations/http/error-taxonomy.test.js.map +0 -1
- package/build/implementations/http/hono/docs/http-doc.js.map +0 -1
- package/build/implementations/http/hono/docs/http-stream-doc.js.map +0 -1
- package/build/implementations/http/hono/docs/rpc-doc.js.map +0 -1
- package/build/implementations/http/hono/docs/stream-doc.js.map +0 -1
- package/build/implementations/http/hono/handlers/http-stream.js +0 -123
- package/build/implementations/http/hono/handlers/http-stream.js.map +0 -1
- package/build/implementations/http/hono/handlers/http-stream.test.js.map +0 -1
- package/build/implementations/http/hono/handlers/http.js +0 -110
- package/build/implementations/http/hono/handlers/http.js.map +0 -1
- package/build/implementations/http/hono/handlers/http.test.js.map +0 -1
- package/build/implementations/http/hono/handlers/rpc.js +0 -32
- package/build/implementations/http/hono/handlers/rpc.js.map +0 -1
- package/build/implementations/http/hono/handlers/rpc.test.js.map +0 -1
- package/build/implementations/http/hono/handlers/stream.d.ts +0 -23
- package/build/implementations/http/hono/handlers/stream.js +0 -147
- package/build/implementations/http/hono/handlers/stream.js.map +0 -1
- package/build/implementations/http/hono/handlers/stream.test.js.map +0 -1
- package/build/implementations/http/hono/index.js.map +0 -1
- package/build/implementations/http/hono/index.test.js.map +0 -1
- package/build/implementations/http/hono/path.js.map +0 -1
- package/build/implementations/http/hono/path.test.js +0 -83
- package/build/implementations/http/hono/path.test.js.map +0 -1
- package/build/implementations/http/hono/types.d.ts +0 -51
- package/build/implementations/http/hono/types.js.map +0 -1
- package/build/implementations/http/on-request-error.test.js.map +0 -1
- package/build/implementations/http/route-errors.test.js.map +0 -1
- package/build/index.d.ts +0 -175
- package/build/index.js +0 -47
- package/build/index.js.map +0 -1
- package/build/index.test.js.map +0 -1
- package/build/migration.test.js.map +0 -1
- package/build/schema/extract-json-schema.d.ts +0 -2
- package/build/schema/extract-json-schema.js +0 -12
- package/build/schema/extract-json-schema.js.map +0 -1
- package/build/schema/extract-json-schema.test.js +0 -23
- package/build/schema/extract-json-schema.test.js.map +0 -1
- package/build/schema/parser.d.ts +0 -36
- package/build/schema/parser.js +0 -210
- package/build/schema/parser.js.map +0 -1
- package/build/schema/parser.test.js +0 -120
- package/build/schema/parser.test.js.map +0 -1
- package/build/schema/resolve-schema-lib.d.ts +0 -12
- package/build/schema/resolve-schema-lib.js +0 -11
- package/build/schema/resolve-schema-lib.js.map +0 -1
- package/build/schema/resolve-schema-lib.test.js +0 -17
- package/build/schema/resolve-schema-lib.test.js.map +0 -1
- package/build/schema/types.d.ts +0 -8
- package/build/schema/types.js +0 -2
- package/build/stack-utils.d.ts +0 -25
- package/build/stack-utils.js.map +0 -1
- package/build/stack-utils.test.js.map +0 -1
- package/build/types.d.ts +0 -142
- package/build/types.js +0 -2
- package/build/types.js.map +0 -1
- package/docs/decisions/2026-06-02-monorepo-split-evaluation.md +0 -80
- package/docs/handoffs/ajsc-named-type-collision.md +0 -134
- package/docs/handoffs/ajsc-named-type-support.md +0 -181
- package/docs/handoffs/shared-models-auto-resolve-response.md +0 -181
- package/docs/npm-workspaces-migration-plan.md +0 -611
- package/docs/superpowers/plans/2026-04-24-doc-registry-simplification.md +0 -886
- package/docs/superpowers/plans/2026-04-24-kotlin-codegen-target.md +0 -1265
- package/docs/superpowers/plans/2026-04-25-ajsc-v7-kotlin-polish.md +0 -1993
- package/docs/superpowers/plans/2026-04-29-safe-result-api.md +0 -2293
- package/docs/superpowers/plans/2026-05-07-astro-adapter.md +0 -1391
- package/docs/superpowers/plans/2026-05-08-create-http.md +0 -3355
- package/docs/superpowers/plans/2026-05-08-hono-app-builder-convergence.md +0 -3365
- package/docs/superpowers/plans/2026-06-05-dx-feedback-round.md +0 -1292
- package/docs/superpowers/plans/2026-06-06-shared-models-convention-and-diagnostics.md +0 -659
- package/docs/superpowers/specs/2026-04-24-kotlin-swift-codegen-design.md +0 -401
- package/docs/superpowers/specs/2026-04-25-ajsc-v7-kotlin-polish-design.md +0 -314
- package/docs/superpowers/specs/2026-04-25-swift-codegen-design.md +0 -264
- package/docs/superpowers/specs/2026-04-29-safe-result-api-design.md +0 -324
- package/docs/superpowers/specs/2026-05-07-astro-adapter-design.md +0 -252
- package/docs/superpowers/specs/2026-05-08-create-http-design.md +0 -409
- package/docs/superpowers/specs/2026-05-08-hono-app-builder-convergence-design.md +0 -411
- package/docs/superpowers/specs/2026-06-05-dx-feedback-round-design.md +0 -285
- package/src/create-http-stream.ts +0 -191
- package/src/create-http.ts +0 -210
- package/src/create-stream.ts +0 -228
- package/src/create.ts +0 -172
- package/src/implementations/http/README.md +0 -390
- package/src/implementations/http/error-dispatch.test.ts +0 -283
- package/src/implementations/http/error-dispatch.ts +0 -176
- package/src/implementations/http/hono/handlers/http-stream.ts +0 -152
- package/src/implementations/http/hono/handlers/http.ts +0 -145
- package/src/implementations/http/hono/handlers/rpc.ts +0 -54
- package/src/implementations/http/hono/path.test.ts +0 -96
- package/src/index.ts +0 -101
- package/src/schema/extract-json-schema.test.ts +0 -25
- package/src/schema/extract-json-schema.ts +0 -15
- package/src/schema/parser.test.ts +0 -182
- package/src/schema/parser.ts +0 -265
- package/src/schema/resolve-schema-lib.test.ts +0 -19
- package/src/schema/resolve-schema-lib.ts +0 -29
- package/src/schema/types.ts +0 -20
- package/src/types.ts +0 -133
- /package/build/{implementations/http → adapters}/astro/astro-context.d.ts +0 -0
- /package/build/{implementations/http → adapters}/astro/astro-context.js +0 -0
- /package/build/{implementations/http → adapters}/astro/create-handler.d.ts +0 -0
- /package/build/{implementations/http → adapters}/astro/create-handler.js +0 -0
- /package/build/{implementations/http → adapters}/astro/index.d.ts +0 -0
- /package/build/{implementations/http → adapters}/astro/index.js +0 -0
- /package/build/{implementations/http → adapters}/astro/index.test.d.ts +0 -0
- /package/build/{implementations/http → adapters}/astro/rewrite-request.d.ts +0 -0
- /package/build/{implementations/http → adapters}/astro/rewrite-request.js +0 -0
- /package/build/{create-http-stream.test.d.ts → adapters/hono/envelope-parity.test.d.ts} +0 -0
- /package/build/{implementations/http → adapters}/hono/handlers/http-stream.test.d.ts +0 -0
- /package/build/{implementations/http → adapters}/hono/handlers/http.test.d.ts +0 -0
- /package/build/{implementations/http → adapters}/hono/handlers/rpc.test.d.ts +0 -0
- /package/build/{implementations/http → adapters}/hono/handlers/stream.test.d.ts +0 -0
- /package/build/{implementations/http → adapters}/hono/index.test.d.ts +0 -0
- /package/build/{implementations/http → adapters/hono}/on-request-error.test.d.ts +0 -0
- /package/build/{implementations/http → adapters/hono}/route-errors.test.d.ts +0 -0
- /package/build/{create-http.test.d.ts → client/freeze.test.d.ts} +0 -0
- /package/build/{create-stream.test.d.ts → codegen/goldens.test.d.ts} +0 -0
- /package/build/{create.test.d.ts → core/create-http-stream.test.d.ts} +0 -0
- /package/build/{doc-envelope.test.d.ts → core/create-http.test.d.ts} +0 -0
- /package/build/{errors.test.d.ts → core/create-stream.test.d.ts} +0 -0
- /package/build/{implementations/http/doc-registry.test.d.ts → core/create.test.d.ts} +0 -0
- /package/build/{implementations/http/error-dispatch.test.d.ts → core/definition-site.test.d.ts} +0 -0
- /package/build/{implementations/http/error-taxonomy.test.d.ts → core/errors.test.d.ts} +0 -0
- /package/build/{errors.test.js → core/errors.test.js} +0 -0
- /package/build/{implementations/http/hono/path.test.d.ts → core/factory-options.test.d.ts} +0 -0
- /package/build/{migration.test.d.ts → core/migration.test.d.ts} +0 -0
- /package/build/{index.test.d.ts → core/procedures.test.d.ts} +0 -0
- /package/build/{implementations/http/hono → core}/types.js +0 -0
- /package/build/schema/{extract-json-schema.test.d.ts → adapter.test.d.ts} +0 -0
- /package/build/schema/{parser.test.d.ts → compile.test.d.ts} +0 -0
- /package/build/schema/{resolve-schema-lib.test.d.ts → typebox.test.d.ts} +0 -0
- /package/build/{stack-utils.test.d.ts → server/context.test.d.ts} +0 -0
- /package/build/{doc-envelope.js → server/doc-envelope.js} +0 -0
- /package/build/{doc-envelope.test.js → server/doc-envelope.test.js} +0 -0
- /package/build/{implementations → server}/types.js +0 -0
- /package/src/{implementations/http → adapters}/astro/README.md +0 -0
- /package/src/{implementations/http → adapters}/astro/astro-context.ts +0 -0
- /package/src/{implementations/http → adapters}/astro/create-handler.ts +0 -0
- /package/src/{implementations/http → adapters}/astro/index.ts +0 -0
- /package/src/{implementations/http → adapters}/astro/rewrite-request.ts +0 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emitter for `kind: 'http-stream'` routes — structured multi-channel `Req`
|
|
3
|
+
* types plus `Yield` / `ReturnType` and a `client.stream(...)` callable.
|
|
4
|
+
*/
|
|
5
|
+
import type { HttpStreamRouteDoc } from '../../server/types.js'
|
|
6
|
+
import { renameExtractedTypes } from '../emit-types.js'
|
|
7
|
+
import { toPascalCase } from '../naming.js'
|
|
8
|
+
import type { EmitRouteContext, RouteChunks } from './context.js'
|
|
9
|
+
import { DeclarationCollector } from './declarations.js'
|
|
10
|
+
import { convertBody, convertExtracted, formatSubNamespace, type NamedType } from './format-types.js'
|
|
11
|
+
import { buildCallableJsDoc, buildErrorUnion, injectRouteErrors } from './route-shared.js'
|
|
12
|
+
|
|
13
|
+
export async function emitHttpStreamRoute(route: HttpStreamRouteDoc, ctx: EmitRouteContext): Promise<RouteChunks> {
|
|
14
|
+
const pascal = toPascalCase(route.name)
|
|
15
|
+
const req = route.jsonSchema.req ?? {}
|
|
16
|
+
const res = route.jsonSchema.res ?? {}
|
|
17
|
+
|
|
18
|
+
// Request channels
|
|
19
|
+
const reqChannelKeys = ['pathParams', 'query', 'body', 'headers'] as const
|
|
20
|
+
const reqTypes: NamedType[] = []
|
|
21
|
+
const presentChannels: string[] = []
|
|
22
|
+
|
|
23
|
+
for (const channel of reqChannelKeys) {
|
|
24
|
+
const schema = req[channel]
|
|
25
|
+
if (schema != null) {
|
|
26
|
+
reqTypes.push({ shortName: toPascalCase(channel), schema })
|
|
27
|
+
presentChannels.push(channel)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Yield + ReturnType
|
|
32
|
+
const yieldSchema = route.jsonSchema.yield
|
|
33
|
+
const returnSchema = route.jsonSchema.returnType
|
|
34
|
+
const resHeadersSchema = res.headers
|
|
35
|
+
|
|
36
|
+
const scopeStr = route.scope ?? 'default'
|
|
37
|
+
const declarations: string[] = []
|
|
38
|
+
let paramsTypeName = 'void'
|
|
39
|
+
let yieldTypeName = 'unknown'
|
|
40
|
+
let returnTypeName = 'void'
|
|
41
|
+
|
|
42
|
+
const taken = new Set<string>(['Req', 'Response', 'Yield', 'ReturnType'])
|
|
43
|
+
|
|
44
|
+
if (ctx.namespaceTypes) {
|
|
45
|
+
const nsLines: string[] = []
|
|
46
|
+
|
|
47
|
+
// Req sub-namespace
|
|
48
|
+
const { nsBlock: reqBlock, refs: reqRefs } = await formatSubNamespace(
|
|
49
|
+
pascal, 'Req', reqTypes, ctx, taken
|
|
50
|
+
)
|
|
51
|
+
if (reqBlock) {
|
|
52
|
+
nsLines.push(reqBlock)
|
|
53
|
+
// Merged type alias so Req can be used as a generic type arg (same pattern as emitApiRoute)
|
|
54
|
+
const reqFields = presentChannels
|
|
55
|
+
.map((ch) => `${ch}: Req.${toPascalCase(ch)}`)
|
|
56
|
+
.join('; ')
|
|
57
|
+
nsLines.push(` export type Req = { ${reqFields} }`)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Response sub-namespace (headers only for http-stream)
|
|
61
|
+
const resTypes: NamedType[] = [{ shortName: 'Headers', schema: resHeadersSchema }]
|
|
62
|
+
const { nsBlock: resBlock } = await formatSubNamespace(
|
|
63
|
+
pascal, 'Response', resTypes, ctx, taken
|
|
64
|
+
)
|
|
65
|
+
if (resBlock) nsLines.push(resBlock)
|
|
66
|
+
|
|
67
|
+
// Yield and ReturnType directly in the route namespace
|
|
68
|
+
const directTypes: NamedType[] = [
|
|
69
|
+
{ shortName: 'Yield', schema: yieldSchema },
|
|
70
|
+
{ shortName: 'ReturnType', schema: returnSchema },
|
|
71
|
+
]
|
|
72
|
+
const collector = new DeclarationCollector(`namespace ${pascal}`)
|
|
73
|
+
for (const { shortName, schema } of directTypes) {
|
|
74
|
+
if (schema == null) continue
|
|
75
|
+
const rawResult = await convertExtracted(schema, ctx)
|
|
76
|
+
if (rawResult == null) continue
|
|
77
|
+
const result = renameExtractedTypes(rawResult, taken)
|
|
78
|
+
for (const decl of result.declarations) {
|
|
79
|
+
const line = collector.accept(decl, ' ')
|
|
80
|
+
if (line != null) nsLines.push(line)
|
|
81
|
+
}
|
|
82
|
+
nsLines.push(` export type ${shortName} = ${result.body}`)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (nsLines.length > 0) {
|
|
86
|
+
declarations.push(` export namespace ${pascal} {\n${nsLines.join('\n')}\n }`)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (presentChannels.length > 0) {
|
|
90
|
+
paramsTypeName = `${ctx.scopePascal}.${pascal}.Req`
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (yieldSchema != null) yieldTypeName = `${ctx.scopePascal}.${pascal}.Yield`
|
|
94
|
+
if (returnSchema != null) returnTypeName = `${ctx.scopePascal}.${pascal}.ReturnType`
|
|
95
|
+
} else {
|
|
96
|
+
// Flat mode
|
|
97
|
+
for (const { shortName, schema } of reqTypes) {
|
|
98
|
+
if (schema == null) continue
|
|
99
|
+
const flatName = `${pascal}Req${shortName}`
|
|
100
|
+
const body = await convertBody(schema, ctx)
|
|
101
|
+
if (body == null) continue
|
|
102
|
+
declarations.push(`export type ${flatName} = ${body}`)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (presentChannels.length > 0) {
|
|
106
|
+
const structureFields = presentChannels
|
|
107
|
+
.map((ch) => `${ch}: ${pascal}Req${toPascalCase(ch)}`)
|
|
108
|
+
.join('; ')
|
|
109
|
+
declarations.push(`export type ${pascal}Req = { ${structureFields} }`)
|
|
110
|
+
paramsTypeName = `${pascal}Req`
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (resHeadersSchema != null) {
|
|
114
|
+
const body = await convertBody(resHeadersSchema, ctx)
|
|
115
|
+
if (body != null) declarations.push(`export type ${pascal}ResponseHeaders = ${body}`)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (yieldSchema != null) {
|
|
119
|
+
const body = await convertBody(yieldSchema, ctx)
|
|
120
|
+
if (body != null) {
|
|
121
|
+
declarations.push(`export type ${pascal}Yield = ${body}`)
|
|
122
|
+
yieldTypeName = `${pascal}Yield`
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (returnSchema != null) {
|
|
127
|
+
const body = await convertBody(returnSchema, ctx)
|
|
128
|
+
if (body != null) {
|
|
129
|
+
declarations.push(`export type ${pascal}ReturnType = ${body}`)
|
|
130
|
+
returnTypeName = `${pascal}ReturnType`
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const callable = [
|
|
136
|
+
buildCallableJsDoc({
|
|
137
|
+
methodLabel: route.method.toUpperCase(),
|
|
138
|
+
path: route.fullPath,
|
|
139
|
+
errorsRef: null,
|
|
140
|
+
}),
|
|
141
|
+
` ${route.name}(req: ${paramsTypeName}, options?: ProcedureCallOptions): TypedStream<${yieldTypeName}, ${returnTypeName}> {`,
|
|
142
|
+
` return client.stream<${yieldTypeName}, ${returnTypeName}>({`,
|
|
143
|
+
` name: '${route.name}',`,
|
|
144
|
+
` scope: '${scopeStr}',`,
|
|
145
|
+
` path: '${route.fullPath}',`,
|
|
146
|
+
` method: '${route.method}',`,
|
|
147
|
+
` kind: 'http-stream',`,
|
|
148
|
+
` streamMode: '${route.streamMode}',`,
|
|
149
|
+
` params: req,`,
|
|
150
|
+
` }, options)`,
|
|
151
|
+
` },`,
|
|
152
|
+
].join('\n')
|
|
153
|
+
|
|
154
|
+
const hasErrors = injectRouteErrors(
|
|
155
|
+
declarations,
|
|
156
|
+
pascal,
|
|
157
|
+
buildErrorUnion(route.errors, ctx),
|
|
158
|
+
ctx.namespaceTypes
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
return { typeDeclarations: declarations, callable, hasStream: true, hasErrors }
|
|
162
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers shared across the per-kind route emitters: versioned route naming,
|
|
3
|
+
* the route-level `Errors` union builder/injector, and the callable JSDoc
|
|
4
|
+
* builder.
|
|
5
|
+
*/
|
|
6
|
+
import { toPascalCase } from '../naming.js'
|
|
7
|
+
import type { EmitRouteContext } from './context.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Returns the PascalCase display name for a route, appending `V{version}`
|
|
11
|
+
* when version > 1. Version 1 produces no suffix for backward compatibility.
|
|
12
|
+
*/
|
|
13
|
+
export function versionedPascal(name: string, version: number | undefined): string {
|
|
14
|
+
const pascal = toPascalCase(name)
|
|
15
|
+
if (version != null && version > 1) return `${pascal}V${version}`
|
|
16
|
+
return pascal
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Route-level Errors union injection
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Builds the body of an `Errors` type union from the route's declared error
|
|
25
|
+
* keys. Filters to keys actually emitted in `_errors.ts` so generated code
|
|
26
|
+
* never references undefined types.
|
|
27
|
+
*
|
|
28
|
+
* In namespace mode the union uses qualified names (`ApiErrors.UseCaseError`);
|
|
29
|
+
* in flat mode it uses the bundled wildcard import alias (`_errors.UseCaseError`).
|
|
30
|
+
* Returns `null` when no keys remain.
|
|
31
|
+
*/
|
|
32
|
+
export function buildErrorUnion(
|
|
33
|
+
routeErrors: string[] | undefined,
|
|
34
|
+
ctx: EmitRouteContext
|
|
35
|
+
): string | null {
|
|
36
|
+
if (!routeErrors || routeErrors.length === 0) return null
|
|
37
|
+
const available = ctx.errorKeys
|
|
38
|
+
const filtered = available ? routeErrors.filter((k) => available.has(k)) : routeErrors
|
|
39
|
+
if (filtered.length === 0) return null
|
|
40
|
+
const qualify = ctx.namespaceTypes
|
|
41
|
+
? (k: string) => `${toPascalCase(ctx.serviceName)}Errors.${k}`
|
|
42
|
+
: (k: string) => `_errors.${k}`
|
|
43
|
+
return filtered.map(qualify).join(' | ')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Injects `export type Errors = ...` into an existing route namespace block
|
|
48
|
+
* (namespace mode) or appends a flat `export type ${pascal}Errors = ...` in
|
|
49
|
+
* flat mode. Mutates the `declarations` array in place and returns whether an
|
|
50
|
+
* injection happened.
|
|
51
|
+
*/
|
|
52
|
+
export function injectRouteErrors(
|
|
53
|
+
declarations: string[],
|
|
54
|
+
routePascal: string,
|
|
55
|
+
errorUnion: string | null,
|
|
56
|
+
namespaceTypes: boolean
|
|
57
|
+
): boolean {
|
|
58
|
+
if (!errorUnion) return false
|
|
59
|
+
if (namespaceTypes) {
|
|
60
|
+
const lastIdx = declarations.length - 1
|
|
61
|
+
if (lastIdx < 0) return false
|
|
62
|
+
const lastDecl = declarations[lastIdx]!
|
|
63
|
+
const closingIdx = lastDecl.lastIndexOf(' }')
|
|
64
|
+
if (closingIdx === -1) return false
|
|
65
|
+
declarations[lastIdx] =
|
|
66
|
+
lastDecl.slice(0, closingIdx) +
|
|
67
|
+
` export type Errors = ${errorUnion}\n` +
|
|
68
|
+
lastDecl.slice(closingIdx)
|
|
69
|
+
return true
|
|
70
|
+
}
|
|
71
|
+
declarations.push(`export type ${routePascal}Errors = ${errorUnion}`)
|
|
72
|
+
return true
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Builds the multi-line JSDoc comment for a route callable. Surfaces the
|
|
77
|
+
* second `options` argument (the per-call AbortSignal/timeout seam — DX #8) and,
|
|
78
|
+
* for routes that declare typed errors, points at the route's `Errors` type and
|
|
79
|
+
* how to narrow it on the throwing path (DX #10). Indented for placement inside
|
|
80
|
+
* the bind-object (4 spaces).
|
|
81
|
+
*/
|
|
82
|
+
export function buildCallableJsDoc(opts: {
|
|
83
|
+
methodLabel: string
|
|
84
|
+
path: string
|
|
85
|
+
errorsRef: string | null
|
|
86
|
+
}): string {
|
|
87
|
+
const lines = [
|
|
88
|
+
` /**`,
|
|
89
|
+
` * ${opts.methodLabel} ${opts.path}`,
|
|
90
|
+
` *`,
|
|
91
|
+
` * @param options Optional per-call {@link ProcedureCallOptions} —`,
|
|
92
|
+
` * \`signal\` (cancel on dispose), \`timeout\`, \`headers\`, \`basePath\`.`,
|
|
93
|
+
]
|
|
94
|
+
if (opts.errorsRef) {
|
|
95
|
+
lines.push(
|
|
96
|
+
` * @throws Declared typed errors: {@link ${opts.errorsRef}}. Narrow with`,
|
|
97
|
+
` * \`instanceof\` on the throwing path, or call \`.safe()\` for a \`Result\`.`,
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
lines.push(` */`)
|
|
101
|
+
return lines.join('\n')
|
|
102
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emitter for `kind: 'rpc'` routes — bindCallable / bindCallableTyped
|
|
3
|
+
* callables with `Params` / `Response` (and optional `Errors`) types.
|
|
4
|
+
*/
|
|
5
|
+
import type { RPCHttpRouteDoc } from '../../server/types.js'
|
|
6
|
+
import type { EmitRouteContext, RouteChunks } from './context.js'
|
|
7
|
+
import { formatTypes } from './format-types.js'
|
|
8
|
+
import { buildCallableJsDoc, buildErrorUnion, injectRouteErrors, versionedPascal } from './route-shared.js'
|
|
9
|
+
|
|
10
|
+
export async function emitRpcRoute(route: RPCHttpRouteDoc, ctx: EmitRouteContext): Promise<RouteChunks> {
|
|
11
|
+
const pascal = versionedPascal(route.name, route.version)
|
|
12
|
+
|
|
13
|
+
const { declarations, refs } = await formatTypes(pascal, [
|
|
14
|
+
{ shortName: 'Params', schema: route.jsonSchema.body },
|
|
15
|
+
{ shortName: 'Response', schema: route.jsonSchema.response },
|
|
16
|
+
], ctx)
|
|
17
|
+
|
|
18
|
+
const paramsTypeName = refs['Params'] ?? 'void'
|
|
19
|
+
const responseTypeName = refs['Response'] ?? 'unknown'
|
|
20
|
+
const scopeStr = Array.isArray(route.scope) ? route.scope.join('-') : route.scope
|
|
21
|
+
|
|
22
|
+
const errorUnion = buildErrorUnion(route.errors, ctx)
|
|
23
|
+
const hasErrors = errorUnion !== null
|
|
24
|
+
const errorsRef = ctx.namespaceTypes
|
|
25
|
+
? `${ctx.scopePascal}.${pascal}.Errors`
|
|
26
|
+
: `${pascal}Errors`
|
|
27
|
+
const helperCall = hasErrors
|
|
28
|
+
? `client.bindCallableTyped<${paramsTypeName}, ${responseTypeName}, ${errorsRef}>`
|
|
29
|
+
: `client.bindCallable<${paramsTypeName}, ${responseTypeName}>`
|
|
30
|
+
|
|
31
|
+
const callable = [
|
|
32
|
+
buildCallableJsDoc({
|
|
33
|
+
methodLabel: route.method.toUpperCase(),
|
|
34
|
+
path: route.path,
|
|
35
|
+
errorsRef: hasErrors ? errorsRef : null,
|
|
36
|
+
}),
|
|
37
|
+
` ${pascal}: ${helperCall}({`,
|
|
38
|
+
` name: '${pascal}',`,
|
|
39
|
+
` scope: '${scopeStr}',`,
|
|
40
|
+
` path: '${route.path}',`,
|
|
41
|
+
` method: '${route.method}',`,
|
|
42
|
+
` kind: 'rpc',`,
|
|
43
|
+
` }),`,
|
|
44
|
+
].join('\n')
|
|
45
|
+
|
|
46
|
+
const hasErrorsInjected = injectRouteErrors(declarations, pascal, errorUnion, ctx.namespaceTypes)
|
|
47
|
+
|
|
48
|
+
return { typeDeclarations: declarations, callable, hasStream: false, hasErrors: hasErrorsInjected }
|
|
49
|
+
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `emitScopeFile` orchestration: dispatches each route to its per-kind
|
|
3
|
+
* emitter, accumulates type declarations / callables / referenced models,
|
|
4
|
+
* and assembles the final scope file (namespace or flat mode) with its
|
|
5
|
+
* import block.
|
|
6
|
+
*/
|
|
7
|
+
import type { ScopeGroup } from '../group-routes.js'
|
|
8
|
+
import type {
|
|
9
|
+
RPCHttpRouteDoc,
|
|
10
|
+
APIHttpRouteDoc,
|
|
11
|
+
StreamHttpRouteDoc,
|
|
12
|
+
HttpStreamRouteDoc,
|
|
13
|
+
} from '../../server/types.js'
|
|
14
|
+
import type { AjscOptions } from '../emit-types.js'
|
|
15
|
+
import { CODEGEN_HEADER } from '../constants.js'
|
|
16
|
+
import { toPascalCase } from '../naming.js'
|
|
17
|
+
import type { EmitRouteContext, RouteChunks } from './context.js'
|
|
18
|
+
import { indent } from './declarations.js'
|
|
19
|
+
import { emitRpcRoute } from './rpc-route.js'
|
|
20
|
+
import { emitApiRoute } from './api-route.js'
|
|
21
|
+
import { emitStreamRoute } from './stream-route.js'
|
|
22
|
+
import { emitHttpStreamRoute } from './http-stream-route.js'
|
|
23
|
+
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Types
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
export interface EmitScopeOptions {
|
|
29
|
+
ajsc?: AjscOptions
|
|
30
|
+
clientImportPath?: string
|
|
31
|
+
namespaceTypes?: boolean
|
|
32
|
+
/** Service identifier used to namespace generated error types (defaults to 'Api'). */
|
|
33
|
+
serviceName?: string
|
|
34
|
+
/**
|
|
35
|
+
* Error keys present in the generated `_errors.ts`. Routes may list keys
|
|
36
|
+
* that aren't emitted (e.g. no schema); those are filtered out at emit time
|
|
37
|
+
* so generated code never references undefined types.
|
|
38
|
+
*/
|
|
39
|
+
errorKeys?: Set<string>
|
|
40
|
+
/**
|
|
41
|
+
* Maps a model `$id` to its shared model type name (built by the run module
|
|
42
|
+
* from ALL models — generated and imported). When present and non-empty,
|
|
43
|
+
* `$id` subschemas are rewritten to `x-named-type` nodes before ajsc; ajsc
|
|
44
|
+
* emits bare references and reports them via `referencedNamedTypes`, which
|
|
45
|
+
* drives the `import type { … } from './_models'` line. Absent/empty →
|
|
46
|
+
* identical inlining behaviour (the conversion wrappers short-circuit so
|
|
47
|
+
* output is byte-identical for envelopes without models).
|
|
48
|
+
*/
|
|
49
|
+
idToModelName?: Map<string, string>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Helpers
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Infers the route kind when the `kind` discriminant is missing.
|
|
58
|
+
* This provides backward compatibility with servers running older ts-procedures
|
|
59
|
+
* versions that don't set `kind` on route docs.
|
|
60
|
+
*/
|
|
61
|
+
function inferRouteKind(route: Record<string, unknown>): 'rpc' | 'api' | 'stream' | 'http-stream' {
|
|
62
|
+
if ('streamMode' in route && 'fullPath' in route) return 'http-stream'
|
|
63
|
+
if ('streamMode' in route) return 'stream'
|
|
64
|
+
if ('fullPath' in route) return 'api'
|
|
65
|
+
return 'rpc'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// emitScopeFile
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Generates a complete TypeScript scope file for a ScopeGroup.
|
|
74
|
+
*
|
|
75
|
+
* When `namespaceTypes` is true, types are wrapped in nested TypeScript namespaces
|
|
76
|
+
* and ajsc runs with `inlineTypes: false` so formatting options (enumStyle, depluralize,
|
|
77
|
+
* jsdoc, etc.) produce extracted sub-types inside each namespace.
|
|
78
|
+
*/
|
|
79
|
+
export async function emitScopeFile(
|
|
80
|
+
group: ScopeGroup,
|
|
81
|
+
options?: EmitScopeOptions,
|
|
82
|
+
): Promise<string> {
|
|
83
|
+
const {
|
|
84
|
+
ajsc: ajscOpts,
|
|
85
|
+
clientImportPath = 'ts-procedures/client',
|
|
86
|
+
namespaceTypes = false,
|
|
87
|
+
serviceName = 'Api',
|
|
88
|
+
errorKeys,
|
|
89
|
+
idToModelName,
|
|
90
|
+
} = options ?? {}
|
|
91
|
+
|
|
92
|
+
const pascal = toPascalCase(group.camelCase)
|
|
93
|
+
const referencedModels = new Set<string>()
|
|
94
|
+
const ctx: EmitRouteContext = {
|
|
95
|
+
ajsc: ajscOpts,
|
|
96
|
+
namespaceTypes,
|
|
97
|
+
scopePascal: pascal,
|
|
98
|
+
serviceName,
|
|
99
|
+
errorKeys,
|
|
100
|
+
idToModelName,
|
|
101
|
+
referencedModels,
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const allTypeDeclarations: string[] = []
|
|
105
|
+
const callables: string[] = []
|
|
106
|
+
let hasStream = false
|
|
107
|
+
let scopeHasErrors = false
|
|
108
|
+
|
|
109
|
+
for (const route of group.routes) {
|
|
110
|
+
let chunks: RouteChunks
|
|
111
|
+
const kind = route.kind ?? inferRouteKind(route as Record<string, unknown>)
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
if (kind === 'rpc') {
|
|
115
|
+
chunks = await emitRpcRoute(route as RPCHttpRouteDoc, ctx)
|
|
116
|
+
} else if (kind === 'api') {
|
|
117
|
+
chunks = await emitApiRoute(route as APIHttpRouteDoc, ctx)
|
|
118
|
+
} else if (kind === 'stream') {
|
|
119
|
+
chunks = await emitStreamRoute(route as StreamHttpRouteDoc, ctx)
|
|
120
|
+
} else if (kind === 'http-stream') {
|
|
121
|
+
chunks = await emitHttpStreamRoute(route as HttpStreamRouteDoc, ctx)
|
|
122
|
+
} else {
|
|
123
|
+
throw new Error(`Unknown route kind "${kind}"`)
|
|
124
|
+
}
|
|
125
|
+
} catch (err) {
|
|
126
|
+
const msg = err instanceof Error ? err.message : String(err)
|
|
127
|
+
throw new Error(
|
|
128
|
+
`[ts-procedures-codegen] Failed to emit route "${route.name}" (kind: ${kind}, scope: ${group.scopeKey}): ${msg}`
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
allTypeDeclarations.push(...chunks.typeDeclarations)
|
|
133
|
+
callables.push(chunks.callable)
|
|
134
|
+
if (chunks.hasStream) hasStream = true
|
|
135
|
+
if (chunks.hasErrors) scopeHasErrors = true
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Build client import line — Result/ResultNoTyped are no longer referenced
|
|
139
|
+
// directly in scope files; the bindCallable helpers infer them from ClientInstance.
|
|
140
|
+
const clientImports = hasStream
|
|
141
|
+
? `import type { ClientInstance, ProcedureCallOptions, TypedStream } from '${clientImportPath}'`
|
|
142
|
+
: `import type { ClientInstance, ProcedureCallOptions } from '${clientImportPath}'`
|
|
143
|
+
|
|
144
|
+
// Build _errors import line when at least one route emits an Errors union.
|
|
145
|
+
// Namespace mode uses the qualified `${Service}Errors` namespace; flat mode
|
|
146
|
+
// pulls classes in via a wildcard alias (`_errors.UseCaseError`).
|
|
147
|
+
let errorsImport = ''
|
|
148
|
+
if (scopeHasErrors) {
|
|
149
|
+
if (namespaceTypes) {
|
|
150
|
+
errorsImport = `import type { ${toPascalCase(serviceName)}Errors } from './_errors'`
|
|
151
|
+
} else {
|
|
152
|
+
errorsImport = `import type * as _errors from './_errors'`
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const callablesBlock = callables.join('\n\n')
|
|
157
|
+
|
|
158
|
+
// Assemble the type + callable section for this scope. ajsc already emitted
|
|
159
|
+
// bare model references (via `x-named-type`); `convertExtracted` / `convertBody`
|
|
160
|
+
// folded the reported names into `ctx.referencedModels`, which drives the
|
|
161
|
+
// `_models` import below. No post-pass over the body is needed.
|
|
162
|
+
let body: string
|
|
163
|
+
if (namespaceTypes) {
|
|
164
|
+
// Namespace mode: types AND `bindScope` live inside `export namespace ${pascal}`.
|
|
165
|
+
// Putting the function inside the namespace makes the merged symbol
|
|
166
|
+
// value+type, which lets `index.ts` use `export import ${pascal} = …`
|
|
167
|
+
// under `verbatimModuleSyntax: true`. (A type-only namespace would trip
|
|
168
|
+
// TS1269/TS1288.) Consumers call `${Pascal}.bindScope(client)`; the
|
|
169
|
+
// generated `index.ts` factory wires this internally.
|
|
170
|
+
const callableLines = indent(callablesBlock, ' ')
|
|
171
|
+
const namespaceMembers = [
|
|
172
|
+
...(allTypeDeclarations.length > 0 ? [allTypeDeclarations.join('\n\n')] : []),
|
|
173
|
+
[
|
|
174
|
+
' /** Binds every callable in this scope to a configured client. */',
|
|
175
|
+
' export function bindScope(client: ClientInstance) {',
|
|
176
|
+
' return {',
|
|
177
|
+
callableLines,
|
|
178
|
+
' }',
|
|
179
|
+
' }',
|
|
180
|
+
].join('\n'),
|
|
181
|
+
].join('\n\n')
|
|
182
|
+
|
|
183
|
+
body = [
|
|
184
|
+
`export namespace ${pascal} {`,
|
|
185
|
+
namespaceMembers,
|
|
186
|
+
'}',
|
|
187
|
+
'',
|
|
188
|
+
].join('\n')
|
|
189
|
+
} else {
|
|
190
|
+
// Flat mode: types at module level, `bind${pascal}Scope` standalone.
|
|
191
|
+
const typesBlock = allTypeDeclarations.length > 0
|
|
192
|
+
? allTypeDeclarations.join('\n') + '\n'
|
|
193
|
+
: ''
|
|
194
|
+
|
|
195
|
+
body = [
|
|
196
|
+
'// ── Types ────────────────────────────────────────',
|
|
197
|
+
'',
|
|
198
|
+
typesBlock,
|
|
199
|
+
'// ── Callables ────────────────────────────────────',
|
|
200
|
+
'',
|
|
201
|
+
`export function bind${pascal}Scope(client: ClientInstance) {`,
|
|
202
|
+
' return {',
|
|
203
|
+
callablesBlock,
|
|
204
|
+
' }',
|
|
205
|
+
'}',
|
|
206
|
+
'',
|
|
207
|
+
].join('\n')
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Build the shared-models import line when any route referenced a `$id` model.
|
|
211
|
+
// Matches the `_errors` import convention exactly: `'./_models'` with no `.js`.
|
|
212
|
+
let modelsImport = ''
|
|
213
|
+
if (referencedModels.size > 0) {
|
|
214
|
+
const names = [...referencedModels].sort().join(', ')
|
|
215
|
+
modelsImport = `import type { ${names} } from './_models'`
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const importsBlock = [clientImports, errorsImport, modelsImport].filter(Boolean).join('\n')
|
|
219
|
+
|
|
220
|
+
return [
|
|
221
|
+
CODEGEN_HEADER,
|
|
222
|
+
importsBlock,
|
|
223
|
+
'',
|
|
224
|
+
body,
|
|
225
|
+
].join('\n')
|
|
226
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emitter for `kind: 'stream'` routes — SSE envelope unwrapping for the yield
|
|
3
|
+
* type plus a `client.stream(...)` callable.
|
|
4
|
+
*/
|
|
5
|
+
import type { StreamHttpRouteDoc } from '../../server/types.js'
|
|
6
|
+
import type { EmitRouteContext, RouteChunks } from './context.js'
|
|
7
|
+
import { formatTypes } from './format-types.js'
|
|
8
|
+
import { buildCallableJsDoc, buildErrorUnion, injectRouteErrors, versionedPascal } from './route-shared.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Checks whether a JSON schema looks like an SSE envelope.
|
|
12
|
+
* SSE envelopes have properties: data, event, id (and optionally retry).
|
|
13
|
+
*/
|
|
14
|
+
function isSseEnvelope(schema: Record<string, unknown>): boolean {
|
|
15
|
+
const props = schema.properties
|
|
16
|
+
if (props == null || typeof props !== 'object') return false
|
|
17
|
+
const keys = Object.keys(props as Record<string, unknown>)
|
|
18
|
+
return keys.includes('data') && keys.includes('event') && keys.includes('id')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Unwraps an SSE envelope schema to return the inner `data` property schema.
|
|
23
|
+
* If not an SSE envelope, returns the schema unchanged.
|
|
24
|
+
*/
|
|
25
|
+
function unwrapSseEnvelope(
|
|
26
|
+
schema: Record<string, unknown>
|
|
27
|
+
): Record<string, unknown> {
|
|
28
|
+
if (!isSseEnvelope(schema)) return schema
|
|
29
|
+
const props = schema.properties as Record<string, Record<string, unknown>>
|
|
30
|
+
const dataSchema = props['data']
|
|
31
|
+
return dataSchema ?? schema
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function emitStreamRoute(route: StreamHttpRouteDoc, ctx: EmitRouteContext): Promise<RouteChunks> {
|
|
35
|
+
const pascal = versionedPascal(route.name, route.version)
|
|
36
|
+
|
|
37
|
+
// Unwrap SSE envelope from yieldType
|
|
38
|
+
let yieldSchema = route.jsonSchema.yieldType
|
|
39
|
+
if (yieldSchema != null && route.streamMode === 'sse' && isSseEnvelope(yieldSchema)) {
|
|
40
|
+
yieldSchema = unwrapSseEnvelope(yieldSchema)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const { declarations, refs } = await formatTypes(pascal, [
|
|
44
|
+
{ shortName: 'Params', schema: route.jsonSchema.params },
|
|
45
|
+
{ shortName: 'Yield', schema: yieldSchema },
|
|
46
|
+
{ shortName: 'Return', schema: route.jsonSchema.returnType },
|
|
47
|
+
], ctx)
|
|
48
|
+
|
|
49
|
+
const paramsTypeName = refs['Params'] ?? 'void'
|
|
50
|
+
const yieldTypeName = refs['Yield'] ?? 'unknown'
|
|
51
|
+
const returnTypeName = refs['Return'] ?? 'void'
|
|
52
|
+
const scopeStr = Array.isArray(route.scope) ? route.scope.join('-') : route.scope
|
|
53
|
+
|
|
54
|
+
const callable = [
|
|
55
|
+
buildCallableJsDoc({
|
|
56
|
+
methodLabel: route.methods.map((m) => m.toUpperCase()).join('|'),
|
|
57
|
+
path: route.path,
|
|
58
|
+
errorsRef: null,
|
|
59
|
+
}),
|
|
60
|
+
` ${pascal}(params: ${paramsTypeName}, options?: ProcedureCallOptions): TypedStream<${yieldTypeName}, ${returnTypeName}> {`,
|
|
61
|
+
` return client.stream<${yieldTypeName}, ${returnTypeName}>({`,
|
|
62
|
+
` name: '${pascal}',`,
|
|
63
|
+
` scope: '${scopeStr}',`,
|
|
64
|
+
` path: '${route.path}',`,
|
|
65
|
+
` method: '${route.methods[0] ?? 'get'}',`,
|
|
66
|
+
` kind: 'stream',`,
|
|
67
|
+
` streamMode: '${route.streamMode}',`,
|
|
68
|
+
` params,`,
|
|
69
|
+
` }, options)`,
|
|
70
|
+
` },`,
|
|
71
|
+
].join('\n')
|
|
72
|
+
|
|
73
|
+
const hasErrors = injectRouteErrors(
|
|
74
|
+
declarations,
|
|
75
|
+
pascal,
|
|
76
|
+
buildErrorUnion(route.errors, ctx),
|
|
77
|
+
ctx.namespaceTypes
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
return { typeDeclarations: declarations, callable, hasStream: true, hasErrors }
|
|
81
|
+
}
|
|
@@ -14,8 +14,8 @@ import { emitErrorsFile } from './emit-errors.js'
|
|
|
14
14
|
import {
|
|
15
15
|
defineErrorTaxonomy,
|
|
16
16
|
taxonomyToErrorDocs,
|
|
17
|
-
} from '../
|
|
18
|
-
import type { DocEnvelope } from '../
|
|
17
|
+
} from '../server/errors/taxonomy.js'
|
|
18
|
+
import type { DocEnvelope } from '../server/types.js'
|
|
19
19
|
|
|
20
20
|
describe('generated _errors.ts — runtime behavior', () => {
|
|
21
21
|
const envelope: DocEnvelope = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
2
|
import { emitErrorsFile } from './emit-errors.js'
|
|
3
|
-
import type { ErrorDoc } from '../
|
|
3
|
+
import type { ErrorDoc } from '../server/types.js'
|
|
4
4
|
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
6
6
|
// Fixtures
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsonSchemaToTypeBody, type AjscOptions } from './emit-types.js'
|
|
2
|
-
import type { ErrorDoc } from '../
|
|
2
|
+
import type { ErrorDoc } from '../server/types.js'
|
|
3
3
|
import { CODEGEN_HEADER } from './constants.js'
|
|
4
4
|
import { toPascalCase } from './naming.js'
|
|
5
5
|
|