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
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Hono Template: {{Name}}
|
|
2
|
+
|
|
3
|
+
A single `HonoAppBuilder` can host all four procedure kinds — RPC (`Create`), RPC stream (`CreateStream`), HTTP REST (`CreateHttp`), and HTTP stream (`CreateHttpStream`) — registered against one `Procedures` factory and mounted with one `register(...)` call. This template demonstrates that.
|
|
4
|
+
|
|
5
|
+
## Implementation — `{{Name}}.hono.ts`
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { Procedures } from 'ts-procedures'
|
|
9
|
+
import type { RPCConfig } from 'ts-procedures/http'
|
|
10
|
+
import { defineErrorTaxonomy, HonoAppBuilder } from 'ts-procedures/hono'
|
|
11
|
+
import { Type } from 'typebox'
|
|
12
|
+
|
|
13
|
+
// ─── Context ──────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
type {{Name}}Context = {
|
|
16
|
+
userId: string
|
|
17
|
+
requestId: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ─── Procedures ───────────────────────────────────────────
|
|
21
|
+
// Capture the factory in a single `procs` variable so every kind shares
|
|
22
|
+
// the same context type and the same final register() call.
|
|
23
|
+
|
|
24
|
+
const procs = Procedures<{{Name}}Context, RPCConfig>()
|
|
25
|
+
|
|
26
|
+
// RPC — `Create`. Mounted at POST /api/{{kebab}}/get-item/1
|
|
27
|
+
export const { GetItem } = procs.Create(
|
|
28
|
+
'GetItem',
|
|
29
|
+
{
|
|
30
|
+
scope: '{{kebab}}',
|
|
31
|
+
version: 1,
|
|
32
|
+
description: 'Fetch an item by id (RPC).',
|
|
33
|
+
schema: {
|
|
34
|
+
params: Type.Object({
|
|
35
|
+
id: Type.String(),
|
|
36
|
+
}),
|
|
37
|
+
returnType: Type.Object({
|
|
38
|
+
id: Type.String(),
|
|
39
|
+
name: Type.String(),
|
|
40
|
+
}),
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
async (ctx, params) => {
|
|
44
|
+
// TODO: implement
|
|
45
|
+
return { id: params.id, name: 'Example' }
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
// RPC stream — `CreateStream`. Mounted at POST /api/{{kebab}}/stream-events/1 (SSE)
|
|
50
|
+
export const { StreamEvents } = procs.CreateStream(
|
|
51
|
+
'StreamEvents',
|
|
52
|
+
{
|
|
53
|
+
scope: '{{kebab}}',
|
|
54
|
+
version: 1,
|
|
55
|
+
description: 'Stream events for the given subject (rpc-stream / SSE).',
|
|
56
|
+
schema: {
|
|
57
|
+
params: Type.Object({
|
|
58
|
+
subject: Type.String(),
|
|
59
|
+
}),
|
|
60
|
+
yieldType: Type.Object({
|
|
61
|
+
seq: Type.Number(),
|
|
62
|
+
message: Type.String(),
|
|
63
|
+
}),
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
async function* (ctx, params) {
|
|
67
|
+
// ctx.signal is guaranteed for streams. Pass it to all downstream async work.
|
|
68
|
+
for (let seq = 0; seq < 3; seq++) {
|
|
69
|
+
if (ctx.signal.aborted) return
|
|
70
|
+
yield { seq, message: `event-${params.subject}-${seq}` }
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
// HTTP REST — `CreateHttp`. Mounted at GET /api/{{kebab}}/:id
|
|
76
|
+
export const { GetUser } = procs.CreateHttp(
|
|
77
|
+
'GetUser',
|
|
78
|
+
{
|
|
79
|
+
path: '/{{kebab}}/:id',
|
|
80
|
+
method: 'get',
|
|
81
|
+
description: 'Fetch a user (REST).',
|
|
82
|
+
schema: {
|
|
83
|
+
req: {
|
|
84
|
+
pathParams: Type.Object({ id: Type.String() }),
|
|
85
|
+
},
|
|
86
|
+
res: {
|
|
87
|
+
body: Type.Object({
|
|
88
|
+
id: Type.String(),
|
|
89
|
+
name: Type.String(),
|
|
90
|
+
}),
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
async (ctx, { pathParams }) => {
|
|
95
|
+
// TODO: implement
|
|
96
|
+
return { id: pathParams.id, name: 'Example' }
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
// HTTP stream — `CreateHttpStream`. Mounted at GET /api/{{kebab}}/:id/watch (text/event-stream)
|
|
101
|
+
export const { WatchUser } = procs.CreateHttpStream(
|
|
102
|
+
'WatchUser',
|
|
103
|
+
{
|
|
104
|
+
path: '/{{kebab}}/:id/watch',
|
|
105
|
+
method: 'get',
|
|
106
|
+
description: 'Server-sent stream of user updates (http-stream).',
|
|
107
|
+
schema: {
|
|
108
|
+
req: {
|
|
109
|
+
pathParams: Type.Object({ id: Type.String() }),
|
|
110
|
+
},
|
|
111
|
+
yield: Type.Object({
|
|
112
|
+
id: Type.String(),
|
|
113
|
+
revision: Type.Number(),
|
|
114
|
+
}),
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
async function* (ctx, { pathParams }) {
|
|
118
|
+
for (let revision = 1; revision <= 3; revision++) {
|
|
119
|
+
if (ctx.signal.aborted) return
|
|
120
|
+
yield { id: pathParams.id, revision }
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
// ─── Error Taxonomy ───────────────────────────────────────
|
|
126
|
+
// Declare the error classes this service throws. Framework errors
|
|
127
|
+
// (ProcedureValidationError → 400, ctx.error() → 500) are caught by the
|
|
128
|
+
// default taxonomy automatically. Add your own classes here — handlers just
|
|
129
|
+
// `throw` them and the builder serializes via this map. See
|
|
130
|
+
// docs/http-integrations.md#error-handling for the full contract.
|
|
131
|
+
|
|
132
|
+
const {{name}}Errors = defineErrorTaxonomy({
|
|
133
|
+
// Example — replace with your app's error classes:
|
|
134
|
+
// NotFoundError: { class: NotFoundError, statusCode: 404 },
|
|
135
|
+
// AuthError: { class: AuthError, statusCode: 401 },
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
// ─── Hono App Builder ─────────────────────────────────────
|
|
139
|
+
// One builder, one register() call, all four kinds. Config is stratified by
|
|
140
|
+
// kind: rpc.{onSuccess}, api.{queryParser, onSuccess}, stream.{...}. Cross-cutting
|
|
141
|
+
// concerns (errors, unknownError, onError, onRequestError, onRequestStart/End,
|
|
142
|
+
// pathPrefix) live at the top level. See src/implementations/http/hono/types.ts.
|
|
143
|
+
|
|
144
|
+
// Optional observers (uncomment as needed):
|
|
145
|
+
// onRequestStart: (c) => {...} // every inbound request (all kinds)
|
|
146
|
+
// rpc: { onSuccess: (procedure, c) => {...} } // successful RPC (Create) responses
|
|
147
|
+
// api: { onSuccess: (procedure, c) => {...} } // successful REST (CreateHttp) responses
|
|
148
|
+
// stream: { onStreamStart: (procedure, c, mode) => {...}, onStreamEnd: (procedure, c, mode) => {...} }
|
|
149
|
+
|
|
150
|
+
const {{name}}Builder = new HonoAppBuilder({
|
|
151
|
+
pathPrefix: '/api',
|
|
152
|
+
errors: {{name}}Errors,
|
|
153
|
+
unknownError: {
|
|
154
|
+
statusCode: 500,
|
|
155
|
+
toResponse: () => ({ name: 'InternalServerError', message: 'Unexpected error' }),
|
|
156
|
+
onCatch: (err, { procedure }) => console.error(`[${procedure.name}]`, err),
|
|
157
|
+
},
|
|
158
|
+
})
|
|
159
|
+
.register(procs, (c) => ({
|
|
160
|
+
userId: c.req.header('x-user-id') || 'anonymous',
|
|
161
|
+
requestId: c.req.header('x-request-id') || crypto.randomUUID(),
|
|
162
|
+
}))
|
|
163
|
+
|
|
164
|
+
export const {{name}}App = {{name}}Builder.build()
|
|
165
|
+
|
|
166
|
+
// Route map:
|
|
167
|
+
// POST /api/{{kebab}}/get-item/1 → RPC (Create)
|
|
168
|
+
// POST /api/{{kebab}}/stream-events/1 → RPC stream (CreateStream, SSE)
|
|
169
|
+
// GET /api/{{kebab}}/:id → REST (CreateHttp)
|
|
170
|
+
// GET /api/{{kebab}}/:id/watch → HTTP stream (CreateHttpStream, SSE)
|
|
171
|
+
|
|
172
|
+
// Documentation: {{name}}Builder.docs or {{name}}Builder.toDocEnvelope()
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Test — `{{Name}}.hono.test.ts`
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
import { describe, test, expect } from 'vitest'
|
|
179
|
+
import { {{name}}App } from './{{Name}}.hono'
|
|
180
|
+
|
|
181
|
+
describe('{{Name}} Hono — all four kinds', () => {
|
|
182
|
+
test('Create (RPC) — POST /api/{{kebab}}/get-item/1', async () => {
|
|
183
|
+
const res = await {{name}}App.request('/api/{{kebab}}/get-item/1', {
|
|
184
|
+
method: 'POST',
|
|
185
|
+
headers: { 'Content-Type': 'application/json' },
|
|
186
|
+
body: JSON.stringify({ id: 'item-1' }),
|
|
187
|
+
})
|
|
188
|
+
expect(res.status).toBe(200)
|
|
189
|
+
expect(await res.json()).toEqual({ id: 'item-1', name: 'Example' })
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
test('CreateStream (rpc-stream) — POST /api/{{kebab}}/stream-events/1 yields SSE', async () => {
|
|
193
|
+
const res = await {{name}}App.request('/api/{{kebab}}/stream-events/1', {
|
|
194
|
+
method: 'POST',
|
|
195
|
+
headers: { 'Content-Type': 'application/json' },
|
|
196
|
+
body: JSON.stringify({ subject: 'orders' }),
|
|
197
|
+
})
|
|
198
|
+
expect(res.status).toBe(200)
|
|
199
|
+
expect(res.headers.get('content-type') ?? '').toContain('text/event-stream')
|
|
200
|
+
|
|
201
|
+
const text = await res.text()
|
|
202
|
+
// Yielded events are emitted as SSE `data:` frames.
|
|
203
|
+
expect(text).toContain('event-orders-0')
|
|
204
|
+
expect(text).toContain('event-orders-2')
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
test('CreateHttp (REST) — GET /api/{{kebab}}/:id', async () => {
|
|
208
|
+
const res = await {{name}}App.request('/api/{{kebab}}/u-1')
|
|
209
|
+
expect(res.status).toBe(200)
|
|
210
|
+
expect(await res.json()).toEqual({ id: 'u-1', name: 'Example' })
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
test('CreateHttpStream (http-stream) — GET /api/{{kebab}}/:id/watch yields SSE', async () => {
|
|
214
|
+
const res = await {{name}}App.request('/api/{{kebab}}/u-1/watch')
|
|
215
|
+
expect(res.status).toBe(200)
|
|
216
|
+
expect(res.headers.get('content-type') ?? '').toContain('text/event-stream')
|
|
217
|
+
|
|
218
|
+
const text = await res.text()
|
|
219
|
+
expect(text).toContain('"revision":1')
|
|
220
|
+
expect(text).toContain('"revision":3')
|
|
221
|
+
})
|
|
222
|
+
})
|
|
223
|
+
```
|
|
@@ -26,18 +26,15 @@ import { ProcedureError, ProcedureValidationError, ProcedureYieldValidationError
|
|
|
26
26
|
// HTTP types
|
|
27
27
|
import type { RPCConfig, RPCHttpRouteDoc, StreamHttpRouteDoc, StreamMode } from 'ts-procedures/http'
|
|
28
28
|
|
|
29
|
-
// Express RPC
|
|
30
|
-
import { ExpressRPCAppBuilder } from 'ts-procedures/express-rpc'
|
|
31
|
-
|
|
32
29
|
// Hono RPC
|
|
33
|
-
import {
|
|
30
|
+
import { HonoAppBuilder } from 'ts-procedures/hono'
|
|
34
31
|
|
|
35
32
|
// Hono Streaming
|
|
36
|
-
import {
|
|
33
|
+
import { HonoAppBuilder, sse } from 'ts-procedures/hono'
|
|
37
34
|
|
|
38
35
|
// Hono API (REST-style)
|
|
39
|
-
import {
|
|
40
|
-
import type { APIConfig, APIInput } from 'ts-procedures/hono
|
|
36
|
+
import { HonoAppBuilder } from 'ts-procedures/hono'
|
|
37
|
+
import type { APIConfig, APIInput } from 'ts-procedures/hono'
|
|
41
38
|
|
|
42
39
|
// Doc Registry — compose route docs from multiple builders
|
|
43
40
|
import { DocRegistry } from 'ts-procedures/http-docs'
|
|
@@ -62,6 +59,8 @@ import type { DocEnvelope, HeaderDoc, ErrorDoc } from 'ts-procedures/http-docs'
|
|
|
62
59
|
|
|
63
60
|
8. **getProcedures() for introspection.** Returns all registered procedures with metadata.
|
|
64
61
|
|
|
62
|
+
9. **`Procedures({ config: { noRuntimeValidation: true } })` skips per-call AJV validation** for every procedure on the factory (both `Create` and `CreateStream`, both `schema.params` and `schema.input`). Shape is `noRuntimeValidation?: true` — only `true` is accepted. JSON Schema is still computed at registration time, so codegen and `info.schema` are unaffected; only the validator runs are bypassed. **Never enable this on a factory whose handlers are reachable from public/untrusted callers** — coerceTypes and removeAdditional also stop running. Reserve for trusted internal factories whose callers are already type-checked at build time. Independent of the per-call `ctx.isPrevalidated` escape hatch used by HTTP builders.
|
|
63
|
+
|
|
65
64
|
## Procedure Pattern
|
|
66
65
|
|
|
67
66
|
```typescript
|
|
@@ -112,31 +111,12 @@ const { StreamEvents } = CreateStream(
|
|
|
112
111
|
)
|
|
113
112
|
```
|
|
114
113
|
|
|
115
|
-
## Express RPC Pattern
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
import { ExpressRPCAppBuilder } from 'ts-procedures/express-rpc'
|
|
119
|
-
import type { RPCConfig } from 'ts-procedures/http'
|
|
120
|
-
|
|
121
|
-
const RPC = Procedures<AppContext, RPCConfig>()
|
|
122
|
-
|
|
123
|
-
RPC.Create('GetUser', {
|
|
124
|
-
scope: 'users', version: 1,
|
|
125
|
-
schema: { params: Type.Object({ id: Type.String() }) },
|
|
126
|
-
}, async (ctx, params) => fetchUser(params.id))
|
|
127
|
-
|
|
128
|
-
const app = new ExpressRPCAppBuilder({ pathPrefix: '/api' })
|
|
129
|
-
.register(RPC, async (req) => ({ userId: await authenticate(req) }))
|
|
130
|
-
.build()
|
|
131
|
-
// POST /api/users/get-user/1
|
|
132
|
-
```
|
|
133
|
-
|
|
134
114
|
## Hono RPC Pattern
|
|
135
115
|
|
|
136
116
|
```typescript
|
|
137
|
-
import {
|
|
117
|
+
import { HonoAppBuilder } from 'ts-procedures/hono'
|
|
138
118
|
|
|
139
|
-
const app = new
|
|
119
|
+
const app = new HonoAppBuilder({ pathPrefix: '/api' })
|
|
140
120
|
.register(RPC, (c) => ({ userId: c.req.header('x-user-id') }))
|
|
141
121
|
.build()
|
|
142
122
|
```
|
|
@@ -144,7 +124,7 @@ const app = new HonoRPCAppBuilder({ pathPrefix: '/api' })
|
|
|
144
124
|
## Hono Streaming Pattern
|
|
145
125
|
|
|
146
126
|
```typescript
|
|
147
|
-
import {
|
|
127
|
+
import { HonoAppBuilder, sse } from 'ts-procedures/hono'
|
|
148
128
|
|
|
149
129
|
const StreamRPC = Procedures<AppContext, RPCConfig>()
|
|
150
130
|
|
|
@@ -158,43 +138,53 @@ StreamRPC.CreateStream('Feed', {
|
|
|
158
138
|
}
|
|
159
139
|
})
|
|
160
140
|
|
|
161
|
-
const app = new
|
|
141
|
+
const app = new HonoAppBuilder({ defaultStreamMode: 'sse' })
|
|
162
142
|
.register(StreamRPC, (c) => ({ userId: c.req.header('x-user-id') }))
|
|
163
143
|
.build()
|
|
164
144
|
// GET|POST /events/feed/1
|
|
165
145
|
```
|
|
166
146
|
|
|
167
|
-
## Hono API Pattern (REST-style)
|
|
147
|
+
## Hono API Pattern (REST-style) — v8 `CreateHttp`
|
|
148
|
+
|
|
149
|
+
In v8, HTTP routes use `CreateHttp` (not `Create + APIConfig`). `schema.input` is renamed `schema.req`. The factory needs no `APIConfig` type parameter.
|
|
168
150
|
|
|
169
151
|
```typescript
|
|
170
|
-
import {
|
|
171
|
-
import type { APIConfig } from 'ts-procedures/http'
|
|
152
|
+
import { HonoAppBuilder } from 'ts-procedures/hono'
|
|
172
153
|
|
|
173
|
-
const API = Procedures<AppContext
|
|
154
|
+
const API = Procedures<AppContext>()
|
|
174
155
|
|
|
175
|
-
API.
|
|
156
|
+
API.CreateHttp('GetUser', {
|
|
176
157
|
path: '/users/:id', method: 'get',
|
|
177
158
|
schema: {
|
|
178
|
-
|
|
159
|
+
req: { pathParams: Type.Object({ id: Type.String() }) },
|
|
160
|
+
res: { body: Type.Object({ id: Type.String(), name: Type.String() }) },
|
|
179
161
|
},
|
|
180
162
|
}, async (ctx, { pathParams }) => fetchUser(pathParams.id))
|
|
181
163
|
|
|
182
|
-
API.
|
|
164
|
+
API.CreateHttp('CreateUser', {
|
|
183
165
|
path: '/users', method: 'post',
|
|
184
166
|
schema: {
|
|
185
|
-
|
|
167
|
+
req: { body: Type.Object({ name: Type.String() }) },
|
|
186
168
|
},
|
|
187
169
|
}, async (ctx, { body }) => createUser(body))
|
|
188
170
|
|
|
189
|
-
const app = new
|
|
171
|
+
const app = new HonoAppBuilder({ pathPrefix: '/api' })
|
|
190
172
|
.register(API, (c) => ({ userId: c.req.header('x-user-id') }))
|
|
191
173
|
.build()
|
|
192
174
|
// GET /api/users/:id → 200, POST /api/users → 201
|
|
193
175
|
```
|
|
194
176
|
|
|
177
|
+
**v7 → v8 migration:**
|
|
178
|
+
|
|
179
|
+
1. `Procedures<Ctx, APIConfig>()` → `Procedures<Ctx>()`
|
|
180
|
+
2. `.Create(` → `.CreateHttp(` for HTTP routes
|
|
181
|
+
3. `schema.input` → `schema.req` (same channels: `pathParams`, `query`, `body`, `headers`)
|
|
182
|
+
4. Move response type to `schema.res.body` (optional)
|
|
183
|
+
5. Re-run `npx ts-procedures-codegen`
|
|
184
|
+
|
|
195
185
|
## Astro adapter
|
|
196
186
|
|
|
197
|
-
Catch-all endpoint pattern. Build Hono apps once with
|
|
187
|
+
Catch-all endpoint pattern. Build Hono apps once with `HonoAppBuilder`, 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.
|
|
198
188
|
|
|
199
189
|
## Error Handling
|
|
200
190
|
|
|
@@ -207,7 +197,7 @@ Catch-all endpoint pattern. Build Hono apps once with HonoAPI/RPC/Stream builder
|
|
|
207
197
|
|
|
208
198
|
### Error Taxonomy (required for custom errors)
|
|
209
199
|
|
|
210
|
-
`defineErrorTaxonomy` maps error classes to HTTP responses declaratively. Works with
|
|
200
|
+
`defineErrorTaxonomy` maps error classes to HTTP responses declaratively. Works with `HonoAppBuilder` for `rpc`, `http`, and pre-stream paths (`rpc-stream` / `http-stream`).
|
|
211
201
|
|
|
212
202
|
Do NOT write `onError` `instanceof` ladders — that's anti-pattern #20. Use the taxonomy instead:
|
|
213
203
|
|
|
@@ -237,13 +227,13 @@ const appErrors = defineErrorTaxonomy({
|
|
|
237
227
|
},
|
|
238
228
|
})
|
|
239
229
|
|
|
240
|
-
new
|
|
230
|
+
new HonoAppBuilder({
|
|
241
231
|
errors: appErrors,
|
|
242
232
|
unknownError: { statusCode: 500, toResponse: () => ({ name: 'InternalServerError' }) },
|
|
243
233
|
})
|
|
244
234
|
```
|
|
245
235
|
|
|
246
|
-
Handlers throw the error classes directly — the builder auto-serializes. `onError` is the first-class imperative peer when you want to handle errors in one callback instead (both modes coexist). In v6 `
|
|
236
|
+
Handlers throw the error classes directly — the builder auto-serializes. `onError` is the first-class imperative peer when you want to handle errors in one callback instead (both modes coexist). In v6 `HonoAppBuilder.onPreStreamError` was renamed to `onError`. Cross-cutting `onRequestError` observer fires for every caught error.
|
|
247
237
|
|
|
248
238
|
### Per-route errors (typed)
|
|
249
239
|
|
|
@@ -311,10 +301,7 @@ onRequestStart → factoryContext() → validation → onStreamStart → handler
|
|
|
311
301
|
- **TypeBox** (`import { Type } from 'typebox'`)
|
|
312
302
|
|
|
313
303
|
**Which HTTP implementation?**
|
|
314
|
-
-
|
|
315
|
-
- Hono (standard) → `HonoRPCAppBuilder`
|
|
316
|
-
- Hono (streaming) → `HonoStreamAppBuilder`
|
|
317
|
-
- Hono (REST-style, per-channel input) → `HonoAPIAppBuilder`
|
|
304
|
+
- Hono (RPC, streams, REST, REST streams) → `HonoAppBuilder`
|
|
318
305
|
|
|
319
306
|
**Stream mode?**
|
|
320
307
|
- Browser EventSource → `'sse'` (default)
|
|
@@ -327,13 +314,14 @@ onRequestStart → factoryContext() → validation → onStreamStart → handler
|
|
|
327
314
|
3. **Never put validation logic in handler** — use `schema.params`
|
|
328
315
|
4. **Never ignore ctx.signal** — pass to all async calls
|
|
329
316
|
5. **Never skip signal.aborted check in stream loops** — causes resource leaks
|
|
330
|
-
6. **Never register Create procedures with
|
|
317
|
+
6. **Never register Create procedures with HonoAppBuilder** — they're silently ignored
|
|
331
318
|
7. **Never use plain JSON Schema objects** — use TypeBox builders
|
|
332
319
|
8. **Never swallow errors without re-throwing** — hides failures
|
|
333
320
|
9. **Never assume extra params fields survive** — `removeAdditional: true` strips them
|
|
334
321
|
10. **Never manually parse types AJV coerces** — `coerceTypes: true` handles it
|
|
335
322
|
11. **Never define both schema.params and schema.input** — mutually exclusive, throws ProcedureRegistrationError
|
|
336
323
|
12. **Never catch raw DOMException/TypeError from generated callables** — catch `ClientTimeoutError`, `ClientAbortError`, `ClientNetworkError` instead; or use `.safe()` for Result-based narrowing
|
|
324
|
+
13. **Never use `Create` for HTTP routes (v8+)** — use `CreateHttp` (unary) or `CreateHttpStream` (streaming); `schema.input` → `schema.req`; `Procedures<Ctx, APIConfig>()` → `Procedures<Ctx>()`
|
|
337
325
|
|
|
338
326
|
## Testing
|
|
339
327
|
|
|
@@ -26,18 +26,15 @@ import { ProcedureError, ProcedureValidationError, ProcedureYieldValidationError
|
|
|
26
26
|
// HTTP types
|
|
27
27
|
import type { RPCConfig, RPCHttpRouteDoc, StreamHttpRouteDoc, StreamMode } from 'ts-procedures/http'
|
|
28
28
|
|
|
29
|
-
// Express RPC
|
|
30
|
-
import { ExpressRPCAppBuilder } from 'ts-procedures/express-rpc'
|
|
31
|
-
|
|
32
29
|
// Hono RPC
|
|
33
|
-
import {
|
|
30
|
+
import { HonoAppBuilder } from 'ts-procedures/hono'
|
|
34
31
|
|
|
35
32
|
// Hono Streaming
|
|
36
|
-
import {
|
|
33
|
+
import { HonoAppBuilder, sse } from 'ts-procedures/hono'
|
|
37
34
|
|
|
38
35
|
// Hono API (REST-style)
|
|
39
|
-
import {
|
|
40
|
-
import type { APIConfig, APIInput } from 'ts-procedures/hono
|
|
36
|
+
import { HonoAppBuilder } from 'ts-procedures/hono'
|
|
37
|
+
import type { APIConfig, APIInput } from 'ts-procedures/hono'
|
|
41
38
|
|
|
42
39
|
// Doc Registry — compose route docs from multiple builders
|
|
43
40
|
import { DocRegistry } from 'ts-procedures/http-docs'
|
|
@@ -62,6 +59,8 @@ import type { DocEnvelope, HeaderDoc, ErrorDoc } from 'ts-procedures/http-docs'
|
|
|
62
59
|
|
|
63
60
|
8. **getProcedures() for introspection.** Returns all registered procedures with metadata.
|
|
64
61
|
|
|
62
|
+
9. **`Procedures({ config: { noRuntimeValidation: true } })` skips per-call AJV validation** for every procedure on the factory (both `Create` and `CreateStream`, both `schema.params` and `schema.input`). Shape is `noRuntimeValidation?: true` — only `true` is accepted. JSON Schema is still computed at registration time, so codegen and `info.schema` are unaffected; only the validator runs are bypassed. **Never enable this on a factory whose handlers are reachable from public/untrusted callers** — coerceTypes and removeAdditional also stop running. Reserve for trusted internal factories whose callers are already type-checked at build time. Independent of the per-call `ctx.isPrevalidated` escape hatch used by HTTP builders.
|
|
63
|
+
|
|
65
64
|
## Procedure Pattern
|
|
66
65
|
|
|
67
66
|
```typescript
|
|
@@ -112,31 +111,12 @@ const { StreamEvents } = CreateStream(
|
|
|
112
111
|
)
|
|
113
112
|
```
|
|
114
113
|
|
|
115
|
-
## Express RPC Pattern
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
import { ExpressRPCAppBuilder } from 'ts-procedures/express-rpc'
|
|
119
|
-
import type { RPCConfig } from 'ts-procedures/http'
|
|
120
|
-
|
|
121
|
-
const RPC = Procedures<AppContext, RPCConfig>()
|
|
122
|
-
|
|
123
|
-
RPC.Create('GetUser', {
|
|
124
|
-
scope: 'users', version: 1,
|
|
125
|
-
schema: { params: Type.Object({ id: Type.String() }) },
|
|
126
|
-
}, async (ctx, params) => fetchUser(params.id))
|
|
127
|
-
|
|
128
|
-
const app = new ExpressRPCAppBuilder({ pathPrefix: '/api' })
|
|
129
|
-
.register(RPC, async (req) => ({ userId: await authenticate(req) }))
|
|
130
|
-
.build()
|
|
131
|
-
// POST /api/users/get-user/1
|
|
132
|
-
```
|
|
133
|
-
|
|
134
114
|
## Hono RPC Pattern
|
|
135
115
|
|
|
136
116
|
```typescript
|
|
137
|
-
import {
|
|
117
|
+
import { HonoAppBuilder } from 'ts-procedures/hono'
|
|
138
118
|
|
|
139
|
-
const app = new
|
|
119
|
+
const app = new HonoAppBuilder({ pathPrefix: '/api' })
|
|
140
120
|
.register(RPC, (c) => ({ userId: c.req.header('x-user-id') }))
|
|
141
121
|
.build()
|
|
142
122
|
```
|
|
@@ -144,7 +124,7 @@ const app = new HonoRPCAppBuilder({ pathPrefix: '/api' })
|
|
|
144
124
|
## Hono Streaming Pattern
|
|
145
125
|
|
|
146
126
|
```typescript
|
|
147
|
-
import {
|
|
127
|
+
import { HonoAppBuilder, sse } from 'ts-procedures/hono'
|
|
148
128
|
|
|
149
129
|
const StreamRPC = Procedures<AppContext, RPCConfig>()
|
|
150
130
|
|
|
@@ -158,43 +138,53 @@ StreamRPC.CreateStream('Feed', {
|
|
|
158
138
|
}
|
|
159
139
|
})
|
|
160
140
|
|
|
161
|
-
const app = new
|
|
141
|
+
const app = new HonoAppBuilder({ defaultStreamMode: 'sse' })
|
|
162
142
|
.register(StreamRPC, (c) => ({ userId: c.req.header('x-user-id') }))
|
|
163
143
|
.build()
|
|
164
144
|
// GET|POST /events/feed/1
|
|
165
145
|
```
|
|
166
146
|
|
|
167
|
-
## Hono API Pattern (REST-style)
|
|
147
|
+
## Hono API Pattern (REST-style) — v8 `CreateHttp`
|
|
148
|
+
|
|
149
|
+
In v8, HTTP routes use `CreateHttp` (not `Create + APIConfig`). `schema.input` is renamed `schema.req`. The factory needs no `APIConfig` type parameter.
|
|
168
150
|
|
|
169
151
|
```typescript
|
|
170
|
-
import {
|
|
171
|
-
import type { APIConfig } from 'ts-procedures/http'
|
|
152
|
+
import { HonoAppBuilder } from 'ts-procedures/hono'
|
|
172
153
|
|
|
173
|
-
const API = Procedures<AppContext
|
|
154
|
+
const API = Procedures<AppContext>()
|
|
174
155
|
|
|
175
|
-
API.
|
|
156
|
+
API.CreateHttp('GetUser', {
|
|
176
157
|
path: '/users/:id', method: 'get',
|
|
177
158
|
schema: {
|
|
178
|
-
|
|
159
|
+
req: { pathParams: Type.Object({ id: Type.String() }) },
|
|
160
|
+
res: { body: Type.Object({ id: Type.String(), name: Type.String() }) },
|
|
179
161
|
},
|
|
180
162
|
}, async (ctx, { pathParams }) => fetchUser(pathParams.id))
|
|
181
163
|
|
|
182
|
-
API.
|
|
164
|
+
API.CreateHttp('CreateUser', {
|
|
183
165
|
path: '/users', method: 'post',
|
|
184
166
|
schema: {
|
|
185
|
-
|
|
167
|
+
req: { body: Type.Object({ name: Type.String() }) },
|
|
186
168
|
},
|
|
187
169
|
}, async (ctx, { body }) => createUser(body))
|
|
188
170
|
|
|
189
|
-
const app = new
|
|
171
|
+
const app = new HonoAppBuilder({ pathPrefix: '/api' })
|
|
190
172
|
.register(API, (c) => ({ userId: c.req.header('x-user-id') }))
|
|
191
173
|
.build()
|
|
192
174
|
// GET /api/users/:id → 200, POST /api/users → 201
|
|
193
175
|
```
|
|
194
176
|
|
|
177
|
+
**v7 → v8 migration:**
|
|
178
|
+
|
|
179
|
+
1. `Procedures<Ctx, APIConfig>()` → `Procedures<Ctx>()`
|
|
180
|
+
2. `.Create(` → `.CreateHttp(` for HTTP routes
|
|
181
|
+
3. `schema.input` → `schema.req` (same channels: `pathParams`, `query`, `body`, `headers`)
|
|
182
|
+
4. Move response type to `schema.res.body` (optional)
|
|
183
|
+
5. Re-run `npx ts-procedures-codegen`
|
|
184
|
+
|
|
195
185
|
## Astro adapter
|
|
196
186
|
|
|
197
|
-
Catch-all endpoint pattern. Build Hono apps once with
|
|
187
|
+
Catch-all endpoint pattern. Build Hono apps once with `HonoAppBuilder`, 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.
|
|
198
188
|
|
|
199
189
|
## Error Handling
|
|
200
190
|
|
|
@@ -207,7 +197,7 @@ Catch-all endpoint pattern. Build Hono apps once with HonoAPI/RPC/Stream builder
|
|
|
207
197
|
|
|
208
198
|
### Error Taxonomy (required for custom errors)
|
|
209
199
|
|
|
210
|
-
`defineErrorTaxonomy` maps error classes to HTTP responses declaratively. Works with
|
|
200
|
+
`defineErrorTaxonomy` maps error classes to HTTP responses declaratively. Works with `HonoAppBuilder` for `rpc`, `http`, and pre-stream paths (`rpc-stream` / `http-stream`).
|
|
211
201
|
|
|
212
202
|
Do NOT write `onError` `instanceof` ladders — that's anti-pattern #20. Use the taxonomy instead:
|
|
213
203
|
|
|
@@ -237,13 +227,13 @@ const appErrors = defineErrorTaxonomy({
|
|
|
237
227
|
},
|
|
238
228
|
})
|
|
239
229
|
|
|
240
|
-
new
|
|
230
|
+
new HonoAppBuilder({
|
|
241
231
|
errors: appErrors,
|
|
242
232
|
unknownError: { statusCode: 500, toResponse: () => ({ name: 'InternalServerError' }) },
|
|
243
233
|
})
|
|
244
234
|
```
|
|
245
235
|
|
|
246
|
-
Handlers throw the error classes directly — the builder auto-serializes. `onError` is the first-class imperative peer when you want to handle errors in one callback instead (both modes coexist). In v6 `
|
|
236
|
+
Handlers throw the error classes directly — the builder auto-serializes. `onError` is the first-class imperative peer when you want to handle errors in one callback instead (both modes coexist). In v6 `HonoAppBuilder.onPreStreamError` was renamed to `onError`. Cross-cutting `onRequestError` observer fires for every caught error.
|
|
247
237
|
|
|
248
238
|
### Per-route errors (typed)
|
|
249
239
|
|
|
@@ -311,10 +301,7 @@ onRequestStart → factoryContext() → validation → onStreamStart → handler
|
|
|
311
301
|
- **TypeBox** (`import { Type } from 'typebox'`)
|
|
312
302
|
|
|
313
303
|
**Which HTTP implementation?**
|
|
314
|
-
-
|
|
315
|
-
- Hono (standard) → `HonoRPCAppBuilder`
|
|
316
|
-
- Hono (streaming) → `HonoStreamAppBuilder`
|
|
317
|
-
- Hono (REST-style, per-channel input) → `HonoAPIAppBuilder`
|
|
304
|
+
- Hono (RPC, streams, REST, REST streams) → `HonoAppBuilder`
|
|
318
305
|
|
|
319
306
|
**Stream mode?**
|
|
320
307
|
- Browser EventSource → `'sse'` (default)
|
|
@@ -327,13 +314,14 @@ onRequestStart → factoryContext() → validation → onStreamStart → handler
|
|
|
327
314
|
3. **Never put validation logic in handler** — use `schema.params`
|
|
328
315
|
4. **Never ignore ctx.signal** — pass to all async calls
|
|
329
316
|
5. **Never skip signal.aborted check in stream loops** — causes resource leaks
|
|
330
|
-
6. **Never register Create procedures with
|
|
317
|
+
6. **Never register Create procedures with HonoAppBuilder** — they're silently ignored
|
|
331
318
|
7. **Never use plain JSON Schema objects** — use TypeBox builders
|
|
332
319
|
8. **Never swallow errors without re-throwing** — hides failures
|
|
333
320
|
9. **Never assume extra params fields survive** — `removeAdditional: true` strips them
|
|
334
321
|
10. **Never manually parse types AJV coerces** — `coerceTypes: true` handles it
|
|
335
322
|
11. **Never define both schema.params and schema.input** — mutually exclusive, throws ProcedureRegistrationError
|
|
336
323
|
12. **Never catch raw DOMException/TypeError from generated callables** — catch `ClientTimeoutError`, `ClientAbortError`, `ClientNetworkError` instead; or use `.safe()` for Result-based narrowing
|
|
324
|
+
13. **Never use `Create` for HTTP routes (v8+)** — use `CreateHttp` (unary) or `CreateHttpStream` (streaming); `schema.input` → `schema.req`; `Procedures<Ctx, APIConfig>()` → `Procedures<Ctx>()`
|
|
337
325
|
|
|
338
326
|
## Testing
|
|
339
327
|
|
package/build/client/call.js
CHANGED
|
@@ -84,7 +84,10 @@ export async function executeCall(config) {
|
|
|
84
84
|
scope: descriptor.scope,
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
|
-
// 8. Return the body
|
|
87
|
+
// 8. Return the body (or { body, headers } when the route declares res.headers)
|
|
88
|
+
if (descriptor.responseHeadersDeclared) {
|
|
89
|
+
return { body: response.body, headers: response.headers };
|
|
90
|
+
}
|
|
88
91
|
return response.body;
|
|
89
92
|
}
|
|
90
93
|
/**
|
package/build/client/call.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call.js","sourceRoot":"","sources":["../../src/client/call.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"call.js","sourceRoot":"","sources":["../../src/client/call.ts"],"names":[],"mappings":"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"}
|