ts-procedures 7.2.0 → 8.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 +65 -3
- package/agent_config/claude-code/agents/ts-procedures-architect.md +6 -8
- package/agent_config/claude-code/skills/ts-procedures/SKILL.md +30 -33
- package/agent_config/claude-code/skills/ts-procedures/anti-patterns.md +139 -53
- package/agent_config/claude-code/skills/ts-procedures/api-reference.md +208 -231
- package/agent_config/claude-code/skills/ts-procedures/patterns.md +80 -153
- package/agent_config/claude-code/skills/ts-procedures-review/SKILL.md +1 -1
- package/agent_config/claude-code/skills/ts-procedures-review/checklist.md +4 -5
- package/agent_config/claude-code/skills/ts-procedures-scaffold/SKILL.md +4 -7
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono.md +223 -0
- package/agent_config/copilot/copilot-instructions.md +36 -48
- package/agent_config/cursor/cursorrules +36 -48
- package/build/client/call.js +4 -1
- package/build/client/call.js.map +1 -1
- package/build/client/call.test.js +23 -0
- package/build/client/call.test.js.map +1 -1
- package/build/client/fetch-adapter.js +3 -1
- package/build/client/fetch-adapter.js.map +1 -1
- package/build/client/fetch-adapter.test.js +11 -1
- package/build/client/fetch-adapter.test.js.map +1 -1
- package/build/client/index.test.js +7 -7
- package/build/client/index.test.js.map +1 -1
- package/build/client/request-builder.d.ts +1 -1
- package/build/client/request-builder.js +2 -2
- package/build/client/request-builder.js.map +1 -1
- package/build/client/stream.js +13 -2
- package/build/client/stream.js.map +1 -1
- package/build/client/stream.test.js +32 -7
- package/build/client/stream.test.js.map +1 -1
- package/build/client/typed-error-dispatch.test.js +8 -92
- package/build/client/typed-error-dispatch.test.js.map +1 -1
- package/build/client/types.d.ts +21 -3
- package/build/codegen/bin/cli.js +0 -0
- package/build/codegen/e2e.test.js +87 -23
- package/build/codegen/e2e.test.js.map +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-scope.js +308 -47
- package/build/codegen/emit-scope.js.map +1 -1
- package/build/codegen/emit-scope.test.js +363 -110
- package/build/codegen/emit-scope.test.js.map +1 -1
- package/build/codegen/pipeline.test.js +7 -7
- package/build/codegen/pipeline.test.js.map +1 -1
- package/build/codegen/resolve-envelope.js +1 -1
- package/build/codegen/resolve-envelope.js.map +1 -1
- package/build/codegen/resolve-envelope.test.js +5 -5
- package/build/codegen/resolve-envelope.test.js.map +1 -1
- package/build/codegen/targets/_shared/route-slots.d.ts +8 -3
- package/build/codegen/targets/_shared/route-slots.js +49 -8
- package/build/codegen/targets/_shared/route-slots.js.map +1 -1
- package/build/codegen/targets/_shared/route-slots.test.js +99 -26
- package/build/codegen/targets/_shared/route-slots.test.js.map +1 -1
- package/build/codegen/targets/kotlin/emit-route-kotlin.test.js +88 -17
- package/build/codegen/targets/kotlin/emit-route-kotlin.test.js.map +1 -1
- package/build/codegen/targets/kotlin/emit-scope-kotlin.test.js +9 -6
- package/build/codegen/targets/kotlin/emit-scope-kotlin.test.js.map +1 -1
- package/build/codegen/targets/kotlin/integration.test.js +6 -0
- package/build/codegen/targets/kotlin/integration.test.js.map +1 -1
- package/build/codegen/targets/swift/access-level.test.js +8 -11
- package/build/codegen/targets/swift/access-level.test.js.map +1 -1
- package/build/codegen/targets/swift/emit-route-swift.test.js +91 -20
- package/build/codegen/targets/swift/emit-route-swift.test.js.map +1 -1
- package/build/codegen/targets/swift/emit-scope-swift.test.js +12 -9
- package/build/codegen/targets/swift/emit-scope-swift.test.js.map +1 -1
- package/build/codegen/targets/swift/integration.test.js +6 -0
- package/build/codegen/targets/swift/integration.test.js.map +1 -1
- package/build/create-http-stream.d.ts +58 -0
- package/build/create-http-stream.js +122 -0
- package/build/create-http-stream.js.map +1 -0
- package/build/create-http-stream.test.js +88 -0
- package/build/create-http-stream.test.js.map +1 -0
- package/build/create-http.d.ts +49 -0
- package/build/create-http.js +108 -0
- package/build/create-http.js.map +1 -0
- package/build/create-http.test.js +137 -0
- package/build/create-http.test.js.map +1 -0
- package/build/create-stream.d.ts +35 -0
- package/build/create-stream.js +123 -0
- package/build/create-stream.js.map +1 -0
- package/build/create-stream.test.js +428 -0
- package/build/create-stream.test.js.map +1 -0
- package/build/create.d.ts +28 -0
- package/build/create.js +82 -0
- package/build/create.js.map +1 -0
- package/build/create.test.js +483 -0
- package/build/create.test.js.map +1 -0
- package/build/exports.d.ts +2 -0
- package/build/implementations/http/astro/index.test.js +20 -12
- package/build/implementations/http/astro/index.test.js.map +1 -1
- package/build/implementations/http/doc-registry.js +1 -1
- package/build/implementations/http/doc-registry.js.map +1 -1
- package/build/implementations/http/doc-registry.test.js +36 -5
- package/build/implementations/http/doc-registry.test.js.map +1 -1
- package/build/implementations/http/error-dispatch.d.ts +76 -0
- package/build/implementations/http/error-dispatch.js +77 -0
- package/build/implementations/http/error-dispatch.js.map +1 -0
- package/build/implementations/http/error-dispatch.test.js +254 -0
- package/build/implementations/http/error-dispatch.test.js.map +1 -0
- package/build/implementations/http/error-taxonomy.d.ts +5 -5
- package/build/implementations/http/hono/docs/http-doc.d.ts +6 -0
- package/build/implementations/http/hono/docs/http-doc.js +42 -0
- package/build/implementations/http/hono/docs/http-doc.js.map +1 -0
- package/build/implementations/http/hono/docs/http-stream-doc.d.ts +6 -0
- package/build/implementations/http/hono/docs/http-stream-doc.js +40 -0
- package/build/implementations/http/hono/docs/http-stream-doc.js.map +1 -0
- package/build/implementations/http/hono/docs/rpc-doc.d.ts +6 -0
- package/build/implementations/http/hono/docs/rpc-doc.js +24 -0
- package/build/implementations/http/hono/docs/rpc-doc.js.map +1 -0
- package/build/implementations/http/hono/docs/stream-doc.d.ts +6 -0
- package/build/implementations/http/hono/docs/stream-doc.js +42 -0
- package/build/implementations/http/hono/docs/stream-doc.js.map +1 -0
- package/build/implementations/http/hono/handlers/http-stream.d.ts +10 -0
- package/build/implementations/http/hono/handlers/http-stream.js +123 -0
- package/build/implementations/http/hono/handlers/http-stream.js.map +1 -0
- package/build/implementations/http/hono/handlers/http-stream.test.js +128 -0
- package/build/implementations/http/hono/handlers/http-stream.test.js.map +1 -0
- package/build/implementations/http/hono/handlers/http.d.ts +10 -0
- package/build/implementations/http/hono/handlers/http.js +115 -0
- package/build/implementations/http/hono/handlers/http.js.map +1 -0
- package/build/implementations/http/hono/handlers/http.test.js +118 -0
- package/build/implementations/http/hono/handlers/http.test.js.map +1 -0
- package/build/implementations/http/hono/handlers/rpc.d.ts +11 -0
- package/build/implementations/http/hono/handlers/rpc.js +32 -0
- package/build/implementations/http/hono/handlers/rpc.js.map +1 -0
- package/build/implementations/http/hono/handlers/rpc.test.js +73 -0
- package/build/implementations/http/hono/handlers/rpc.test.js.map +1 -0
- package/build/implementations/http/hono/handlers/stream.d.ts +23 -0
- package/build/implementations/http/hono/handlers/stream.js +147 -0
- package/build/implementations/http/hono/handlers/stream.js.map +1 -0
- package/build/implementations/http/hono/handlers/stream.test.d.ts +1 -0
- package/build/implementations/http/hono/handlers/stream.test.js +177 -0
- package/build/implementations/http/hono/handlers/stream.test.js.map +1 -0
- package/build/implementations/http/hono/index.d.ts +57 -0
- package/build/implementations/http/hono/index.js +149 -0
- package/build/implementations/http/hono/index.js.map +1 -0
- package/build/implementations/http/hono/index.test.d.ts +1 -0
- package/build/implementations/http/hono/index.test.js +274 -0
- package/build/implementations/http/hono/index.test.js.map +1 -0
- package/build/implementations/http/hono/path.d.ts +17 -0
- package/build/implementations/http/hono/path.js +39 -0
- package/build/implementations/http/hono/path.js.map +1 -0
- package/build/implementations/http/hono/path.test.d.ts +1 -0
- package/build/implementations/http/hono/path.test.js +83 -0
- package/build/implementations/http/hono/path.test.js.map +1 -0
- package/build/implementations/http/hono/types.d.ts +51 -0
- package/build/implementations/http/hono/types.js.map +1 -0
- package/build/implementations/http/on-request-error.test.js +6 -96
- package/build/implementations/http/on-request-error.test.js.map +1 -1
- package/build/implementations/http/route-errors.test.js +11 -59
- package/build/implementations/http/route-errors.test.js.map +1 -1
- package/build/implementations/types.d.ts +43 -9
- package/build/index.d.ts +125 -115
- package/build/index.js +10 -222
- package/build/index.js.map +1 -1
- package/build/index.test.js +30 -822
- package/build/index.test.js.map +1 -1
- package/build/migration.test.d.ts +1 -0
- package/build/migration.test.js +34 -0
- package/build/migration.test.js.map +1 -0
- package/build/schema/compute-schema.d.ts +11 -3
- package/build/schema/compute-schema.js +13 -7
- package/build/schema/compute-schema.js.map +1 -1
- package/build/schema/parser.d.ts +11 -3
- package/build/schema/parser.js +49 -9
- package/build/schema/parser.js.map +1 -1
- package/build/stack-utils.js +8 -0
- package/build/stack-utils.js.map +1 -1
- package/build/types.d.ts +142 -0
- package/build/types.js.map +1 -0
- package/docs/astro-adapter.md +5 -5
- package/docs/core.md +34 -17
- package/docs/http-integrations.md +83 -170
- package/docs/streaming.md +3 -60
- package/docs/superpowers/plans/2026-05-07-astro-adapter.md +2 -7
- package/docs/superpowers/plans/2026-05-08-create-http.md +3355 -0
- package/docs/superpowers/plans/2026-05-08-hono-app-builder-convergence.md +3365 -0
- package/docs/superpowers/specs/2026-05-07-astro-adapter-design.md +1 -3
- package/docs/superpowers/specs/2026-05-08-create-http-design.md +409 -0
- package/docs/superpowers/specs/2026-05-08-hono-app-builder-convergence-design.md +411 -0
- package/package.json +4 -22
- package/src/client/call.test.ts +26 -0
- package/src/client/call.ts +4 -1
- package/src/client/fetch-adapter.test.ts +14 -1
- package/src/client/fetch-adapter.ts +3 -1
- package/src/client/index.test.ts +7 -7
- package/src/client/request-builder.ts +2 -2
- package/src/client/stream.test.ts +39 -7
- package/src/client/stream.ts +16 -2
- package/src/client/typed-error-dispatch.test.ts +7 -97
- package/src/client/types.ts +21 -3
- package/src/codegen/__fixtures__/users-envelope.json +119 -38
- package/src/codegen/e2e.test.ts +98 -24
- package/src/codegen/emit-errors.integration.test.ts +1 -1
- package/src/codegen/emit-scope.test.ts +395 -110
- package/src/codegen/emit-scope.ts +350 -55
- package/src/codegen/pipeline.test.ts +7 -7
- package/src/codegen/resolve-envelope.test.ts +5 -5
- package/src/codegen/resolve-envelope.ts +1 -1
- package/src/codegen/targets/_shared/route-slots.test.ts +109 -26
- package/src/codegen/targets/_shared/route-slots.ts +48 -11
- package/src/codegen/targets/kotlin/__fixtures__/users-golden.kt +73 -0
- package/src/codegen/targets/kotlin/emit-route-kotlin.test.ts +100 -17
- package/src/codegen/targets/kotlin/emit-scope-kotlin.test.ts +9 -6
- package/src/codegen/targets/kotlin/integration.test.ts +19 -0
- package/src/codegen/targets/swift/__fixtures__/users-golden.swift +79 -0
- package/src/codegen/targets/swift/access-level.test.ts +8 -11
- package/src/codegen/targets/swift/emit-route-swift.test.ts +103 -20
- package/src/codegen/targets/swift/emit-scope-swift.test.ts +12 -9
- package/src/codegen/targets/swift/integration.test.ts +17 -0
- package/src/create-http-stream.test.ts +97 -0
- package/src/create-http-stream.ts +191 -0
- package/src/create-http.test.ts +163 -0
- package/src/create-http.ts +211 -0
- package/src/create-stream.test.ts +565 -0
- package/src/create-stream.ts +228 -0
- package/src/create.test.ts +658 -0
- package/src/create.ts +172 -0
- package/src/exports.ts +2 -0
- package/src/implementations/http/README.md +135 -95
- package/src/implementations/http/astro/README.md +4 -5
- package/src/implementations/http/astro/index.test.ts +25 -18
- package/src/implementations/http/doc-registry.test.ts +42 -5
- package/src/implementations/http/doc-registry.ts +1 -1
- package/src/implementations/http/error-dispatch.test.ts +283 -0
- package/src/implementations/http/error-dispatch.ts +176 -0
- package/src/implementations/http/error-taxonomy.ts +5 -5
- package/src/implementations/http/hono/docs/http-doc.ts +43 -0
- package/src/implementations/http/hono/docs/http-stream-doc.ts +44 -0
- package/src/implementations/http/hono/docs/rpc-doc.ts +34 -0
- package/src/implementations/http/hono/docs/stream-doc.ts +53 -0
- package/src/implementations/http/hono/handlers/http-stream.test.ts +150 -0
- package/src/implementations/http/hono/handlers/http-stream.ts +152 -0
- package/src/implementations/http/hono/handlers/http.test.ts +130 -0
- package/src/implementations/http/hono/handlers/http.ts +147 -0
- package/src/implementations/http/hono/handlers/rpc.test.ts +81 -0
- package/src/implementations/http/hono/handlers/rpc.ts +54 -0
- package/src/implementations/http/hono/handlers/stream.test.ts +198 -0
- package/src/implementations/http/hono/handlers/stream.ts +208 -0
- package/src/implementations/http/hono/index.test.ts +329 -0
- package/src/implementations/http/hono/index.ts +204 -0
- package/src/implementations/http/hono/path.test.ts +96 -0
- package/src/implementations/http/hono/path.ts +59 -0
- package/src/implementations/http/hono/types.ts +93 -0
- package/src/implementations/http/on-request-error.test.ts +10 -116
- package/src/implementations/http/route-errors.test.ts +11 -77
- package/src/implementations/types.ts +44 -9
- package/src/index.test.ts +35 -1091
- package/src/index.ts +50 -474
- package/src/migration.test.ts +48 -0
- package/src/schema/compute-schema.ts +26 -12
- package/src/schema/parser.ts +62 -12
- package/src/stack-utils.ts +8 -0
- package/src/types.ts +133 -0
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/express-rpc.md +0 -137
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono-api.md +0 -173
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono-rpc.md +0 -142
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono-stream.md +0 -147
- package/build/implementations/http/express-rpc/error-taxonomy.test.js +0 -83
- package/build/implementations/http/express-rpc/error-taxonomy.test.js.map +0 -1
- package/build/implementations/http/express-rpc/index.d.ts +0 -125
- package/build/implementations/http/express-rpc/index.js +0 -216
- package/build/implementations/http/express-rpc/index.js.map +0 -1
- package/build/implementations/http/express-rpc/index.test.js +0 -684
- package/build/implementations/http/express-rpc/index.test.js.map +0 -1
- package/build/implementations/http/express-rpc/types.d.ts +0 -11
- package/build/implementations/http/express-rpc/types.js.map +0 -1
- package/build/implementations/http/hono-api/error-taxonomy.test.js +0 -137
- package/build/implementations/http/hono-api/error-taxonomy.test.js.map +0 -1
- package/build/implementations/http/hono-api/index.d.ts +0 -151
- package/build/implementations/http/hono-api/index.js +0 -344
- package/build/implementations/http/hono-api/index.js.map +0 -1
- package/build/implementations/http/hono-api/index.test.js +0 -992
- package/build/implementations/http/hono-api/index.test.js.map +0 -1
- package/build/implementations/http/hono-api/types.d.ts +0 -13
- package/build/implementations/http/hono-api/types.js.map +0 -1
- package/build/implementations/http/hono-rpc/error-taxonomy.test.js +0 -64
- package/build/implementations/http/hono-rpc/error-taxonomy.test.js.map +0 -1
- package/build/implementations/http/hono-rpc/index.d.ts +0 -130
- package/build/implementations/http/hono-rpc/index.js +0 -209
- package/build/implementations/http/hono-rpc/index.js.map +0 -1
- package/build/implementations/http/hono-rpc/index.test.js +0 -828
- package/build/implementations/http/hono-rpc/index.test.js.map +0 -1
- package/build/implementations/http/hono-rpc/types.d.ts +0 -11
- package/build/implementations/http/hono-rpc/types.js +0 -2
- package/build/implementations/http/hono-rpc/types.js.map +0 -1
- package/build/implementations/http/hono-stream/error-taxonomy.test.js +0 -159
- package/build/implementations/http/hono-stream/error-taxonomy.test.js.map +0 -1
- package/build/implementations/http/hono-stream/index.d.ts +0 -171
- package/build/implementations/http/hono-stream/index.js +0 -415
- package/build/implementations/http/hono-stream/index.js.map +0 -1
- package/build/implementations/http/hono-stream/index.test.js +0 -1383
- package/build/implementations/http/hono-stream/index.test.js.map +0 -1
- package/build/implementations/http/hono-stream/types.d.ts +0 -15
- package/build/implementations/http/hono-stream/types.js +0 -2
- package/build/implementations/http/hono-stream/types.js.map +0 -1
- package/src/implementations/http/express-rpc/README.md +0 -280
- package/src/implementations/http/express-rpc/error-taxonomy.test.ts +0 -103
- package/src/implementations/http/express-rpc/index.test.ts +0 -957
- package/src/implementations/http/express-rpc/index.ts +0 -327
- package/src/implementations/http/express-rpc/types.ts +0 -16
- package/src/implementations/http/hono-api/README.md +0 -284
- package/src/implementations/http/hono-api/error-taxonomy.test.ts +0 -179
- package/src/implementations/http/hono-api/index.test.ts +0 -1341
- package/src/implementations/http/hono-api/index.ts +0 -519
- package/src/implementations/http/hono-api/types.ts +0 -16
- package/src/implementations/http/hono-rpc/README.md +0 -357
- package/src/implementations/http/hono-rpc/error-taxonomy.test.ts +0 -82
- package/src/implementations/http/hono-rpc/index.test.ts +0 -1107
- package/src/implementations/http/hono-rpc/index.ts +0 -320
- package/src/implementations/http/hono-rpc/types.ts +0 -16
- package/src/implementations/http/hono-stream/README.md +0 -559
- package/src/implementations/http/hono-stream/error-taxonomy.test.ts +0 -178
- package/src/implementations/http/hono-stream/index.test.ts +0 -1804
- package/src/implementations/http/hono-stream/index.ts +0 -622
- package/src/implementations/http/hono-stream/types.ts +0 -20
- /package/build/{implementations/http/express-rpc/error-taxonomy.test.d.ts → create-http-stream.test.d.ts} +0 -0
- /package/build/{implementations/http/express-rpc/index.test.d.ts → create-http.test.d.ts} +0 -0
- /package/build/{implementations/http/hono-api/error-taxonomy.test.d.ts → create-stream.test.d.ts} +0 -0
- /package/build/{implementations/http/hono-api/index.test.d.ts → create.test.d.ts} +0 -0
- /package/build/implementations/http/{hono-rpc/error-taxonomy.test.d.ts → error-dispatch.test.d.ts} +0 -0
- /package/build/implementations/http/{hono-rpc/index.test.d.ts → hono/handlers/http-stream.test.d.ts} +0 -0
- /package/build/implementations/http/{hono-stream/error-taxonomy.test.d.ts → hono/handlers/http.test.d.ts} +0 -0
- /package/build/implementations/http/{hono-stream/index.test.d.ts → hono/handlers/rpc.test.d.ts} +0 -0
- /package/build/implementations/http/{express-rpc → hono}/types.js +0 -0
- /package/build/{implementations/http/hono-api/types.js → types.js} +0 -0
|
@@ -12,7 +12,6 @@ The goal is a "drop in the entry point" adapter: a single catch-all Astro file d
|
|
|
12
12
|
|
|
13
13
|
## Non-goals
|
|
14
14
|
|
|
15
|
-
- Express RPC support. Express uses Node `req`/`res`, not Web `Request`/`Response`. A bridge is non-trivial (body streams, hijacked sockets, `res.flushHeaders`); defer until requested.
|
|
16
15
|
- Native Astro builders. Mirroring `HonoAPIAppBuilder` as `AstroAPIAppBuilder` would duplicate path-matching, schema validation, error taxonomy, and DocRegistry plumbing. The catch-all pattern covers the request without that cost.
|
|
17
16
|
- Per-procedure file scaffolding (one Astro file per procedure). Out of scope for v1.
|
|
18
17
|
- DocRegistry / codegen integration. Users keep wiring `DocRegistry` against the same builders they pass to the adapter; the adapter returns no `.docs`.
|
|
@@ -229,7 +228,6 @@ Integration-style, real builders, simulated `Request`:
|
|
|
229
228
|
},
|
|
230
229
|
"optionalDependencies": {
|
|
231
230
|
"ajsc": "...",
|
|
232
|
-
"express": "...",
|
|
233
231
|
"hono": "...",
|
|
234
232
|
"astro": "^5.0.0"
|
|
235
233
|
},
|
|
@@ -239,7 +237,7 @@ Integration-style, real builders, simulated `Request`:
|
|
|
239
237
|
}
|
|
240
238
|
```
|
|
241
239
|
|
|
242
|
-
Matching the existing pattern for `hono
|
|
240
|
+
Matching the existing pattern for `hono`: listed as `optionalDependencies` so it isn't pulled into non-Astro deployments, and as `devDependencies` so types resolve at build time. Astro is imported via `import type` only — zero runtime dependency on the published package.
|
|
243
241
|
|
|
244
242
|
## Agent config / docs
|
|
245
243
|
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
# CreateHttp & CreateHttpStream — Design
|
|
2
|
+
|
|
3
|
+
Date: 2026-05-08
|
|
4
|
+
Branch: TBD (next major — v8)
|
|
5
|
+
Status: design
|
|
6
|
+
|
|
7
|
+
## Goal
|
|
8
|
+
|
|
9
|
+
Eliminate the long-standing `schema.params` vs `schema.input` ambiguity on the core `Create` / `CreateStream` primitives by splitting the surface into four purpose-shaped creators. RPC stays as the lean primitive; HTTP becomes its own first-class shape with structured request channels and response (body + headers) typing.
|
|
10
|
+
|
|
11
|
+
| Creator | Purpose | Schema shape |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `Create` | RPC unary (today's primitive, simplified) | `{ params, returnType }` |
|
|
14
|
+
| `CreateStream` | RPC streaming (today's primitive, simplified) | `{ params, yieldType, returnType }` |
|
|
15
|
+
| `CreateHttp` | HTTP unary (new) | `{ req: { pathParams?, query?, body?, headers? }, res?: { body?, headers? } }` |
|
|
16
|
+
| `CreateHttpStream` | HTTP streaming (new) | `{ req: {...}, yield, returnType?, res?: { headers? } }` |
|
|
17
|
+
|
|
18
|
+
The `Create` / `CreateStream` shape stops accepting `schema.input` entirely. HTTP-specific config (`path`, `method`, `successStatus`, `scope`, `errors`) becomes first-class on the HTTP creators rather than living on a `TExtendedConfig` generic. Response headers — previously not modelable — become a typed first-class concept.
|
|
19
|
+
|
|
20
|
+
## Non-goals
|
|
21
|
+
|
|
22
|
+
- **Runtime validation of `res.body` / `res.headers`.** Today `schema.returnType` is doc-only at runtime; the same rule applies to `res`. Adding a `validateResponse: true` opt-in is a clean follow-up but kept out to bound the breaking-changes scope to the input ambiguity cleanup.
|
|
23
|
+
- **`ctx.res.setHeader(...)` style imperative API.** Headers flow through the handler return value only. Pure return-driven, type-checkable end-to-end.
|
|
24
|
+
- **Per-builder migration adapters.** This is a major version. Clean break with informative `ProcedureRegistrationError` migration messages — no v7-compat shim layer.
|
|
25
|
+
- **Renaming `Create` or `CreateStream`.** Their shapes simplify (lose `schema.input`), but the names and the RPC posture stay.
|
|
26
|
+
|
|
27
|
+
## Decisions locked during brainstorming
|
|
28
|
+
|
|
29
|
+
1. **Four creators, one factory.** `Procedures<TContext>()` returns `{ Create, CreateStream, CreateHttp, CreateHttpStream }`. Mirrors the existing `Create` / `CreateStream` split.
|
|
30
|
+
2. **Conditional return shape on HTTP creators.** Handler return widens type-driven from declared `res`:
|
|
31
|
+
- no `res` → `void`
|
|
32
|
+
- `res: { body }` → bare body (matches today's `schema.returnType` ergonomics)
|
|
33
|
+
- `res: { headers }` → `{ headers }`
|
|
34
|
+
- `res: { body, headers }` → `{ body, headers }`
|
|
35
|
+
3. **HTTP fields baked into CreateHttp config.** `path`, `method`, `successStatus`, `scope`, `errors` live directly on the `CreateHttp` / `CreateHttpStream` config — no `Procedures<Ctx, APIConfig>()` plumbing for HTTP routes. `Create` / `CreateStream` keep `TExtendedConfig` for non-HTTP extensions (`RPCConfig`, etc.).
|
|
36
|
+
4. **`CreateHttpStream` initial response headers** via async-preamble shape: when `res.headers` is declared, the handler is an `async` function returning `{ headers, stream: AsyncGenerator }`. When not, the handler is a plain `async function*`.
|
|
37
|
+
5. **`schema.input` and `APIInput` removed.** Not deprecated — removed. `ProcedureRegistrationError` thrown at registration time with a v8 migration message.
|
|
38
|
+
|
|
39
|
+
## API surface
|
|
40
|
+
|
|
41
|
+
### The four creators
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
const procs = Procedures<MyContext>()
|
|
45
|
+
|
|
46
|
+
// 1. RPC unary — schema.input removed; schema.params is the only input shape
|
|
47
|
+
procs.Create('GetUser', {
|
|
48
|
+
schema: {
|
|
49
|
+
params: Type.Object({ id: Type.String() }),
|
|
50
|
+
returnType: Type.Object({ id: Type.String(), name: Type.String() }),
|
|
51
|
+
},
|
|
52
|
+
}, async (ctx, { id }) => ({ id, name: 'John' }))
|
|
53
|
+
|
|
54
|
+
// 2. RPC streaming — schema.input removed
|
|
55
|
+
procs.CreateStream('Tail', {
|
|
56
|
+
schema: {
|
|
57
|
+
params: Type.Object({ source: Type.String() }),
|
|
58
|
+
yieldType: Type.Object({ line: Type.String() }),
|
|
59
|
+
returnType: Type.Object({ totalLines: Type.Number() }),
|
|
60
|
+
},
|
|
61
|
+
}, async function* (ctx, { source }) { /* ... */ })
|
|
62
|
+
|
|
63
|
+
// 3. HTTP unary
|
|
64
|
+
procs.CreateHttp('GetUser', {
|
|
65
|
+
path: '/users/:id',
|
|
66
|
+
method: 'get',
|
|
67
|
+
successStatus: 200, // optional, defaulted by method
|
|
68
|
+
scope: 'users', // optional, codegen grouping
|
|
69
|
+
errors: ['UserNotFound'], // optional, taxonomy keys (TErrorKey-narrowable)
|
|
70
|
+
schema: {
|
|
71
|
+
req: {
|
|
72
|
+
pathParams: Type.Object({ id: Type.String() }),
|
|
73
|
+
query: Type.Object({ include: Type.Optional(Type.String()) }),
|
|
74
|
+
},
|
|
75
|
+
res: {
|
|
76
|
+
body: Type.Object({ id: Type.String(), name: Type.String() }),
|
|
77
|
+
headers: Type.Object({ 'x-rate-limit-remaining': Type.String() }),
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
}, async (ctx, { pathParams, query }) => ({
|
|
81
|
+
body: { id: pathParams.id, name: 'John' },
|
|
82
|
+
headers: { 'x-rate-limit-remaining': '99' },
|
|
83
|
+
}))
|
|
84
|
+
|
|
85
|
+
// 4. HTTP streaming — async preamble + generator when res.headers declared
|
|
86
|
+
procs.CreateHttpStream('TailLogs', {
|
|
87
|
+
path: '/streams/logs',
|
|
88
|
+
method: 'get',
|
|
89
|
+
scope: 'streams',
|
|
90
|
+
schema: {
|
|
91
|
+
req: { query: Type.Object({ source: Type.String() }) },
|
|
92
|
+
yield: Type.Object({ line: Type.String() }),
|
|
93
|
+
returnType: Type.Object({ totalLines: Type.Number() }),
|
|
94
|
+
res: { headers: Type.Object({ 'x-stream-id': Type.String() }) },
|
|
95
|
+
},
|
|
96
|
+
}, async (ctx, { query }) => {
|
|
97
|
+
const streamId = await openStream(query.source)
|
|
98
|
+
return {
|
|
99
|
+
headers: { 'x-stream-id': streamId },
|
|
100
|
+
stream: (async function* () {
|
|
101
|
+
yield { line: 'a' }
|
|
102
|
+
return { totalLines: 1 }
|
|
103
|
+
})(),
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
// 4b. Without res.headers — plain async generator (today's CreateStream shape)
|
|
108
|
+
procs.CreateHttpStream('TailLogs', {
|
|
109
|
+
path: '/streams/logs', method: 'get',
|
|
110
|
+
schema: {
|
|
111
|
+
req: { query: Type.Object({ source: Type.String() }) },
|
|
112
|
+
yield: Type.Object({ line: Type.String() }),
|
|
113
|
+
returnType: Type.Object({ totalLines: Type.Number() }),
|
|
114
|
+
},
|
|
115
|
+
}, async function* (ctx, { query }) {
|
|
116
|
+
yield { line: 'a' }
|
|
117
|
+
return { totalLines: 1 }
|
|
118
|
+
})
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Handler signature inference
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
type CreateHttpHandler<TReq, TRes, TContext> = (
|
|
125
|
+
ctx: TContext & TLocalContext,
|
|
126
|
+
req: PrettifyChannels<TReq>,
|
|
127
|
+
) => Promise<HttpReturn<TRes>>
|
|
128
|
+
|
|
129
|
+
type HttpReturn<TRes> =
|
|
130
|
+
TRes extends { body: infer B; headers: infer H } ? { body: Infer<B>; headers: Infer<H> }
|
|
131
|
+
: TRes extends { headers: infer H } ? { headers: Infer<H> }
|
|
132
|
+
: TRes extends { body: infer B } ? Infer<B>
|
|
133
|
+
: void
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`PrettifyChannels<TReq>` maps each declared channel through `TSchemaLib<TReq[K]>` — same machinery as today's `schema.input` inference at `src/index.ts:127-130`.
|
|
137
|
+
|
|
138
|
+
`ctx` shape is unchanged from today: `TContext & { error, signal? }` for `CreateHttp`, `TContext & { error, signal: AbortSignal }` for `CreateHttpStream`. Hono builders inject `c.req.raw.signal` automatically.
|
|
139
|
+
|
|
140
|
+
### Generic over `TErrorKey`
|
|
141
|
+
|
|
142
|
+
Same compile-time typo protection as today's `APIConfig<TErrorKey>`, lifted onto the creator. `TErrorKey` defaults to `string` (unconstrained) and gets narrowed in one of two ways:
|
|
143
|
+
|
|
144
|
+
**Per-call narrowing via `satisfies`** (zero ceremony):
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
const appErrors = defineErrorTaxonomy({
|
|
148
|
+
UserNotFound: { class: UserNotFoundError, statusCode: 404 },
|
|
149
|
+
})
|
|
150
|
+
type AppErrorKey = keyof typeof appErrors & string
|
|
151
|
+
|
|
152
|
+
procs.CreateHttp('GetUser', {
|
|
153
|
+
path: '/users/:id', method: 'get',
|
|
154
|
+
errors: ['UserNotFound', 'NotARealKey'] satisfies AppErrorKey[], // ^^ TS error
|
|
155
|
+
schema: { req: {...}, res: {...} },
|
|
156
|
+
}, handler)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**App-wide narrowing via aliased creator** (DRYer for large apps): expose a typed alias once at module-init time and use it everywhere:
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
const procs = Procedures<MyContext>()
|
|
163
|
+
const HttpRoute = procs.CreateHttp as
|
|
164
|
+
<TName extends string, TReq, TRes>(
|
|
165
|
+
name: TName,
|
|
166
|
+
config: CreateHttpConfig<TReq, TRes, AppErrorKey>,
|
|
167
|
+
handler: CreateHttpHandler<TReq, TRes, MyContext>,
|
|
168
|
+
) => ReturnType<typeof procs.CreateHttp<TName, TReq, TRes, AppErrorKey>>
|
|
169
|
+
|
|
170
|
+
HttpRoute('GetUser', { ..., errors: ['UserNotFound'] }, handler)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
The framework ships `CreateHttpConfig` and `CreateHttpHandler` as exported helper types so the alias pattern is a one-liner per app.
|
|
174
|
+
|
|
175
|
+
### `kind` discriminant on every registration
|
|
176
|
+
|
|
177
|
+
Replaces today's `isStream?: boolean`. Builders filter by kind; non-matching procedures recorded in `skippedProcedures` and warned at `DocRegistry.toJSON()` time.
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
type ProcedureKind = 'rpc' | 'rpc-stream' | 'http' | 'http-stream'
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
| Creator | `kind` | Served by |
|
|
184
|
+
|---|---|---|
|
|
185
|
+
| `Create` | `'rpc'` | hono-rpc |
|
|
186
|
+
| `CreateStream` | `'rpc-stream'` | hono-stream |
|
|
187
|
+
| `CreateHttp` | `'http'` | hono-api |
|
|
188
|
+
| `CreateHttpStream` | `'http-stream'` | hono-api |
|
|
189
|
+
|
|
190
|
+
## Builder integration
|
|
191
|
+
|
|
192
|
+
### `HonoAPIAppBuilder` — unified HTTP builder
|
|
193
|
+
|
|
194
|
+
Serves both `'http'` and `'http-stream'` registrations. Single mount, single error config, single doc source. Internal branch on kind:
|
|
195
|
+
|
|
196
|
+
- **`'http'` branch:** today's flow with three differences:
|
|
197
|
+
1. Reads `path` / `method` / `successStatus` / `scope` / `errors` directly off the registration (no `Procedures<Ctx, APIConfig>()` generic plumbing).
|
|
198
|
+
2. Drops the `schema.params` body/query fallback. `req` channels are the only source.
|
|
199
|
+
3. When the handler returns `{ body, headers }`, iterate headers via `c.header(k, v)` before `c.json(body, status)` / `c.body(null, status)`. Error responses don't carry handler-declared headers.
|
|
200
|
+
- **`'http-stream'` branch:** pre-stream phase (validation + async preamble if `res.headers` declared) → if it throws, error taxonomy serializes a normal HTTP error (no SSE opened); if it succeeds, response headers are written, then the SSE/text stream opens. Mid-stream errors continue through `onMidStreamError`. The `isPrevalidated` flag pattern (today used by HonoStreamAppBuilder) extends to this branch.
|
|
201
|
+
|
|
202
|
+
`HonoAPIFactoryItem<TFactory>` simplifies — no `APIConfig` extension generic. `extendProcedureDoc` callback signature is unchanged, but the `base` doc handed to it has the new `req`/`res` grouping (callbacks reading `base.jsonSchema.body` directly need to read `base.jsonSchema.req.body` after upgrade).
|
|
203
|
+
|
|
204
|
+
The path-param consistency check (`extractPathParamNames` + schema key matching) **moves from the Hono builder into core `CreateHttp` registration** — fires at registration time regardless of which HTTP builder is attached. `ProcedureRegistrationError` with the existing well-formed message.
|
|
205
|
+
|
|
206
|
+
### Other builders — minimal change
|
|
207
|
+
|
|
208
|
+
- **`HonoStreamAppBuilder`:** unchanged externally. Internally filters by `kind === 'rpc-stream'`. Symmetric pair to `HonoRPCAppBuilder` for serving `Create` / `CreateStream`.
|
|
209
|
+
- **`HonoRPCAppBuilder`:** unchanged externally. Internally filters by `kind === 'rpc'`. CreateHttp registrations on the same factory get recorded in `skippedProcedures`.
|
|
210
|
+
- **Astro adapter** (`src/implementations/http/astro/`): same kind-aware updates as hono-api. Mirrors the hono-api pattern. Implementation phase.
|
|
211
|
+
|
|
212
|
+
### Mixed-kind factories
|
|
213
|
+
|
|
214
|
+
Because all four creators share one `Procedures()` factory, you *can* mix `Create` and `CreateHttp` in the same factory. Builders pick out what they serve. The user-facing rule: register a builder for each kind you want to serve.
|
|
215
|
+
|
|
216
|
+
## Doc envelope & codegen impact
|
|
217
|
+
|
|
218
|
+
### `APIHttpRouteDoc` regroups under `req` / `res`
|
|
219
|
+
|
|
220
|
+
Symmetric with the registration shape — removes the awkward "request `headers` vs response `headers`" overload at the JSON schema level (today both would just be top-level `headers`):
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
// before
|
|
224
|
+
jsonSchema: { pathParams?, query?, body?, headers?, response? }
|
|
225
|
+
|
|
226
|
+
// after
|
|
227
|
+
jsonSchema: {
|
|
228
|
+
req: { pathParams?, query?, body?, headers? }
|
|
229
|
+
res?: { body?, headers? }
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### New `'http-stream'` kind in the envelope
|
|
234
|
+
|
|
235
|
+
Existing `StreamHttpRouteDoc` (kind `'stream'`) keeps serving `CreateStream` unchanged. New variant for `CreateHttpStream`:
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
interface HttpStreamRouteDoc {
|
|
239
|
+
kind: 'http-stream'
|
|
240
|
+
name: string
|
|
241
|
+
scope?: string
|
|
242
|
+
path: string
|
|
243
|
+
method: HttpMethod
|
|
244
|
+
fullPath: string
|
|
245
|
+
streamMode: StreamMode
|
|
246
|
+
jsonSchema: {
|
|
247
|
+
req: { pathParams?, query?, body?, headers? }
|
|
248
|
+
res?: { headers? } // body absent — yield/returnType replace it
|
|
249
|
+
yield?: Record<string, unknown>
|
|
250
|
+
returnType?: Record<string, unknown>
|
|
251
|
+
}
|
|
252
|
+
errors?: string[] // pre-stream only
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
`AnyHttpRouteDoc = RPCHttpRouteDoc | APIHttpRouteDoc | StreamHttpRouteDoc | HttpStreamRouteDoc`.
|
|
257
|
+
|
|
258
|
+
### Generated callable shape (TS target)
|
|
259
|
+
|
|
260
|
+
Conditional return widens symmetric to the server side:
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
// res: { body } only — bare body (no break for routes without res.headers)
|
|
264
|
+
function getUser(req, opts?): Promise<GetUser.Response.Body>
|
|
265
|
+
|
|
266
|
+
// res: { body, headers }
|
|
267
|
+
function getUser(req, opts?): Promise<{ body: GetUser.Response.Body; headers: GetUser.Response.Headers }>
|
|
268
|
+
|
|
269
|
+
// res: { headers } only
|
|
270
|
+
function getUser(req, opts?): Promise<{ headers: GetUser.Response.Headers }>
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Generated namespace (namespace mode):
|
|
274
|
+
```
|
|
275
|
+
Users.GetUser.Req.PathParams
|
|
276
|
+
Users.GetUser.Req.Query
|
|
277
|
+
Users.GetUser.Req.Body
|
|
278
|
+
Users.GetUser.Req.Headers
|
|
279
|
+
Users.GetUser.Response.Body
|
|
280
|
+
Users.GetUser.Response.Headers
|
|
281
|
+
Users.GetUser.Errors
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Flat-mode aliases: `GetUserReqPathParams`, `GetUserReqBody`, `GetUserResponseBody`, `GetUserResponseHeaders`. Naming lives in `src/codegen/emit-scope.ts` and per-target run modules; `targets/_shared/route-slots.ts` gets a response-headers slot.
|
|
285
|
+
|
|
286
|
+
`.safe()` widens identically: `Result<{ body, headers }, ETyped>` when headers declared. The `'typed'` arm omission rule (when no `route.errors`) is unchanged.
|
|
287
|
+
|
|
288
|
+
### `CreateHttpStream` generated callable
|
|
289
|
+
|
|
290
|
+
Returns `TypedStream<TYield, TReturn>` as today; `TypedStream` gains an optional `.headers` field surfaced by the adapter when `res.headers` is declared on the route:
|
|
291
|
+
|
|
292
|
+
```ts
|
|
293
|
+
interface TypedStream<TYield, TReturn> {
|
|
294
|
+
[Symbol.asyncIterator](): AsyncIterator<TYield>
|
|
295
|
+
result: Promise<TReturn>
|
|
296
|
+
headers?: Headers // populated at stream-open time
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
At runtime `.headers` is always populated (the adapter has the response Headers object). The TypeScript surface marks it optional and emits it on the route's `TypedStream` type only when `res.headers` is declared, so callers without declared response headers don't see it in their type — no behavior difference, just type-level discipline. `AdapterStreamResponse` extends with a `headers: Headers` field; `executeStream` wires it onto the constructed `TypedStream`.
|
|
301
|
+
|
|
302
|
+
### Kotlin / Swift targets
|
|
303
|
+
|
|
304
|
+
Mobile devs own the HTTP layer entirely (existing posture). Emit a `Response.Headers` data class / struct only when `res.headers` is declared. Consumer's HTTP wrapper maps response headers into it. No runtime adapter changes for these targets.
|
|
305
|
+
|
|
306
|
+
### Self-contained codegen
|
|
307
|
+
|
|
308
|
+
`_client.ts` extends to read response headers from the unary response and surface initial headers on the stream response. Everything else (error registry, runtime classes, dispatch, `_errors.ts`, `_types.ts`) is unchanged. Source-hash invalidation forces regeneration on upgrade — no migration tooling needed.
|
|
309
|
+
|
|
310
|
+
## Error handling
|
|
311
|
+
|
|
312
|
+
The existing taxonomy system (`defineErrorTaxonomy`, `resolveErrorResponse`, `defaultErrorTaxonomy`) carries forward unchanged. Per-route `errors` keys, dispatch order (`onRequestError` observer → taxonomy → `onError` → hard default), and the client error registry / dispatch all keep their shape.
|
|
313
|
+
|
|
314
|
+
### `CreateHttpStream` error lifecycle
|
|
315
|
+
|
|
316
|
+
- **Pre-stream** (validation, async preamble): unary error dispatch — taxonomy / `onError` / hard default. SSE response never opened. Identical to today's HonoStreamAppBuilder pre-stream behavior, extended to the async preamble step.
|
|
317
|
+
- **Mid-stream** (errors thrown after first yield): `onMidStreamError`, unchanged. Taxonomy doesn't apply — response already committed.
|
|
318
|
+
|
|
319
|
+
### `isPrevalidated` and `noRuntimeValidation`
|
|
320
|
+
|
|
321
|
+
Both unchanged. `isPrevalidated` flag pattern extends to the new `'http-stream'` builder branch. `noRuntimeValidation` opts the entire factory out of per-call AJV for all four creators (JSON Schema still computed at registration time).
|
|
322
|
+
|
|
323
|
+
### New registration-time errors (all `ProcedureRegistrationError`)
|
|
324
|
+
|
|
325
|
+
| Trigger | Migration message |
|
|
326
|
+
|---|---|
|
|
327
|
+
| `schema.input` on `Create` / `CreateStream` | "`schema.input` was removed in v8. Use `CreateHttp` / `CreateHttpStream` for per-channel HTTP validation." |
|
|
328
|
+
| `path` / `method` / `req` / `res` on `Create` / `CreateStream` | "HTTP fields require `CreateHttp` / `CreateHttpStream`." |
|
|
329
|
+
| `schema.params` on `CreateHttp` / `CreateHttpStream` | "Use `schema.req.body` (or `query`) instead of `schema.params`." |
|
|
330
|
+
| Path template params don't match `req.pathParams` schema keys | (existing message, moved into core) |
|
|
331
|
+
|
|
332
|
+
Phrased as "X was removed in v8, use Y" so anyone running v7 code against the v8 core gets pointed straight at the fix.
|
|
333
|
+
|
|
334
|
+
## Source organization
|
|
335
|
+
|
|
336
|
+
`src/index.ts` is 537 lines today. Adding two more creators inline doubles the surface. Split:
|
|
337
|
+
|
|
338
|
+
```
|
|
339
|
+
src/
|
|
340
|
+
index.ts # Procedures factory, glue (~80 lines)
|
|
341
|
+
create.ts # Create
|
|
342
|
+
create-stream.ts # CreateStream
|
|
343
|
+
create-http.ts # CreateHttp + path-param consistency check
|
|
344
|
+
create-http-stream.ts # CreateHttpStream
|
|
345
|
+
types.ts # TLocalContext, TStreamContext, registration types, ProcedureKind
|
|
346
|
+
schema/ # unchanged
|
|
347
|
+
implementations/ # builders updated per "Builder integration" section
|
|
348
|
+
codegen/ # updated per "Doc envelope & codegen impact" section
|
|
349
|
+
client/ # _client.ts response.headers + TypedStream.headers
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Each creator is independent and self-contained — passes the "what does it do, how do you use it, what does it depend on" test.
|
|
353
|
+
|
|
354
|
+
## Migration
|
|
355
|
+
|
|
356
|
+
Major version (v8). No deprecation period. Registration errors are the migration safety net.
|
|
357
|
+
|
|
358
|
+
| v7 | v8 |
|
|
359
|
+
|---|---|
|
|
360
|
+
| `Procedures<Ctx, APIConfig>()` | `Procedures<Ctx>()` |
|
|
361
|
+
| `.Create('GetUser', { path, method, schema: { input: {...} } }, h)` | `.CreateHttp('GetUser', { path, method, schema: { req: {...}, res: { body: ... } } }, h)` |
|
|
362
|
+
| `.CreateStream('Tail', { path, method, schema: { input: {...} } }, g)` | `.CreateHttpStream('Tail', { path, method, schema: { req: {...}, yield: ... } }, g)` |
|
|
363
|
+
| `schema.input.pathParams` | `schema.req.pathParams` |
|
|
364
|
+
| `schema.params` on an HTTP route | `schema.req.body` or `schema.req.query` (explicit channel) |
|
|
365
|
+
| `APIInput<{...}>` satisfies type | removed — channels typed by `req` directly |
|
|
366
|
+
| `Procedures<Ctx, RPCConfig>().Create(...)` | unchanged — RPC factories keep `TExtendedConfig` |
|
|
367
|
+
| Handler `(ctx, { pathParams, query, body }) => result` | unchanged — request side identical |
|
|
368
|
+
| Handler `return result` | unchanged unless `res.headers` declared → `return { body, headers }` |
|
|
369
|
+
|
|
370
|
+
### What's NOT changing
|
|
371
|
+
|
|
372
|
+
- `HonoRPCAppBuilder`, `HonoStreamAppBuilder` external APIs.
|
|
373
|
+
- `DocRegistry`, error taxonomy public API.
|
|
374
|
+
- Client error dispatch, generated error registry, per-route `Errors` union.
|
|
375
|
+
- Per-call `ProcedureCallOptions`, hooks pipeline, `RequestMeta` augmentation.
|
|
376
|
+
- `TypedStream` external API (only addition: optional `.headers`).
|
|
377
|
+
- AJV config (`allErrors`, `coerceTypes`, `removeAdditional`).
|
|
378
|
+
- Codegen flag set, CLI surface, `--target ts/kotlin/swift`.
|
|
379
|
+
|
|
380
|
+
### Codegen consumer migration
|
|
381
|
+
|
|
382
|
+
1. `npm install` v8 server packages.
|
|
383
|
+
2. Restart the dev server / rebuild.
|
|
384
|
+
3. Re-run `npx ts-procedures-codegen` (or `--watch`). Source hash invalidates; fresh files written.
|
|
385
|
+
4. TS callers update flat-mode aliases (`GetUserResponse` → `GetUserResponseBody`); namespace-mode users get `Users.GetUser.Response.Body` automatically.
|
|
386
|
+
5. Routes adopting `res.headers` update await sites: `const { body, headers } = await api.users.getUser(req)`.
|
|
387
|
+
|
|
388
|
+
## Testing
|
|
389
|
+
|
|
390
|
+
| Test file | Coverage |
|
|
391
|
+
|---|---|
|
|
392
|
+
| `src/create.test.ts` | Extracted from `index.test.ts`. Create-only path. Schema-input rejection. |
|
|
393
|
+
| `src/create-stream.test.ts` | CreateStream-only. Schema-input rejection. Yield validation, abort, generator return value. |
|
|
394
|
+
| `src/create-http.test.ts` | All four req-channel combos. Response shape: body-only, body+headers, headers-only, void. Registration errors (HTTP fields rejected on Create, path-param mismatch, `schema.params` rejected). `TErrorKey` compile-time narrowing via `expectTypeOf`. |
|
|
395
|
+
| `src/create-http-stream.test.ts` | Both handler shapes (async generator vs. async-returning-`{headers, stream}`). Pre-stream errors as HTTP errors. Mid-stream errors → `onMidStreamError`. Initial headers applied before first yield. |
|
|
396
|
+
| `src/implementations/http/hono-api/index.test.ts` | Both `'http'` and `'http-stream'` kinds. Response headers application. `skippedProcedures` for non-http kinds. |
|
|
397
|
+
| `src/implementations/http/{hono-rpc,hono-stream}/index.test.ts` | Filter by `kind`. `skippedProcedures` populated when CreateHttp procedures are registered to RPC factories. |
|
|
398
|
+
| `src/codegen/__fixtures__/users-envelope.json` | Regenerated to v8 envelope (`req`/`res` grouping, new `'http-stream'` kind). |
|
|
399
|
+
| `src/codegen/targets/{ts,kotlin,swift}/run.test.ts` | Snapshot updates. New tests for `Response.Headers` emission. |
|
|
400
|
+
| `src/client/call.test.ts`, `stream.test.ts` | Response-headers parsing on unary; `TypedStream.headers` populated for streams declaring `res.headers`. |
|
|
401
|
+
|
|
402
|
+
## Out-of-scope follow-ups
|
|
403
|
+
|
|
404
|
+
These are flagged for the implementation phase but not part of this design:
|
|
405
|
+
|
|
406
|
+
- **`agent_config/` updates** — `claude-code/skills/ts-procedures-scaffold/templates/`, `claude-code/skills/ts-procedures/patterns.md`, `anti-patterns.md`, `cursor/cursorrules`, `copilot/copilot-instructions.md` updated to use `CreateHttp` for HTTP examples.
|
|
407
|
+
- **`CHANGELOG.md` and `README.md`** — major-version entry with migration table and v7→v8 expectations.
|
|
408
|
+
- **`validateResponse: true` opt-in** — runtime validation of `res.body` / `res.headers`. Clean follow-up; non-breaking.
|
|
409
|
+
- **Astro adapter detail design** — mirrors hono-api; called out as "same kind-aware updates" but not specced separately.
|