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
package/docs/core.md
CHANGED
|
@@ -10,6 +10,7 @@ The `Procedures()` function creates a factory for defining procedures. It accept
|
|
|
10
10
|
|
|
11
11
|
```typescript
|
|
12
12
|
Procedures<TContext, TExtendedConfig>(builder?: {
|
|
13
|
+
config?: { noRuntimeValidation?: true }
|
|
13
14
|
onCreate?: (procedure: TProcedureRegistration<TContext, TExtendedConfig>) => void
|
|
14
15
|
})
|
|
15
16
|
```
|
|
@@ -18,6 +19,7 @@ Procedures<TContext, TExtendedConfig>(builder?: {
|
|
|
18
19
|
|-----------|----------------------------------------------------------------------------|
|
|
19
20
|
| `TContext` | The base context type passed to all handlers as the first parameter |
|
|
20
21
|
| `TExtendedConfig` | Additional configuration properties for all procedures `config` properties |
|
|
22
|
+
| `builder.config.noRuntimeValidation` | When `true`, every procedure created by this factory skips AJV validation of `schema.params` and `schema.input` at call time. Applies to both `Create` and `CreateStream`. Default: validation runs. |
|
|
21
23
|
| `builder.onCreate` | Optional callback invoked when each procedure is registered (runtime) |
|
|
22
24
|
|
|
23
25
|
## Create Function
|
|
@@ -91,7 +93,7 @@ async function* (ctx, params) => AsyncGenerator<TYield, TReturn | void>
|
|
|
91
93
|
- `ctx.error(message, meta?)` - Create a ProcedureError
|
|
92
94
|
- `ctx.signal?` - AbortSignal for cancellation support (optional for `Create`, always present for `CreateStream`)
|
|
93
95
|
|
|
94
|
-
When using the built-in HTTP
|
|
96
|
+
When using the built-in HTTP implementation (Hono), `ctx.signal` is automatically injected from the HTTP request, so handlers can detect client disconnection. For direct usage without a server, `signal` is `undefined` unless you pass one in context.
|
|
95
97
|
|
|
96
98
|
**Returns:**
|
|
97
99
|
- `{ [name]: handler }` - Named generator export
|
|
@@ -221,6 +223,22 @@ AJV is configured with:
|
|
|
221
223
|
|
|
222
224
|
**Note:** `schema.params` is validated at runtime. `schema.returnType` is for documentation/introspection only.
|
|
223
225
|
|
|
226
|
+
### Disabling Runtime Validation
|
|
227
|
+
|
|
228
|
+
For trusted internal callers — for example, a back-of-house factory whose inputs are already type-checked at build time and whose handlers are never invoked from public HTTP — pass `config.noRuntimeValidation: true` when constructing the factory:
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
const { Create, CreateStream } = Procedures({
|
|
232
|
+
config: { noRuntimeValidation: true },
|
|
233
|
+
})
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
When set, every procedure registered by this factory skips AJV validation of `schema.params` and `schema.input` on every call. JSON Schema is still computed at registration time (so `info.schema` and codegen are unaffected) — only the per-call validator runs are bypassed.
|
|
237
|
+
|
|
238
|
+
**Use sparingly.** Do not enable this for procedures that accept input from public clients, untyped JSON bodies, or anything you do not control end-to-end. The flag is shaped as `noRuntimeValidation?: true` (only `true` is accepted) to make the opt-out explicit at the call site.
|
|
239
|
+
|
|
240
|
+
This is independent of the per-call `ctx.isPrevalidated` escape hatch used by HTTP builders that have already validated upstream — both paths short-circuit the same validators.
|
|
241
|
+
|
|
224
242
|
## Error Handling
|
|
225
243
|
|
|
226
244
|
### Using ctx.error()
|
|
@@ -274,7 +292,7 @@ The taxonomy also drives typed `catch` blocks on generated clients and per-route
|
|
|
274
292
|
|
|
275
293
|
## Abort Signal
|
|
276
294
|
|
|
277
|
-
For regular procedures, `ctx.signal` is available when the server implementation provides it. The built-in HTTP
|
|
295
|
+
For regular procedures, `ctx.signal` is available when the server implementation provides it. The built-in HTTP integration (`HonoAppBuilder`) injects the request's abort signal automatically:
|
|
278
296
|
|
|
279
297
|
```typescript
|
|
280
298
|
const { Create } = Procedures<{ signal: AbortSignal }>()
|
|
@@ -292,7 +310,7 @@ const { LongQuery } = Create(
|
|
|
292
310
|
)
|
|
293
311
|
```
|
|
294
312
|
|
|
295
|
-
When using the Hono
|
|
313
|
+
When using the Hono implementation, `ctx.signal` aborts when the client disconnects, automatically cancelling in-flight `fetch()` calls, database queries, or any other signal-aware operation.
|
|
296
314
|
|
|
297
315
|
For streaming abort signal behavior (including `signal.reason` and consumer break detection), see [Streaming Procedures](./streaming.md#abort-signal-integration).
|
|
298
316
|
|
|
@@ -300,27 +318,25 @@ For streaming abort signal behavior (including `signal.reason` and consumer brea
|
|
|
300
318
|
|
|
301
319
|
### onCreate Callback
|
|
302
320
|
|
|
303
|
-
Register procedures with
|
|
321
|
+
Register procedures with a custom framework via the `onCreate` callback. Each registration receives `{ name, handler, config }` so you can wire it into whatever router or framework you want:
|
|
304
322
|
|
|
305
323
|
```typescript
|
|
306
|
-
import
|
|
324
|
+
import { Hono } from 'hono'
|
|
325
|
+
import { ProcedureError } from 'ts-procedures'
|
|
307
326
|
|
|
308
|
-
const app =
|
|
309
|
-
const routes: Map<string, Function> = new Map()
|
|
327
|
+
const app = new Hono()
|
|
310
328
|
|
|
311
|
-
const { Create } = Procedures<{
|
|
312
|
-
onCreate: ({ name, handler
|
|
313
|
-
|
|
314
|
-
app.post(`/rpc/${name}`, async (req, res) => {
|
|
329
|
+
const { Create } = Procedures<{ raw: unknown }>({
|
|
330
|
+
onCreate: ({ name, handler }) => {
|
|
331
|
+
app.post(`/rpc/${name}`, async (c) => {
|
|
315
332
|
try {
|
|
316
|
-
const result = await handler({
|
|
317
|
-
|
|
333
|
+
const result = await handler({ raw: c }, await c.req.json())
|
|
334
|
+
return c.json(result)
|
|
318
335
|
} catch (e) {
|
|
319
336
|
if (e instanceof ProcedureError) {
|
|
320
|
-
|
|
321
|
-
} else {
|
|
322
|
-
res.status(500).json({ error: 'Internal error' })
|
|
337
|
+
return c.json({ error: e.message }, 500)
|
|
323
338
|
}
|
|
339
|
+
return c.json({ error: 'Internal error' }, 500)
|
|
324
340
|
}
|
|
325
341
|
})
|
|
326
342
|
},
|
|
@@ -329,7 +345,7 @@ const { Create } = Procedures<{ req: Request; res: Response }>({
|
|
|
329
345
|
// Procedures are automatically registered as /rpc/GetUser, /rpc/CreateUser, etc.
|
|
330
346
|
```
|
|
331
347
|
|
|
332
|
-
For built-in HTTP
|
|
348
|
+
For the built-in HTTP integration (RPC, RPC streams, REST, REST streams via `HonoAppBuilder`), see [HTTP Integrations](./http-integrations.md).
|
|
333
349
|
|
|
334
350
|
### Introspection with getProcedures()
|
|
335
351
|
|
|
@@ -419,6 +435,7 @@ describe('GetUser', () => {
|
|
|
419
435
|
Creates a procedure factory.
|
|
420
436
|
|
|
421
437
|
**Parameters:**
|
|
438
|
+
- `builder.config.noRuntimeValidation` - When `true`, every procedure registered through this factory skips AJV validation of `schema.params` and `schema.input` at call time. Default: validation runs. See [Disabling Runtime Validation](#disabling-runtime-validation).
|
|
422
439
|
- `builder.onCreate` - Callback invoked when each procedure is registered
|
|
423
440
|
|
|
424
441
|
**Returns:**
|
|
@@ -2,89 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
# HTTP Framework Integrations
|
|
4
4
|
|
|
5
|
-
ts-procedures includes built-in HTTP
|
|
5
|
+
ts-procedures includes a built-in HTTP builder for Hono that handles routing, context resolution, lifecycle hooks, abort signals, and automatic route documentation. The builder reads procedures off the factory at registration time and mounts the matching routes when you call `build()`.
|
|
6
6
|
|
|
7
|
-
For a full
|
|
7
|
+
For a full reference (config interfaces, path generation, context resolution, abort signal, lifecycle hooks, route documentation), see the [HTTP implementations overview](../src/implementations/http/README.md).
|
|
8
8
|
|
|
9
9
|
## Integrations at a Glance
|
|
10
10
|
|
|
11
|
-
| Integration | Export |
|
|
12
|
-
|
|
13
|
-
|
|
|
14
|
-
| Hono RPC | `ts-procedures/hono-rpc` | RPC (POST routes) | [README](../src/implementations/http/hono-rpc/README.md) |
|
|
15
|
-
| Hono Stream | `ts-procedures/hono-stream` | SSE/text streaming | [README](../src/implementations/http/hono-stream/README.md) |
|
|
16
|
-
| Hono API | `ts-procedures/hono-api` | REST (method-based) | [README](../src/implementations/http/hono-api/README.md) |
|
|
11
|
+
| Integration | Export | Procedure kinds | Guide |
|
|
12
|
+
|-------------|--------|-----------------|-------|
|
|
13
|
+
| HonoAppBuilder | `ts-procedures/hono` | `rpc`, `rpc-stream`, `http`, `http-stream` | [HTTP implementations overview](../src/implementations/http/README.md) |
|
|
17
14
|
|
|
18
|
-
##
|
|
15
|
+
## Hono
|
|
19
16
|
|
|
20
|
-
|
|
17
|
+
`HonoAppBuilder` is the single Hono integration. One builder dispatches all four procedure kinds — `rpc`, `rpc-stream`, `http`, `http-stream` — from one `register()` call. Works with Bun, Deno, Cloudflare Workers, and Node.js.
|
|
21
18
|
|
|
22
19
|
```typescript
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
RPC.Create(
|
|
28
|
-
'GetUser',
|
|
29
|
-
{
|
|
30
|
-
scope: ['users', 'get'],
|
|
31
|
-
version: 1,
|
|
32
|
-
schema: {
|
|
33
|
-
params: Type.Object({ id: Type.String() }),
|
|
34
|
-
returnType: Type.Object({ id: Type.String(), name: Type.String() }),
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
async (ctx, params) => {
|
|
38
|
-
return { id: params.id, name: 'John Doe' }
|
|
39
|
-
}
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
const app = new ExpressRPCAppBuilder()
|
|
43
|
-
.register(RPC, (req) => ({ userId: req.headers['x-user-id'] as string }))
|
|
44
|
-
.build()
|
|
45
|
-
|
|
46
|
-
app.listen(3000)
|
|
47
|
-
// Route created: POST /users/get/get-user/1
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
See the [Express RPC Integration Guide](../src/implementations/http/express-rpc/README.md) for complete setup including lifecycle hooks, error handling, and route documentation.
|
|
51
|
-
|
|
52
|
-
## Hono RPC
|
|
53
|
-
|
|
54
|
-
RPC-style HTTP integration for Hono with the same routing pattern as Express RPC. Works with Bun, Deno, Cloudflare Workers, and Node.js.
|
|
55
|
-
|
|
56
|
-
```typescript
|
|
57
|
-
import { HonoRPCAppBuilder, RPCConfig } from 'ts-procedures/hono-rpc'
|
|
20
|
+
import { Procedures } from 'ts-procedures'
|
|
21
|
+
import { HonoAppBuilder } from 'ts-procedures/hono'
|
|
22
|
+
import type { RPCConfig } from 'ts-procedures/http'
|
|
23
|
+
import { Type } from 'typebox'
|
|
58
24
|
|
|
59
|
-
|
|
25
|
+
type AppContext = { userId: string }
|
|
26
|
+
const procs = Procedures<AppContext, RPCConfig>()
|
|
60
27
|
|
|
61
|
-
RPC
|
|
28
|
+
// 1. RPC procedure (Create) — POST /rpc/users/profile/get-user/1
|
|
29
|
+
procs.Create('GetUser', {
|
|
62
30
|
scope: ['users', 'profile'],
|
|
63
31
|
version: 1,
|
|
64
32
|
schema: { params: Type.Object({ id: Type.String() }) },
|
|
65
|
-
}, async (ctx, params) => {
|
|
66
|
-
return { id: params.id, name: 'John Doe' }
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
const app = new HonoRPCAppBuilder({ pathPrefix: '/rpc' })
|
|
70
|
-
.register(RPC, (c) => ({ userId: c.req.header('x-user-id') || 'anonymous' }))
|
|
71
|
-
.build()
|
|
72
|
-
|
|
73
|
-
// POST /rpc/users/profile/get-user/1
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
See the [Hono RPC Integration Guide](../src/implementations/http/hono-rpc/README.md) for complete setup including context resolution, doc extension, abort signal, error handling, and runtime compatibility.
|
|
77
|
-
|
|
78
|
-
## Hono Stream
|
|
33
|
+
}, async (ctx, params) => ({ id: params.id, name: 'John Doe' }))
|
|
79
34
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
import { HonoStreamAppBuilder } from 'ts-procedures/hono-stream'
|
|
84
|
-
|
|
85
|
-
const StreamRPC = Procedures<AppContext, RPCConfig>()
|
|
86
|
-
|
|
87
|
-
StreamRPC.CreateStream('WatchNotifications', {
|
|
35
|
+
// 2. RPC stream (CreateStream) — GET/POST /rpc/user/notifications/watch-notifications/1
|
|
36
|
+
procs.CreateStream('WatchNotifications', {
|
|
88
37
|
scope: ['user', 'notifications'],
|
|
89
38
|
version: 1,
|
|
90
39
|
schema: { yieldType: Type.Object({ id: Type.Number(), message: Type.String() }) },
|
|
@@ -95,60 +44,43 @@ StreamRPC.CreateStream('WatchNotifications', {
|
|
|
95
44
|
}
|
|
96
45
|
})
|
|
97
46
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
.build()
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
See the [Hono Stream Integration Guide](../src/implementations/http/hono-stream/README.md) for complete setup including SSE/text modes, the `sse()` helper, validation, error handling, and migration notes.
|
|
104
|
-
|
|
105
|
-
## Hono API Integration
|
|
106
|
-
|
|
107
|
-
REST-style HTTP integration for Hono that routes by HTTP method with per-channel input validation via `schema.input`.
|
|
108
|
-
|
|
109
|
-
```typescript
|
|
110
|
-
import { Procedures } from 'ts-procedures'
|
|
111
|
-
import { HonoAPIAppBuilder } from 'ts-procedures/hono-api'
|
|
112
|
-
import type { APIConfig } from 'ts-procedures/http'
|
|
113
|
-
import { Type } from 'typebox'
|
|
114
|
-
|
|
115
|
-
const API = Procedures<{ userId: string }, APIConfig>()
|
|
116
|
-
|
|
117
|
-
API.Create('GetUser', {
|
|
47
|
+
// 3. REST procedure (CreateHttp) — GET /rpc/users/:id
|
|
48
|
+
procs.CreateHttp('GetUserRest', {
|
|
118
49
|
path: '/users/:id',
|
|
119
50
|
method: 'get',
|
|
51
|
+
scope: 'users',
|
|
120
52
|
schema: {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
},
|
|
124
|
-
returnType: Type.Object({ id: Type.String(), name: Type.String() }),
|
|
53
|
+
req: { pathParams: Type.Object({ id: Type.String() }) },
|
|
54
|
+
res: { body: Type.Object({ id: Type.String(), name: Type.String() }) },
|
|
125
55
|
},
|
|
126
|
-
}, async (ctx, { pathParams }) =>
|
|
127
|
-
return await fetchUser(pathParams.id)
|
|
128
|
-
})
|
|
56
|
+
}, async (ctx, { pathParams }) => fetchUser(pathParams.id))
|
|
129
57
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
58
|
+
// 4. REST stream (CreateHttpStream) — GET /rpc/streams/logs
|
|
59
|
+
procs.CreateHttpStream('TailLogs', {
|
|
60
|
+
path: '/streams/logs',
|
|
61
|
+
method: 'get',
|
|
62
|
+
scope: 'streams',
|
|
133
63
|
schema: {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
},
|
|
64
|
+
req: { query: Type.Object({ source: Type.String() }) },
|
|
65
|
+
yield: Type.Object({ line: Type.String() }),
|
|
137
66
|
},
|
|
138
|
-
}, async (ctx, {
|
|
139
|
-
|
|
67
|
+
}, async function* (ctx, { query }) {
|
|
68
|
+
for await (const line of tail(query.source)) yield { line }
|
|
140
69
|
})
|
|
141
70
|
|
|
142
|
-
const app = new
|
|
143
|
-
|
|
71
|
+
const app = new HonoAppBuilder({
|
|
72
|
+
pathPrefix: '/rpc',
|
|
73
|
+
rpc: { onSuccess: (proc, c) => log.info(`[rpc] ${proc.name}`) },
|
|
74
|
+
api: { onSuccess: (proc, c) => log.info(`[api] ${proc.name}`) },
|
|
75
|
+
stream: { defaultStreamMode: 'sse' },
|
|
76
|
+
})
|
|
77
|
+
.register(procs, (c) => ({ userId: c.req.header('x-user-id') || 'anonymous' }))
|
|
144
78
|
.build()
|
|
145
|
-
|
|
146
|
-
// Routes:
|
|
147
|
-
// GET /api/users/:id -> 200
|
|
148
|
-
// POST /api/users -> 201
|
|
149
79
|
```
|
|
150
80
|
|
|
151
|
-
|
|
81
|
+
`HonoAppBuilder`'s config is **stratified** — kind-specific knobs (`onSuccess`, `queryParser`, `defaultStreamMode`, `onStreamStart`, `onStreamEnd`, `onMidStreamError`) live inside the matching `rpc:` / `api:` / `stream:` block. Cross-cutting hooks (`onRequestStart`, `onRequestEnd`, `onRequestError`, `errors`, `unknownError`, `onError`) stay at the top level.
|
|
82
|
+
|
|
83
|
+
For the full surface — config interfaces, path generation, context resolution, abort signal, lifecycle hooks, route doc shapes — see the [HTTP implementations overview](../src/implementations/http/README.md).
|
|
152
84
|
|
|
153
85
|
## Error Handling
|
|
154
86
|
|
|
@@ -165,7 +97,7 @@ Both modes also expose `onRequestError` — a cross-cutting observer for logging
|
|
|
165
97
|
|
|
166
98
|
```typescript
|
|
167
99
|
import { defineErrorTaxonomy } from 'ts-procedures/http-errors'
|
|
168
|
-
import {
|
|
100
|
+
import { HonoAppBuilder } from 'ts-procedures/hono'
|
|
169
101
|
|
|
170
102
|
class UseCaseError extends Error {
|
|
171
103
|
constructor(readonly externalMsg: string, readonly internalMsg: string) {
|
|
@@ -190,40 +122,34 @@ const appErrors = defineErrorTaxonomy({
|
|
|
190
122
|
},
|
|
191
123
|
})
|
|
192
124
|
|
|
193
|
-
new
|
|
125
|
+
new HonoAppBuilder({
|
|
194
126
|
errors: appErrors,
|
|
195
127
|
unknownError: {
|
|
196
128
|
statusCode: 500,
|
|
197
129
|
toResponse: () => ({ name: 'InternalServerError', message: 'Unexpected error' }),
|
|
198
130
|
onCatch: (err, { procedure }) => logger.error({ procedure: procedure.name, err }),
|
|
199
131
|
},
|
|
200
|
-
}).register(
|
|
132
|
+
}).register(procs, /* ... */).build()
|
|
201
133
|
```
|
|
202
134
|
|
|
203
|
-
|
|
135
|
+
For streaming procedures the taxonomy covers the pre-stream path only; mid-stream errors are handled via `stream.onMidStreamError`.
|
|
204
136
|
|
|
205
137
|
### Imperative — the `onError` callback
|
|
206
138
|
|
|
207
139
|
For apps that don't need typed client dispatch or declarative docs, configure `onError` directly and handle every error in one place:
|
|
208
140
|
|
|
209
141
|
```typescript
|
|
210
|
-
new
|
|
142
|
+
new HonoAppBuilder({
|
|
211
143
|
onError: (procedure, c, error) => {
|
|
212
144
|
logger.error(`[${procedure.name}]`, error)
|
|
213
145
|
return c.json({ error: error.message ?? 'unknown error' }, 500)
|
|
214
146
|
},
|
|
215
|
-
}).register(
|
|
147
|
+
}).register(procs, /* ... */).build()
|
|
216
148
|
```
|
|
217
149
|
|
|
218
150
|
(Need to route different error classes to different status codes? Use the taxonomy — that's exactly what it's designed for. Hand-writing `instanceof` ladders inside `onError` is [anti-pattern #20](../agent_config/claude-code/skills/ts-procedures/anti-patterns.md).)
|
|
219
151
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
| Builder | `onError` signature |
|
|
223
|
-
|---|---|
|
|
224
|
-
| `HonoAPIAppBuilder`, `HonoRPCAppBuilder` | `(procedure, c: Context, error) => Response \| Promise<Response>` |
|
|
225
|
-
| `ExpressRPCAppBuilder` | `(procedure, req, res, error) => void` (write to `res`) |
|
|
226
|
-
| `HonoStreamAppBuilder` | `(procedure, c: Context, error) => Response \| Promise<Response>` — pre-stream only |
|
|
152
|
+
`HonoAppBuilder`'s `onError` signature: `(procedure, c: Context, error) => Response | Promise<Response>` — for streaming procedures, pre-stream only.
|
|
227
153
|
|
|
228
154
|
Picking between modes isn't irreversible: you can start with `onError`, migrate chunks to the taxonomy as your error model stabilizes, and leave the rest in `onError`. Both modes coexist in the dispatch order below.
|
|
229
155
|
|
|
@@ -232,27 +158,27 @@ Picking between modes isn't irreversible: you can start with `onError`, migrate
|
|
|
232
158
|
`APIConfig` and `RPCConfig` are generic over a `TErrorKey extends string` parameter so you can declare which errors a specific route may emit:
|
|
233
159
|
|
|
234
160
|
```typescript
|
|
235
|
-
|
|
161
|
+
const procs = Procedures<Ctx>()
|
|
162
|
+
type ErrorKey = keyof typeof appErrors & string
|
|
236
163
|
|
|
237
|
-
|
|
238
|
-
const API = Procedures<Ctx, MyAPIConfig>()
|
|
239
|
-
|
|
240
|
-
API.Create('GetUser', {
|
|
164
|
+
procs.CreateHttp('GetUser', {
|
|
241
165
|
path: '/users/:id',
|
|
242
166
|
method: 'get',
|
|
243
|
-
errors: ['UseCaseError'], // typo-checked against the taxonomy keys
|
|
167
|
+
errors: ['UseCaseError'] satisfies ErrorKey[], // typo-checked against the taxonomy keys
|
|
244
168
|
schema: { /* ... */ },
|
|
245
169
|
}, /* handler */)
|
|
246
170
|
```
|
|
247
171
|
|
|
248
172
|
These per-route declarations flow into the DocEnvelope and drive typed `catch` blocks on generated clients — see [Client & Codegen → Typed Error Handling](./client-and-codegen.md#typed-error-handling).
|
|
249
173
|
|
|
174
|
+
**Tip:** if a factory exclusively contains HTTP procedures, prefer the factory-level generic form `Procedures<Ctx, APIConfig<keyof typeof appErrors & string>>()` — it bakes the typo-checked error keys into every route on that factory so individual `errors: [...] satisfies ErrorKey[]` annotations are no longer needed. The per-route `satisfies` form above is the right pick when a single factory mixes HTTP procedures with other config shapes.
|
|
175
|
+
|
|
250
176
|
### Cross-cutting observability — `onRequestError`
|
|
251
177
|
|
|
252
178
|
`onRequestError` fires for every caught error, **before** dispatch. It's an observer — it can't mutate the response. Use it for APM, distributed tracing, custom logging, or metrics where you want one hook that sees every error regardless of which mode dispatched it.
|
|
253
179
|
|
|
254
180
|
```typescript
|
|
255
|
-
new
|
|
181
|
+
new HonoAppBuilder({
|
|
256
182
|
errors: appErrors,
|
|
257
183
|
onRequestError: async ({ err, procedure, raw }) => {
|
|
258
184
|
sentry.captureException(err, { procedure: procedure.name })
|
|
@@ -271,41 +197,19 @@ The observer is awaited before the response is sent, and any error it throws is
|
|
|
271
197
|
|
|
272
198
|
Configuring only the taxonomy, only `onError`, both, or neither are all valid. When neither is configured the builder goes straight from step 1 to step 4.
|
|
273
199
|
|
|
274
|
-
##
|
|
200
|
+
## DocRegistry — Composing Docs
|
|
275
201
|
|
|
276
|
-
|
|
202
|
+
For a single-builder app, the simplest path is `builder.toDocEnvelope({ basePath, errors })` — it wraps `DocRegistry` for you and produces the same envelope shape:
|
|
277
203
|
|
|
278
204
|
```typescript
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
import { HonoStreamAppBuilder } from 'ts-procedures/hono-stream'
|
|
283
|
-
import { DocRegistry } from 'ts-procedures/http-docs'
|
|
284
|
-
|
|
285
|
-
const app = new Hono()
|
|
286
|
-
|
|
287
|
-
const rpcBuilder = new HonoRPCAppBuilder({ app, pathPrefix: '/rpc' })
|
|
288
|
-
.register(RPC, ctxResolver)
|
|
289
|
-
const apiBuilder = new HonoAPIAppBuilder({ app, pathPrefix: '/api' })
|
|
290
|
-
.register(API, ctxResolver)
|
|
291
|
-
const streamBuilder = new HonoStreamAppBuilder({ app })
|
|
292
|
-
.register(Stream, ctxResolver)
|
|
205
|
+
const builder = new HonoAppBuilder({ pathPrefix: '/api', errors: appErrors })
|
|
206
|
+
.register(procs, ctxResolver)
|
|
207
|
+
const app = builder.build()
|
|
293
208
|
|
|
294
|
-
|
|
295
|
-
apiBuilder.build()
|
|
296
|
-
streamBuilder.build()
|
|
297
|
-
|
|
298
|
-
const docs = new DocRegistry().from(rpcBuilder).from(apiBuilder).from(streamBuilder)
|
|
299
|
-
app.get('/docs', (c) => c.json(docs.toJSON()))
|
|
209
|
+
app.get('/docs', (c) => c.json(builder.toDocEnvelope()))
|
|
300
210
|
```
|
|
301
211
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
If you omit `app`, each builder constructs its own internal `Hono` instance — useful when you really do want isolated apps (multi-tenant routing, separate ports, etc.).
|
|
305
|
-
|
|
306
|
-
## DocRegistry — Composing Docs from Multiple Builders
|
|
307
|
-
|
|
308
|
-
Use `DocRegistry` to compose route documentation from any combination of HTTP builders into a typed envelope:
|
|
212
|
+
For multi-app aggregation — e.g., two `HonoAppBuilder` instances mounted under different prefixes — use `DocRegistry` directly:
|
|
309
213
|
|
|
310
214
|
```typescript
|
|
311
215
|
import { DocRegistry } from 'ts-procedures/http-docs'
|
|
@@ -315,9 +219,8 @@ const docs = new DocRegistry({
|
|
|
315
219
|
headers: [{ name: 'Authorization', description: 'Bearer token', required: false }],
|
|
316
220
|
errors: appErrors, // your ErrorTaxonomy — auto-converted to ErrorDocs, framework defaults merged
|
|
317
221
|
})
|
|
318
|
-
.from(
|
|
319
|
-
.from(
|
|
320
|
-
.from(streamBuilder)
|
|
222
|
+
.from(publicBuilder)
|
|
223
|
+
.from(adminBuilder)
|
|
321
224
|
|
|
322
225
|
app.get('/docs', (c) => c.json(docs.toJSON()))
|
|
323
226
|
```
|
|
@@ -328,7 +231,7 @@ For errors that aren't in your taxonomy (middleware-level, infrastructure, doc-o
|
|
|
328
231
|
|
|
329
232
|
```typescript
|
|
330
233
|
const docs = new DocRegistry({ errors: appErrors, basePath: '/api' })
|
|
331
|
-
.from(
|
|
234
|
+
.from(honoBuilder)
|
|
332
235
|
.documentError({ name: 'RateLimitExceeded', statusCode: 429, description: 'too many requests' })
|
|
333
236
|
```
|
|
334
237
|
|
|
@@ -339,10 +242,20 @@ The `DocRegistry` output is the input for [Client Code Generation](./client-and-
|
|
|
339
242
|
## Type Exports
|
|
340
243
|
|
|
341
244
|
```typescript
|
|
342
|
-
// HTTP types
|
|
343
|
-
import type {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
245
|
+
// Shared HTTP types
|
|
246
|
+
import type {
|
|
247
|
+
RPCConfig,
|
|
248
|
+
RPCHttpRouteDoc,
|
|
249
|
+
StreamHttpRouteDoc,
|
|
250
|
+
HttpStreamRouteDoc,
|
|
251
|
+
StreamMode,
|
|
252
|
+
APIConfig,
|
|
253
|
+
APIHttpRouteDoc,
|
|
254
|
+
APIInput,
|
|
255
|
+
HttpMethod,
|
|
256
|
+
} from 'ts-procedures/http'
|
|
257
|
+
|
|
258
|
+
// Hono builder + Hono-specific types
|
|
259
|
+
import { HonoAppBuilder } from 'ts-procedures/hono'
|
|
260
|
+
import type { HonoAppBuilderConfig, QueryParser, OnRequestErrorContext, ExtendProcedureDoc } from 'ts-procedures/hono'
|
|
348
261
|
```
|
package/docs/streaming.md
CHANGED
|
@@ -105,72 +105,15 @@ for await (const item of CancellableStream({}, {})) {
|
|
|
105
105
|
}
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
## SSE Integration
|
|
108
|
+
## SSE Integration
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
import express from 'express'
|
|
112
|
-
import { Procedures } from 'ts-procedures'
|
|
113
|
-
|
|
114
|
-
const app = express()
|
|
115
|
-
|
|
116
|
-
const { CreateStream, getProcedures } = Procedures<{ req: express.Request }>({
|
|
117
|
-
onCreate: (proc) => {
|
|
118
|
-
if (proc.isStream) {
|
|
119
|
-
// Register streaming procedures as SSE endpoints
|
|
120
|
-
app.get(`/stream/${proc.name}`, async (req, res) => {
|
|
121
|
-
res.writeHead(200, {
|
|
122
|
-
'Content-Type': 'text/event-stream',
|
|
123
|
-
'Cache-Control': 'no-cache',
|
|
124
|
-
'Connection': 'keep-alive',
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
const generator = proc.handler({ req }, req.query)
|
|
128
|
-
|
|
129
|
-
req.on('close', async () => {
|
|
130
|
-
// Client disconnected - stop the generator
|
|
131
|
-
await generator.return(undefined)
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
try {
|
|
135
|
-
for await (const data of generator) {
|
|
136
|
-
res.write(`data: ${JSON.stringify(data)}\n\n`)
|
|
137
|
-
}
|
|
138
|
-
} finally {
|
|
139
|
-
res.end()
|
|
140
|
-
}
|
|
141
|
-
})
|
|
142
|
-
}
|
|
143
|
-
},
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
// Define a streaming procedure
|
|
147
|
-
CreateStream(
|
|
148
|
-
'LiveFeed',
|
|
149
|
-
{
|
|
150
|
-
schema: {
|
|
151
|
-
params: Type.Object({ channel: Type.String() }),
|
|
152
|
-
yieldType: Type.Object({ event: Type.String(), data: Type.Any() }),
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
async function* (ctx, params) {
|
|
156
|
-
while (!ctx.signal.aborted) {
|
|
157
|
-
const event = await pollForEvent(params.channel)
|
|
158
|
-
yield event
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
app.listen(3000)
|
|
164
|
-
// SSE endpoint: GET /stream/LiveFeed?channel=updates
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
For the built-in Hono streaming integration, see the [Hono Stream README](../src/implementations/http/hono-stream/README.md).
|
|
110
|
+
For the built-in Hono streaming integration, see [HTTP Integrations](./http-integrations.md). `HonoAppBuilder` dispatches `CreateStream` and `CreateHttpStream` procedures as SSE or text streams from the same `register()` call as your RPC and REST routes.
|
|
168
111
|
|
|
169
112
|
## Stream Errors
|
|
170
113
|
|
|
171
114
|
Streaming procedures support the same error handling as regular procedures (see [Error Handling](./core.md#error-handling)).
|
|
172
115
|
|
|
173
|
-
For HTTP stream endpoints, pre-stream errors (validation, context resolution, anything thrown before the first yield) go through the same two peer error-handling modes as every other HTTP builder — either the declarative `errors` / `unknownError` taxonomy (from `defineErrorTaxonomy`) or the imperative `onError` callback on `
|
|
116
|
+
For HTTP stream endpoints, pre-stream errors (validation, context resolution, anything thrown before the first yield) go through the same two peer error-handling modes as every other HTTP builder — either the declarative `errors` / `unknownError` taxonomy (from `defineErrorTaxonomy`) or the imperative `onError` callback on `HonoAppBuilder`. Cross-cutting `onRequestError` observer fires for every pre-stream error. See [HTTP Integrations → Error Handling](./http-integrations.md#error-handling) for the full contract. Mid-stream errors (thrown after the first yield) still flow through `onMidStreamError` and are surfaced to the client as SSE error events — the HTTP status is already committed once streaming begins, so mid-stream is outside the peer error modes.
|
|
174
117
|
|
|
175
118
|
```typescript
|
|
176
119
|
const { StreamWithErrors } = CreateStream(
|
|
@@ -60,7 +60,6 @@ Open `package.json` and confirm both:
|
|
|
60
60
|
"optionalDependencies": {
|
|
61
61
|
"ajsc": "7.2.0",
|
|
62
62
|
"astro": "^5.0.0",
|
|
63
|
-
"express": "^5.2.1",
|
|
64
63
|
"hono": "^4.7.4"
|
|
65
64
|
},
|
|
66
65
|
"devDependencies": {
|
|
@@ -990,7 +989,6 @@ Dispatch rules:
|
|
|
990
989
|
|
|
991
990
|
## What's NOT included
|
|
992
991
|
|
|
993
|
-
- Express RPC support (Express uses Node `req`/`res`, not Web Fetch).
|
|
994
992
|
- DocRegistry coupling — wire `DocRegistry` against the same builders separately for client codegen.
|
|
995
993
|
````
|
|
996
994
|
|
|
@@ -1253,7 +1251,7 @@ Multi-app: pass an array; first non-404 response wins. All-404 falls back to the
|
|
|
1253
1251
|
|
|
1254
1252
|
Constraints:
|
|
1255
1253
|
- Astro 5+ in SSR (or `prerender = false`).
|
|
1256
|
-
-
|
|
1254
|
+
- Hono builders only — the adapter accepts `Request`/`Response` apps.
|
|
1257
1255
|
````
|
|
1258
1256
|
|
|
1259
1257
|
- [ ] **Step 3: Update patterns.md**
|
|
@@ -1270,8 +1268,6 @@ When a downstream developer is building inside an Astro app, recommend the catch
|
|
|
1270
1268
|
3. Mount the built app(s) in a single catch-all file: `src/pages/api/[...rest].ts`. Use `pathPrefix: '/api'` so your Hono routes don't need to repeat the prefix.
|
|
1271
1269
|
|
|
1272
1270
|
Anti-pattern: don't create one Astro file per procedure — that loses the centralized factory wiring and forces the developer to repeat the context closure.
|
|
1273
|
-
|
|
1274
|
-
Anti-pattern: don't try to use `express-rpc` with the Astro adapter. The adapter only accepts Web-Fetch apps (Hono).
|
|
1275
1271
|
````
|
|
1276
1272
|
|
|
1277
1273
|
- [ ] **Step 4: Mirror the same content into Copilot and Cursor rules**
|
|
@@ -1283,7 +1279,7 @@ In each file, locate the existing builders section and append (verbatim — same
|
|
|
1283
1279
|
```markdown
|
|
1284
1280
|
## Astro adapter
|
|
1285
1281
|
|
|
1286
|
-
Catch-all endpoint pattern. Build Hono apps once with HonoAPI/RPC/Stream builders, mount via `createAstroHandler` in `src/pages/api/[...rest].ts` with `pathPrefix: '/api'`. Read Astro context inside factory closures with `getAstroContext(c)`. Multi-app dispatch is first-non-404-wins.
|
|
1282
|
+
Catch-all endpoint pattern. Build Hono apps once with HonoAPI/RPC/Stream builders, mount via `createAstroHandler` in `src/pages/api/[...rest].ts` with `pathPrefix: '/api'`. Read Astro context inside factory closures with `getAstroContext(c)`. Multi-app dispatch is first-non-404-wins.
|
|
1287
1283
|
```
|
|
1288
1284
|
|
|
1289
1285
|
- [ ] **Step 5: Run the docs-consistency check**
|
|
@@ -1388,7 +1384,6 @@ If nothing changed, skip this step.
|
|
|
1388
1384
|
- `stripPrefix(request, prefix)` — defined Task 2, called Task 4. Same signature.
|
|
1389
1385
|
|
|
1390
1386
|
**Out-of-scope items confirmed not in plan:**
|
|
1391
|
-
- Express adapter — explicitly excluded
|
|
1392
1387
|
- Native Astro builders — explicitly excluded
|
|
1393
1388
|
- DocRegistry coupling — wired separately in walkthrough (Task 10), not in adapter
|
|
1394
1389
|
- `dispatch: 'merge'` knob — not introduced
|