ts-procedures 2.1.0 → 3.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/build/errors.d.ts +2 -1
- package/build/errors.js +3 -2
- package/build/errors.js.map +1 -1
- package/build/errors.test.js +40 -0
- package/build/errors.test.js.map +1 -0
- package/build/implementations/http/express-rpc/index.d.ts +36 -35
- package/build/implementations/http/express-rpc/index.js +29 -13
- package/build/implementations/http/express-rpc/index.js.map +1 -1
- package/build/implementations/http/express-rpc/index.test.js +146 -92
- package/build/implementations/http/express-rpc/index.test.js.map +1 -1
- package/build/implementations/http/hono-rpc/index.d.ts +83 -0
- package/build/implementations/http/hono-rpc/index.js +148 -0
- package/build/implementations/http/hono-rpc/index.js.map +1 -0
- package/build/implementations/http/hono-rpc/index.test.js +647 -0
- package/build/implementations/http/hono-rpc/index.test.js.map +1 -0
- package/build/implementations/http/hono-rpc/types.d.ts +28 -0
- package/build/implementations/http/hono-rpc/types.js.map +1 -0
- package/build/implementations/types.d.ts +1 -1
- package/build/index.d.ts +12 -0
- package/build/index.js +29 -7
- package/build/index.js.map +1 -1
- package/build/index.test.js +65 -0
- package/build/index.test.js.map +1 -1
- package/build/schema/parser.js +3 -0
- package/build/schema/parser.js.map +1 -1
- package/build/schema/parser.test.js +18 -0
- package/build/schema/parser.test.js.map +1 -1
- package/package.json +8 -2
- package/src/errors.test.ts +53 -0
- package/src/errors.ts +4 -2
- package/src/implementations/http/README.md +172 -0
- package/src/implementations/http/express-rpc/README.md +151 -228
- package/src/implementations/http/express-rpc/index.test.ts +167 -93
- package/src/implementations/http/express-rpc/index.ts +67 -38
- package/src/implementations/http/hono-rpc/README.md +293 -0
- package/src/implementations/http/hono-rpc/index.test.ts +847 -0
- package/src/implementations/http/hono-rpc/index.ts +202 -0
- package/src/implementations/http/hono-rpc/types.ts +33 -0
- package/src/implementations/types.ts +2 -1
- package/src/index.test.ts +83 -0
- package/src/index.ts +34 -8
- package/src/schema/parser.test.ts +26 -0
- package/src/schema/parser.ts +5 -1
- package/build/implementations/http/client/index.js +0 -2
- package/build/implementations/http/client/index.js.map +0 -1
- package/build/implementations/http/express/example/factories.d.ts +0 -97
- package/build/implementations/http/express/example/factories.js +0 -4
- package/build/implementations/http/express/example/factories.js.map +0 -1
- package/build/implementations/http/express/example/procedures/auth.d.ts +0 -1
- package/build/implementations/http/express/example/procedures/auth.js +0 -22
- package/build/implementations/http/express/example/procedures/auth.js.map +0 -1
- package/build/implementations/http/express/example/procedures/users.d.ts +0 -1
- package/build/implementations/http/express/example/procedures/users.js +0 -30
- package/build/implementations/http/express/example/procedures/users.js.map +0 -1
- package/build/implementations/http/express/example/server.d.ts +0 -3
- package/build/implementations/http/express/example/server.js +0 -49
- package/build/implementations/http/express/example/server.js.map +0 -1
- package/build/implementations/http/express/example/server.test.d.ts +0 -1
- package/build/implementations/http/express/example/server.test.js +0 -110
- package/build/implementations/http/express/example/server.test.js.map +0 -1
- package/build/implementations/http/express/index.d.ts +0 -35
- package/build/implementations/http/express/index.js +0 -75
- package/build/implementations/http/express/index.js.map +0 -1
- package/build/implementations/http/express/index.test.js +0 -329
- package/build/implementations/http/express/index.test.js.map +0 -1
- package/build/implementations/http/express/types.d.ts +0 -17
- package/build/implementations/http/express/types.js.map +0 -1
- /package/build/{implementations/http/client/index.d.ts → errors.test.d.ts} +0 -0
- /package/build/implementations/http/{express → hono-rpc}/index.test.d.ts +0 -0
- /package/build/implementations/http/{express → hono-rpc}/types.js +0 -0
|
@@ -6,6 +6,31 @@ import { castArray } from 'es-toolkit/compat'
|
|
|
6
6
|
import { ExpressFactoryItem, ExtractContext, ProceduresFactory } from './types.js'
|
|
7
7
|
|
|
8
8
|
export type { RPCConfig, RPCHttpRouteDoc }
|
|
9
|
+
|
|
10
|
+
export type ExpressRPCAppBuilderConfig = {
|
|
11
|
+
/**
|
|
12
|
+
* An existing Express application instance to use.
|
|
13
|
+
* When provided, ensure to set up necessary middleware (e.g., json/body parser) beforehand.
|
|
14
|
+
* If not provided, a new instance will be created.
|
|
15
|
+
*/
|
|
16
|
+
app?: express.Express
|
|
17
|
+
/** Optional path prefix for all RPC routes. */
|
|
18
|
+
pathPrefix?: string
|
|
19
|
+
onRequestStart?: (req: express.Request) => void
|
|
20
|
+
onRequestEnd?: (req: express.Request, res: express.Response) => void
|
|
21
|
+
onSuccess?: (
|
|
22
|
+
procedure: TProcedureRegistration,
|
|
23
|
+
req: express.Request,
|
|
24
|
+
res: express.Response
|
|
25
|
+
) => void
|
|
26
|
+
error?: (
|
|
27
|
+
procedure: TProcedureRegistration,
|
|
28
|
+
req: express.Request,
|
|
29
|
+
res: express.Response,
|
|
30
|
+
error: Error
|
|
31
|
+
) => void
|
|
32
|
+
}
|
|
33
|
+
|
|
9
34
|
/**
|
|
10
35
|
* Builder class for creating an Express application with RPC routes.
|
|
11
36
|
*
|
|
@@ -27,29 +52,7 @@ export class ExpressRPCAppBuilder {
|
|
|
27
52
|
*
|
|
28
53
|
* @param config
|
|
29
54
|
*/
|
|
30
|
-
constructor(
|
|
31
|
-
readonly config?: {
|
|
32
|
-
/**
|
|
33
|
-
* An existing Express application instance to use.
|
|
34
|
-
* When provided, ensure to set up necessary middleware (e.g., json/body parser) beforehand.
|
|
35
|
-
* If not provided, a new instance will be created.
|
|
36
|
-
*/
|
|
37
|
-
app?: express.Express
|
|
38
|
-
onRequestStart?: (req: express.Request) => void
|
|
39
|
-
onRequestEnd?: (req: express.Request, res: express.Response) => void
|
|
40
|
-
onSuccess?: (
|
|
41
|
-
procedure: TProcedureRegistration,
|
|
42
|
-
req: express.Request,
|
|
43
|
-
res: express.Response
|
|
44
|
-
) => void
|
|
45
|
-
error?: (
|
|
46
|
-
procedure: TProcedureRegistration,
|
|
47
|
-
req: express.Request,
|
|
48
|
-
res: express.Response,
|
|
49
|
-
error: Error
|
|
50
|
-
) => void
|
|
51
|
-
}
|
|
52
|
-
) {
|
|
55
|
+
constructor(readonly config?: ExpressRPCAppBuilderConfig) {
|
|
53
56
|
if (config?.app) {
|
|
54
57
|
this._app = config.app
|
|
55
58
|
} else {
|
|
@@ -74,6 +77,41 @@ export class ExpressRPCAppBuilder {
|
|
|
74
77
|
}
|
|
75
78
|
}
|
|
76
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Generates the RPC route path based on the RPC configuration.
|
|
82
|
+
* The RPCConfig name can be a string or an array of strings to form nested paths.
|
|
83
|
+
*
|
|
84
|
+
* Example
|
|
85
|
+
* name: ['string', 'string-string', 'string']
|
|
86
|
+
* path: /string/string-string/string/version
|
|
87
|
+
* @param config
|
|
88
|
+
*/
|
|
89
|
+
static makeRPCHttpRoutePath({
|
|
90
|
+
name,
|
|
91
|
+
config,
|
|
92
|
+
prefix,
|
|
93
|
+
}: {
|
|
94
|
+
name: string
|
|
95
|
+
prefix?: string
|
|
96
|
+
config: RPCConfig
|
|
97
|
+
}) {
|
|
98
|
+
const normalizedPrefix = prefix ? (prefix.startsWith('/') ? prefix : `/${prefix}`) : ''
|
|
99
|
+
|
|
100
|
+
return `${normalizedPrefix}/${castArray(config.scope).map(kebabCase).join('/')}/${kebabCase(name)}/${String(config.version).trim()}`
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Instance method wrapper for makeRPCHttpRoutePath that uses the builder's pathPrefix.
|
|
105
|
+
* @param config - The RPC configuration
|
|
106
|
+
*/
|
|
107
|
+
makeRPCHttpRoutePath(name: string, config: RPCConfig): string {
|
|
108
|
+
return ExpressRPCAppBuilder.makeRPCHttpRoutePath({
|
|
109
|
+
name,
|
|
110
|
+
config,
|
|
111
|
+
prefix: this.config?.pathPrefix,
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
|
|
77
115
|
private factories: ExpressFactoryItem<any>[] = []
|
|
78
116
|
|
|
79
117
|
private _app: express.Express = express()
|
|
@@ -153,9 +191,13 @@ export class ExpressRPCAppBuilder {
|
|
|
153
191
|
* Generates the RPC HTTP route for the given procedure.
|
|
154
192
|
* @param procedure
|
|
155
193
|
*/
|
|
156
|
-
buildRpcHttpRouteDoc(procedure: TProcedureRegistration<any, RPCConfig>): RPCHttpRouteDoc {
|
|
194
|
+
private buildRpcHttpRouteDoc(procedure: TProcedureRegistration<any, RPCConfig>): RPCHttpRouteDoc {
|
|
157
195
|
const { config } = procedure
|
|
158
|
-
const path =
|
|
196
|
+
const path = ExpressRPCAppBuilder.makeRPCHttpRoutePath({
|
|
197
|
+
name: procedure.name,
|
|
198
|
+
config,
|
|
199
|
+
prefix: this.config?.pathPrefix,
|
|
200
|
+
})
|
|
159
201
|
const method = 'post' // RPCs use POST method
|
|
160
202
|
const jsonSchema: { body?: object; response?: object } = {}
|
|
161
203
|
|
|
@@ -172,17 +214,4 @@ export class ExpressRPCAppBuilder {
|
|
|
172
214
|
jsonSchema,
|
|
173
215
|
}
|
|
174
216
|
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Generates the RPC route path based on the RPC configuration.
|
|
178
|
-
* The RPCConfig name can be a string or an array of strings to form nested paths.
|
|
179
|
-
*
|
|
180
|
-
* Example
|
|
181
|
-
* name: ['string', 'string-string', 'string']
|
|
182
|
-
* path: /rpc/string/string-string/string/version
|
|
183
|
-
* @param config
|
|
184
|
-
*/
|
|
185
|
-
makeRPCHttpRoutePath(config: RPCConfig) {
|
|
186
|
-
return `/rpc/${castArray(config.name).map(kebabCase).join('/')}/${String(config.version).trim()}`
|
|
187
|
-
}
|
|
188
217
|
}
|
|
@@ -0,0 +1,293 @@
|
|
|
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/implementations/http/hono-rpc'
|
|
17
|
+
import { v } from 'suretype'
|
|
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: v.object({ id: v.string() }),
|
|
33
|
+
returnType: v.object({ id: v.string(), name: v.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' })
|
|
43
|
+
.register(RPC, (c) => ({
|
|
44
|
+
userId: c.req.header('x-user-id') || 'anonymous'
|
|
45
|
+
}))
|
|
46
|
+
|
|
47
|
+
const app = builder.build()
|
|
48
|
+
|
|
49
|
+
// Bun
|
|
50
|
+
export default app
|
|
51
|
+
|
|
52
|
+
// Node.js
|
|
53
|
+
// import { serve } from '@hono/node-server'
|
|
54
|
+
// serve(app)
|
|
55
|
+
|
|
56
|
+
// POST /rpc/users/profile/get-user/1 → { id: "123", name: "John Doe" }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Configuration
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
type HonoRPCAppBuilderConfig = {
|
|
63
|
+
app?: Hono // Existing Hono app (optional)
|
|
64
|
+
pathPrefix?: string // Prefix for all routes (e.g., '/rpc/v1')
|
|
65
|
+
onRequestStart?: (c: Context) => void
|
|
66
|
+
onRequestEnd?: (c: Context) => void
|
|
67
|
+
onSuccess?: (procedure: TProcedureRegistration, c: Context) => void
|
|
68
|
+
error?: (procedure: TProcedureRegistration, c: Context, error: Error) => Response | Promise<Response>
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
| Option | Type | Description |
|
|
73
|
+
|--------|------|---------------------------------------------------|
|
|
74
|
+
| `app` | `Hono` | Use existing Hono app instead of creating new one |
|
|
75
|
+
| `pathPrefix` | `string` | Prefix all routes (e.g., `/rpc/v1`) |
|
|
76
|
+
| `onRequestStart` | `(c) => void` | Called at start of each request |
|
|
77
|
+
| `onRequestEnd` | `(c) => void` | Called after handler completes |
|
|
78
|
+
| `onSuccess` | `(proc, c) => void` | Called on successful handler execution |
|
|
79
|
+
| `error` | `(proc, c, err) => Response` | Custom error handler (must return Response) |
|
|
80
|
+
|
|
81
|
+
## Context Resolution
|
|
82
|
+
|
|
83
|
+
The context resolver receives the Hono `Context` object:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
builder.register(RPC, (c: Context) => ({
|
|
87
|
+
userId: c.req.header('x-user-id') || 'anonymous',
|
|
88
|
+
userAgent: c.req.header('user-agent'),
|
|
89
|
+
ip: c.req.raw.headers.get('cf-connecting-ip') // Cloudflare
|
|
90
|
+
}))
|
|
91
|
+
|
|
92
|
+
// Async context resolution
|
|
93
|
+
builder.register(RPC, async (c) => {
|
|
94
|
+
const token = c.req.header('authorization')?.replace('Bearer ', '')
|
|
95
|
+
const user = await verifyToken(token)
|
|
96
|
+
return { userId: user.id, roles: user.roles }
|
|
97
|
+
})
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Error Handling
|
|
101
|
+
|
|
102
|
+
Custom error handler receives the procedure, context, and error. **Must return a Response:**
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const builder = new HonoRPCAppBuilder({
|
|
106
|
+
error: (procedure, c, error) => {
|
|
107
|
+
console.error(`Error in ${procedure.name}:`, error)
|
|
108
|
+
|
|
109
|
+
if (error instanceof ValidationError) {
|
|
110
|
+
return c.json({ error: error.message, code: 'VALIDATION_ERROR' }, 400)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (error instanceof AuthError) {
|
|
114
|
+
return c.json({ error: 'Unauthorized', code: 'AUTH_ERROR' }, 401)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return c.json({ error: 'Internal server error' }, 500)
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Default error handling:** Returns `{ error: message }` with status 500.
|
|
123
|
+
|
|
124
|
+
## Using Existing Hono App
|
|
125
|
+
|
|
126
|
+
You can add RPC routes to an existing Hono application:
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
const app = new Hono()
|
|
130
|
+
|
|
131
|
+
// Add custom middleware and routes
|
|
132
|
+
app.use('*', cors())
|
|
133
|
+
app.get('/custom', (c) => c.json({ custom: true }))
|
|
134
|
+
|
|
135
|
+
const builder = new HonoRPCAppBuilder({ app })
|
|
136
|
+
.register(RPC, contextResolver)
|
|
137
|
+
|
|
138
|
+
builder.build() // Adds RPC routes to existing app
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Runtime Compatibility
|
|
142
|
+
|
|
143
|
+
HonoRPCAppBuilder works across all Hono-supported runtimes:
|
|
144
|
+
|
|
145
|
+
### Bun
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
const app = builder.build()
|
|
149
|
+
export default app
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Node.js
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { serve } from '@hono/node-server'
|
|
156
|
+
|
|
157
|
+
const app = builder.build()
|
|
158
|
+
serve(app)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Deno
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { serve } from 'https://deno.land/std/http/server.ts'
|
|
165
|
+
|
|
166
|
+
const app = builder.build()
|
|
167
|
+
serve(app.fetch)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Cloudflare Workers
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
const app = builder.build()
|
|
174
|
+
export default app
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## API Reference
|
|
178
|
+
|
|
179
|
+
### Constructor
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
new HonoRPCAppBuilder(config?: HonoRPCAppBuilderConfig)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Methods
|
|
186
|
+
|
|
187
|
+
| Method | Signature | Description |
|
|
188
|
+
|--------|-----------|-------------|
|
|
189
|
+
| `register` | `register<T>(factory, context): this` | Register procedure factory with context |
|
|
190
|
+
| `build` | `build(): Hono` | Build routes and return app |
|
|
191
|
+
| `makeRPCHttpRoutePath` | `makeRPCHttpRoutePath(config: RPCConfig): string` | Generate route path |
|
|
192
|
+
|
|
193
|
+
### Static Methods
|
|
194
|
+
|
|
195
|
+
| Method | Signature | Description |
|
|
196
|
+
|--------|-----------|-------------|
|
|
197
|
+
| `makeRPCHttpRoutePath` | `static makeRPCHttpRoutePath({ config, prefix }): string` | Generate route path with custom prefix |
|
|
198
|
+
|
|
199
|
+
### Properties
|
|
200
|
+
|
|
201
|
+
| Property | Type | Description |
|
|
202
|
+
|----------|------|-------------|
|
|
203
|
+
| `app` | `Hono` | The Hono application instance |
|
|
204
|
+
| `docs` | `RPCHttpRouteDoc[]` | Route documentation (after `build()`) |
|
|
205
|
+
| `config` | `HonoRPCAppBuilderConfig` | The configuration object |
|
|
206
|
+
|
|
207
|
+
## TypeScript Types
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
import {
|
|
211
|
+
HonoRPCAppBuilder,
|
|
212
|
+
HonoRPCAppBuilderConfig,
|
|
213
|
+
RPCConfig,
|
|
214
|
+
RPCHttpRouteDoc
|
|
215
|
+
} from 'ts-procedures/implementations/http/hono-rpc'
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Full Example
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
import { Hono, Context } from 'hono'
|
|
222
|
+
import { Procedures } from 'ts-procedures'
|
|
223
|
+
import { HonoRPCAppBuilder, RPCConfig } from 'ts-procedures/implementations/http/hono-rpc'
|
|
224
|
+
import { v } from 'suretype'
|
|
225
|
+
|
|
226
|
+
// Context types
|
|
227
|
+
type PublicContext = { source: 'public' }
|
|
228
|
+
type AuthContext = { source: 'auth'; userId: string }
|
|
229
|
+
|
|
230
|
+
// Create factories
|
|
231
|
+
const PublicRPC = Procedures<PublicContext, RPCConfig>()
|
|
232
|
+
const AuthRPC = Procedures<AuthContext, RPCConfig>()
|
|
233
|
+
|
|
234
|
+
// Public procedures
|
|
235
|
+
PublicRPC.Create('HealthCheck', { scope: 'health', version: 1 }, async () => ({
|
|
236
|
+
status: 'ok'
|
|
237
|
+
}))
|
|
238
|
+
|
|
239
|
+
PublicRPC.Create('GetVersion', { scope: ['system', 'version'], version: 1 }, async () => ({
|
|
240
|
+
version: '1.0.0'
|
|
241
|
+
}))
|
|
242
|
+
|
|
243
|
+
// Authenticated procedures
|
|
244
|
+
AuthRPC.Create(
|
|
245
|
+
'GetProfile',
|
|
246
|
+
{
|
|
247
|
+
scope: ['users', 'profile'],
|
|
248
|
+
version: 1,
|
|
249
|
+
schema: { returnType: v.object({ userId: v.string() }) }
|
|
250
|
+
},
|
|
251
|
+
async (ctx) => ({ userId: ctx.userId })
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
AuthRPC.Create(
|
|
255
|
+
'UpdateProfile',
|
|
256
|
+
{
|
|
257
|
+
scope: ['users', 'profile'],
|
|
258
|
+
version: 2,
|
|
259
|
+
schema: { params: v.object({ name: v.string() }) }
|
|
260
|
+
},
|
|
261
|
+
async (ctx, params) => ({ userId: ctx.userId, name: params.name })
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
// Build app
|
|
265
|
+
const builder = new HonoRPCAppBuilder({
|
|
266
|
+
pathPrefix: '/rpc',
|
|
267
|
+
onRequestStart: (c) => console.log(`→ ${c.req.method} ${c.req.path}`),
|
|
268
|
+
onRequestEnd: (c) => console.log(`← completed`),
|
|
269
|
+
onSuccess: (proc) => console.log(`✓ ${proc.name}`),
|
|
270
|
+
error: (proc, c, err) => {
|
|
271
|
+
console.error(`✗ ${proc.name}:`, err.message)
|
|
272
|
+
return c.json({ error: err.message }, 500)
|
|
273
|
+
}
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
builder
|
|
277
|
+
.register(PublicRPC, () => ({ source: 'public' as const }))
|
|
278
|
+
.register(AuthRPC, (c) => ({
|
|
279
|
+
source: 'auth' as const,
|
|
280
|
+
userId: c.req.header('x-user-id') || 'anonymous'
|
|
281
|
+
}))
|
|
282
|
+
|
|
283
|
+
const app = builder.build()
|
|
284
|
+
|
|
285
|
+
// Generated routes:
|
|
286
|
+
// POST /rpc/health/1
|
|
287
|
+
// POST /rpc/system/version/get-version/1
|
|
288
|
+
// POST /rpc/users/profile/get-user/1
|
|
289
|
+
// POST /rpc/users/profile/get-user/2
|
|
290
|
+
|
|
291
|
+
console.log('Routes:', builder.docs.map(d => d.path))
|
|
292
|
+
export default app
|
|
293
|
+
```
|