ts-procedures 7.3.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 +104 -53
- package/agent_config/claude-code/skills/ts-procedures/api-reference.md +205 -232
- 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 +34 -48
- package/agent_config/cursor/cursorrules +34 -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 +124 -124
- package/build/index.js +10 -221
- package/build/index.js.map +1 -1
- package/build/index.test.js +20 -919
- 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 +15 -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 +22 -1249
- package/src/index.ts +49 -485
- 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
|
@@ -1,357 +0,0 @@
|
|
|
1
|
-
# HonoRPCAppBuilder
|
|
2
|
-
|
|
3
|
-
Hono integration for `ts-procedures` that creates type-safe RPC endpoints as POST routes. Works with Bun, Deno, Cloudflare Workers, and Node.js.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install ts-procedures hono
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Quick Start
|
|
12
|
-
|
|
13
|
-
```typescript
|
|
14
|
-
import { Hono } from 'hono'
|
|
15
|
-
import { Procedures } from 'ts-procedures'
|
|
16
|
-
import { HonoRPCAppBuilder, RPCConfig } from 'ts-procedures/hono-rpc'
|
|
17
|
-
import { Type } from 'typebox'
|
|
18
|
-
|
|
19
|
-
// Define your context type
|
|
20
|
-
type AppContext = { userId: string }
|
|
21
|
-
|
|
22
|
-
// Create a procedure factory
|
|
23
|
-
const RPC = Procedures<AppContext, RPCConfig>()
|
|
24
|
-
|
|
25
|
-
// Define procedures
|
|
26
|
-
RPC.Create(
|
|
27
|
-
'GetUser',
|
|
28
|
-
{
|
|
29
|
-
scope: ['users', 'profile'],
|
|
30
|
-
version: 1,
|
|
31
|
-
schema: {
|
|
32
|
-
params: Type.Object({ id: Type.String() }),
|
|
33
|
-
returnType: Type.Object({ id: Type.String(), name: Type.String() }),
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
async (ctx, params) => {
|
|
37
|
-
return { id: params.id, name: 'John Doe' }
|
|
38
|
-
}
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
// Build the Hono app
|
|
42
|
-
const builder = new HonoRPCAppBuilder({ pathPrefix: '/rpc' }).register(RPC, (c) => ({
|
|
43
|
-
userId: c.req.header('x-user-id') || 'anonymous',
|
|
44
|
-
}))
|
|
45
|
-
|
|
46
|
-
const app = builder.build()
|
|
47
|
-
|
|
48
|
-
// Bun
|
|
49
|
-
export default app
|
|
50
|
-
|
|
51
|
-
// Node.js
|
|
52
|
-
// import { serve } from '@hono/node-server'
|
|
53
|
-
// serve(app)
|
|
54
|
-
|
|
55
|
-
// POST /rpc/users/profile/get-user/1 → { id: "123", name: "John Doe" }
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## Configuration
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
61
|
-
type HonoRPCAppBuilderConfig = {
|
|
62
|
-
app?: Hono // Existing Hono app (optional)
|
|
63
|
-
pathPrefix?: string // Prefix for all routes (e.g., '/rpc/v1')
|
|
64
|
-
onRequestStart?: (c: Context) => void
|
|
65
|
-
onRequestEnd?: (c: Context) => void
|
|
66
|
-
onSuccess?: (procedure: TProcedureRegistration, c: Context) => void
|
|
67
|
-
onError?: (
|
|
68
|
-
procedure: TProcedureRegistration,
|
|
69
|
-
c: Context,
|
|
70
|
-
error: Error
|
|
71
|
-
) => Response | Promise<Response>
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
| Option | Type | Description |
|
|
76
|
-
| ---------------- | ---------------------------- | ------------------------------------------------- |
|
|
77
|
-
| `app` | `Hono` | Use existing Hono app instead of creating new one |
|
|
78
|
-
| `pathPrefix` | `string` | Prefix all routes (e.g., `/rpc/v1`) |
|
|
79
|
-
| `onRequestStart` | `(c) => void` | Called at start of each request |
|
|
80
|
-
| `onRequestEnd` | `(c) => void` | Called after handler completes |
|
|
81
|
-
| `onSuccess` | `(proc, c) => void` | Called on successful handler execution |
|
|
82
|
-
| `onError` | `(proc, c, err) => Response` | Imperative error handler (peer of `errors` taxonomy — see Error Handling) |
|
|
83
|
-
|
|
84
|
-
## Context Resolution
|
|
85
|
-
|
|
86
|
-
The context resolver receives the Hono `Context` object:
|
|
87
|
-
|
|
88
|
-
```typescript
|
|
89
|
-
builder.register(RPC, (c: Context) => ({
|
|
90
|
-
userId: c.req.header('x-user-id') || 'anonymous',
|
|
91
|
-
userAgent: c.req.header('user-agent'),
|
|
92
|
-
ip: c.req.raw.headers.get('cf-connecting-ip'), // Cloudflare
|
|
93
|
-
}))
|
|
94
|
-
|
|
95
|
-
// Async context resolution
|
|
96
|
-
builder.register(RPC, async (c) => {
|
|
97
|
-
const token = c.req.header('authorization')?.replace('Bearer ', '')
|
|
98
|
-
const user = await verifyToken(token)
|
|
99
|
-
return { userId: user.id, roles: user.roles }
|
|
100
|
-
})
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
## Extending Procedure Documentation
|
|
104
|
-
|
|
105
|
-
The `register` method accepts an optional third parameter `extendProcedureDoc` that allows you to add custom fields to each procedure's documentation. This is useful for adding metadata like descriptions, tags, or custom fields for API documentation generators.
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
// Example of a factory extending the procedure config:
|
|
109
|
-
type ExtendedRPCConfig = {
|
|
110
|
-
description: string
|
|
111
|
-
tags: string[]
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
builder.register(RPC, (c) => ({ userId: c.req.header('x-user-id') || 'anonymous' }), {
|
|
115
|
-
extendProcedureDoc: ({ base, procedure }, { base: RPCHttpRouteDoc, procedure }) =>
|
|
116
|
-
({
|
|
117
|
-
description: `Procedure: ${procedure.name}`,
|
|
118
|
-
tags: Array.isArray(procedure.config.scope)
|
|
119
|
-
? procedure.config.scope
|
|
120
|
-
: [procedure.config.scope],
|
|
121
|
-
}),
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
// Access extended docs after build()
|
|
125
|
-
const app = builder.build()
|
|
126
|
-
console.log(builder.docs) // Each doc now includes description and tags
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
The `extendProcedureDoc` callback receives:
|
|
130
|
-
|
|
131
|
-
| Parameter | Type | Description |
|
|
132
|
-
| ----------- | ------------------------ | ------------------------------------------------------------------------------------------ |
|
|
133
|
-
| `base` | `RPCHttpRouteDoc` | The base documentation with `name`, `path`, `method`, `scope`, `version`, and `jsonSchema` |
|
|
134
|
-
| `procedure` | `TProcedureRegistration` | The full procedure registration including `name`, `config`, and `handler` |
|
|
135
|
-
|
|
136
|
-
This allows you to derive documentation fields from procedure config or add static metadata per factory registration.
|
|
137
|
-
|
|
138
|
-
## Abort Signal
|
|
139
|
-
|
|
140
|
-
`HonoRPCAppBuilder` automatically injects the HTTP request's `AbortSignal` (`c.req.raw.signal`) into the handler context. When a client disconnects mid-request, `ctx.signal` aborts, cancelling any signal-aware operations:
|
|
141
|
-
|
|
142
|
-
```typescript
|
|
143
|
-
RPC.Create(
|
|
144
|
-
'SlowQuery',
|
|
145
|
-
{ scope: 'data', version: 1 },
|
|
146
|
-
async (ctx, params) => {
|
|
147
|
-
// Automatically cancelled if client disconnects
|
|
148
|
-
const response = await fetch('https://slow-api.example.com/data', {
|
|
149
|
-
signal: ctx.signal,
|
|
150
|
-
})
|
|
151
|
-
return response.json()
|
|
152
|
-
}
|
|
153
|
-
)
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
To use `ctx.signal` with type safety, include `signal: AbortSignal` in your context type:
|
|
157
|
-
|
|
158
|
-
```typescript
|
|
159
|
-
type AppContext = { userId: string; signal: AbortSignal }
|
|
160
|
-
const RPC = Procedures<AppContext, RPCConfig>()
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
## Error Handling
|
|
164
|
-
|
|
165
|
-
Declare error classes via `defineErrorTaxonomy` and pass them to the builder's `errors` option. Handlers `throw` their classes; the builder auto-serializes to the configured status + body.
|
|
166
|
-
|
|
167
|
-
```typescript
|
|
168
|
-
import { defineErrorTaxonomy } from 'ts-procedures/hono-rpc'
|
|
169
|
-
|
|
170
|
-
const appErrors = defineErrorTaxonomy({
|
|
171
|
-
AuthError: { class: AuthError, statusCode: 401 },
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
new HonoRPCAppBuilder({
|
|
175
|
-
errors: appErrors,
|
|
176
|
-
unknownError: { toResponse: () => ({ error: 'Internal server error' }) },
|
|
177
|
-
})
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
Full contract (both peer error modes, `onRequestError` observer, per-route narrowing via `RPCConfig<keyof typeof appErrors & string>`): see **[docs/http-integrations.md § Error Handling](../../../../docs/http-integrations.md#error-handling)** — the canonical explanation shared across all four HTTP builders.
|
|
181
|
-
|
|
182
|
-
## Using Existing Hono App
|
|
183
|
-
|
|
184
|
-
You can add RPC routes to an existing Hono application:
|
|
185
|
-
|
|
186
|
-
```typescript
|
|
187
|
-
const app = new Hono()
|
|
188
|
-
|
|
189
|
-
// Add custom middleware and routes
|
|
190
|
-
app.use('*', cors())
|
|
191
|
-
app.get('/custom', (c) => c.json({ custom: true }))
|
|
192
|
-
|
|
193
|
-
const builder = new HonoRPCAppBuilder({ app }).register(RPC, contextResolver)
|
|
194
|
-
|
|
195
|
-
builder.build() // Adds RPC routes to existing app
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
## Runtime Compatibility
|
|
199
|
-
|
|
200
|
-
HonoRPCAppBuilder works across all Hono-supported runtimes:
|
|
201
|
-
|
|
202
|
-
### Bun
|
|
203
|
-
|
|
204
|
-
```typescript
|
|
205
|
-
const app = builder.build()
|
|
206
|
-
export default app
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### Node.js
|
|
210
|
-
|
|
211
|
-
```typescript
|
|
212
|
-
import { serve } from '@hono/node-server'
|
|
213
|
-
|
|
214
|
-
const app = builder.build()
|
|
215
|
-
serve(app)
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### Deno
|
|
219
|
-
|
|
220
|
-
```typescript
|
|
221
|
-
import { serve } from 'https://deno.land/std/http/server.ts'
|
|
222
|
-
|
|
223
|
-
const app = builder.build()
|
|
224
|
-
serve(app.fetch)
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### Cloudflare Workers
|
|
228
|
-
|
|
229
|
-
```typescript
|
|
230
|
-
const app = builder.build()
|
|
231
|
-
export default app
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
## API Reference
|
|
235
|
-
|
|
236
|
-
### Constructor
|
|
237
|
-
|
|
238
|
-
```typescript
|
|
239
|
-
new HonoRPCAppBuilder(config?: HonoRPCAppBuilderConfig)
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### Methods
|
|
243
|
-
|
|
244
|
-
| Method | Signature | Description |
|
|
245
|
-
| ---------------------- | ------------------------------------------------- | ------------------------------------------------------------------ |
|
|
246
|
-
| `register` | `register<T>(factory, context, options?): this` | Register procedure factory with context and optional doc extension |
|
|
247
|
-
| `build` | `build(): Hono` | Build routes and return app |
|
|
248
|
-
| `makeRPCHttpRoutePath` | `makeRPCHttpRoutePath(config: RPCConfig): string` | Generate route path |
|
|
249
|
-
|
|
250
|
-
### Static Methods
|
|
251
|
-
|
|
252
|
-
| Method | Signature | Description |
|
|
253
|
-
| ---------------------- | --------------------------------------------------------- | -------------------------------------- |
|
|
254
|
-
| `makeRPCHttpRoutePath` | `static makeRPCHttpRoutePath({ config, prefix }): string` | Generate route path with custom prefix |
|
|
255
|
-
|
|
256
|
-
### Properties
|
|
257
|
-
|
|
258
|
-
| Property | Type | Description |
|
|
259
|
-
| -------- | ------------------------- | ------------------------------------- |
|
|
260
|
-
| `app` | `Hono` | The Hono application instance |
|
|
261
|
-
| `docs` | `RPCHttpRouteDoc[]` | Route documentation (after `build()`) |
|
|
262
|
-
| `config` | `HonoRPCAppBuilderConfig` | The configuration object |
|
|
263
|
-
|
|
264
|
-
## TypeScript Types
|
|
265
|
-
|
|
266
|
-
```typescript
|
|
267
|
-
import { HonoRPCAppBuilder, defineErrorTaxonomy } from 'ts-procedures/hono-rpc'
|
|
268
|
-
import type {
|
|
269
|
-
HonoRPCAppBuilderConfig,
|
|
270
|
-
RPCConfig,
|
|
271
|
-
RPCHttpRouteDoc,
|
|
272
|
-
ErrorTaxonomy,
|
|
273
|
-
ErrorTaxonomyEntry,
|
|
274
|
-
UnknownErrorConfig,
|
|
275
|
-
OnRequestErrorContext,
|
|
276
|
-
} from 'ts-procedures/hono-rpc'
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
## Full Example
|
|
280
|
-
|
|
281
|
-
```typescript
|
|
282
|
-
import { Hono, Context } from 'hono'
|
|
283
|
-
import { Procedures } from 'ts-procedures'
|
|
284
|
-
import { HonoRPCAppBuilder, RPCConfig } from 'ts-procedures/hono-rpc'
|
|
285
|
-
import { Type } from 'typebox'
|
|
286
|
-
|
|
287
|
-
// Context types
|
|
288
|
-
type PublicContext = { source: 'public' }
|
|
289
|
-
type AuthContext = { source: 'auth'; userId: string }
|
|
290
|
-
|
|
291
|
-
// Create factories
|
|
292
|
-
const PublicRPC = Procedures<PublicContext, RPCConfig>()
|
|
293
|
-
const AuthRPC = Procedures<AuthContext, RPCConfig>()
|
|
294
|
-
|
|
295
|
-
// Public procedures
|
|
296
|
-
PublicRPC.Create('HealthCheck', { scope: 'health', version: 1 }, async () => ({
|
|
297
|
-
status: 'ok',
|
|
298
|
-
}))
|
|
299
|
-
|
|
300
|
-
PublicRPC.Create('GetVersion', { scope: ['system', 'version'], version: 1 }, async () => ({
|
|
301
|
-
version: '1.0.0',
|
|
302
|
-
}))
|
|
303
|
-
|
|
304
|
-
// Authenticated procedures
|
|
305
|
-
AuthRPC.Create(
|
|
306
|
-
'GetProfile',
|
|
307
|
-
{
|
|
308
|
-
scope: ['users', 'profile'],
|
|
309
|
-
version: 1,
|
|
310
|
-
schema: { returnType: Type.Object({ userId: Type.String() }) },
|
|
311
|
-
},
|
|
312
|
-
async (ctx) => ({ userId: ctx.userId })
|
|
313
|
-
)
|
|
314
|
-
|
|
315
|
-
AuthRPC.Create(
|
|
316
|
-
'UpdateProfile',
|
|
317
|
-
{
|
|
318
|
-
scope: ['users', 'profile'],
|
|
319
|
-
version: 2,
|
|
320
|
-
schema: { params: Type.Object({ name: Type.String() }) },
|
|
321
|
-
},
|
|
322
|
-
async (ctx, params) => ({ userId: ctx.userId, name: params.name })
|
|
323
|
-
)
|
|
324
|
-
|
|
325
|
-
// Build app
|
|
326
|
-
const builder = new HonoRPCAppBuilder({
|
|
327
|
-
pathPrefix: '/rpc',
|
|
328
|
-
onRequestStart: (c) => console.log(`→ ${c.req.method} ${c.req.path}`),
|
|
329
|
-
onRequestEnd: (c) => console.log(`← completed`),
|
|
330
|
-
onSuccess: (proc) => console.log(`✓ ${proc.name}`),
|
|
331
|
-
onError: (proc, c, err) => {
|
|
332
|
-
console.error(`✗ ${proc.name}:`, err.message)
|
|
333
|
-
return c.json({ error: err.message }, 500)
|
|
334
|
-
},
|
|
335
|
-
})
|
|
336
|
-
|
|
337
|
-
builder
|
|
338
|
-
.register(PublicRPC, () => ({ source: 'public' as const }))
|
|
339
|
-
.register(AuthRPC, (c) => ({
|
|
340
|
-
source: 'auth' as const,
|
|
341
|
-
userId: c.req.header('x-user-id') || 'anonymous',
|
|
342
|
-
}))
|
|
343
|
-
|
|
344
|
-
const app = builder.build()
|
|
345
|
-
|
|
346
|
-
// Generated routes:
|
|
347
|
-
// POST /rpc/health/health-check/1
|
|
348
|
-
// POST /rpc/system/version/get-version/1
|
|
349
|
-
// POST /rpc/users/profile/get-profile/1
|
|
350
|
-
// POST /rpc/users/profile/update-profile/2
|
|
351
|
-
|
|
352
|
-
console.log(
|
|
353
|
-
'Routes:',
|
|
354
|
-
builder.docs.map((d) => d.path)
|
|
355
|
-
)
|
|
356
|
-
export default app
|
|
357
|
-
```
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test, vi } from 'vitest'
|
|
2
|
-
import { Type } from 'typebox'
|
|
3
|
-
import { Procedures } from '../../../index.js'
|
|
4
|
-
import { RPCConfig } from '../../types.js'
|
|
5
|
-
import { HonoRPCAppBuilder, defineErrorTaxonomy } from './index.js'
|
|
6
|
-
|
|
7
|
-
class UseCaseError extends Error {
|
|
8
|
-
constructor(
|
|
9
|
-
readonly externalMsg: string,
|
|
10
|
-
readonly internalMsg: string
|
|
11
|
-
) {
|
|
12
|
-
super(externalMsg)
|
|
13
|
-
this.name = 'UseCaseError'
|
|
14
|
-
Object.setPrototypeOf(this, UseCaseError.prototype)
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
describe('HonoRPCAppBuilder — error taxonomy', () => {
|
|
19
|
-
test('taxonomy catches user error thrown from RPC handler', async () => {
|
|
20
|
-
const errors = defineErrorTaxonomy({
|
|
21
|
-
UseCaseError: {
|
|
22
|
-
class: UseCaseError,
|
|
23
|
-
statusCode: 422,
|
|
24
|
-
toResponse: (err) => ({ name: 'UseCaseError', message: err.externalMsg }),
|
|
25
|
-
},
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
const RPC = Procedures<{}, RPCConfig>()
|
|
29
|
-
RPC.Create(
|
|
30
|
-
'Boom',
|
|
31
|
-
{ scope: 'test', version: 1, schema: { params: Type.Object({}) } },
|
|
32
|
-
async () => {
|
|
33
|
-
throw new UseCaseError('ext', 'int')
|
|
34
|
-
}
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
const app = new HonoRPCAppBuilder({ errors }).register(RPC, () => ({})).build()
|
|
38
|
-
const res = await app.request('/test/boom/1', {
|
|
39
|
-
method: 'POST',
|
|
40
|
-
headers: { 'Content-Type': 'application/json' },
|
|
41
|
-
body: '{}',
|
|
42
|
-
})
|
|
43
|
-
expect(res.status).toBe(422)
|
|
44
|
-
expect(await res.json()).toEqual({ name: 'UseCaseError', message: 'ext' })
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
test('unknownError catches unmapped errors', async () => {
|
|
48
|
-
const RPC = Procedures<{}, RPCConfig>()
|
|
49
|
-
RPC.Create(
|
|
50
|
-
'Boom',
|
|
51
|
-
{ scope: 'test', version: 1, schema: { params: Type.Object({}) } },
|
|
52
|
-
async () => {
|
|
53
|
-
throw new TypeError('db down')
|
|
54
|
-
}
|
|
55
|
-
)
|
|
56
|
-
const app = new HonoRPCAppBuilder({
|
|
57
|
-
unknownError: { statusCode: 503, toResponse: () => ({ name: 'ServiceUnavailable' }) },
|
|
58
|
-
})
|
|
59
|
-
.register(RPC, () => ({}))
|
|
60
|
-
.build()
|
|
61
|
-
|
|
62
|
-
const res = await app.request('/test/boom/1', { method: 'POST', body: '{}' })
|
|
63
|
-
expect(res.status).toBe(503)
|
|
64
|
-
expect(await res.json()).toEqual({ name: 'ServiceUnavailable' })
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
test('onError callback runs when taxonomy does not match', async () => {
|
|
68
|
-
const onError = vi.fn(async (_p: any, c: any) => c.json({ legacy: true }, 418))
|
|
69
|
-
const RPC = Procedures<{}, RPCConfig>()
|
|
70
|
-
RPC.Create(
|
|
71
|
-
'Boom',
|
|
72
|
-
{ scope: 'test', version: 1, schema: { params: Type.Object({}) } },
|
|
73
|
-
async () => {
|
|
74
|
-
throw new TypeError('legacy')
|
|
75
|
-
}
|
|
76
|
-
)
|
|
77
|
-
const app = new HonoRPCAppBuilder({ onError }).register(RPC, () => ({})).build()
|
|
78
|
-
const res = await app.request('/test/boom/1', { method: 'POST', body: '{}' })
|
|
79
|
-
expect(res.status).toBe(418)
|
|
80
|
-
expect(onError).toHaveBeenCalledOnce()
|
|
81
|
-
})
|
|
82
|
-
})
|