@veloxts/router 0.6.84 → 0.6.86
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/CHANGELOG.md +18 -0
- package/GUIDE.md +51 -7
- package/dist/expose.d.ts +12 -9
- package/dist/expose.js +13 -9
- package/dist/index.d.ts +10 -6
- package/dist/index.js +6 -3
- package/dist/middleware/chain.d.ts +54 -0
- package/dist/middleware/chain.js +80 -0
- package/dist/middleware/index.d.ts +7 -0
- package/dist/middleware/index.js +6 -0
- package/dist/openapi/generator.js +10 -0
- package/dist/openapi/html-generator.d.ts +66 -0
- package/dist/openapi/html-generator.js +116 -0
- package/dist/openapi/index.d.ts +1 -0
- package/dist/openapi/index.js +4 -0
- package/dist/openapi/plugin.js +7 -90
- package/dist/procedure/builder.js +36 -59
- package/dist/procedure/types.d.ts +66 -6
- package/dist/rest/adapter.d.ts +38 -1
- package/dist/rest/adapter.js +94 -27
- package/dist/rest/index.d.ts +2 -2
- package/dist/rest/index.js +1 -1
- package/dist/rest/naming.d.ts +38 -2
- package/dist/rest/naming.js +65 -18
- package/dist/rpc.d.ts +144 -0
- package/dist/rpc.js +127 -0
- package/dist/trpc/adapter.d.ts +139 -10
- package/dist/trpc/adapter.js +33 -61
- package/dist/trpc/index.d.ts +3 -1
- package/dist/types.d.ts +51 -7
- package/package.json +3 -3
package/dist/rest/naming.d.ts
CHANGED
|
@@ -59,7 +59,7 @@ export declare function parseNamingConvention(name: string, type: ProcedureType)
|
|
|
59
59
|
*/
|
|
60
60
|
export declare function buildRestPath(namespace: string, mapping: RestMapping): string;
|
|
61
61
|
/**
|
|
62
|
-
* Build a nested REST path with parent resource prefix
|
|
62
|
+
* Build a nested REST path with parent resource prefix (single level)
|
|
63
63
|
*
|
|
64
64
|
* Creates paths like `/posts/:postId/comments/:id` for nested resources.
|
|
65
65
|
*
|
|
@@ -70,7 +70,7 @@ export declare function buildRestPath(namespace: string, mapping: RestMapping):
|
|
|
70
70
|
*
|
|
71
71
|
* @example
|
|
72
72
|
* ```typescript
|
|
73
|
-
* const parent = {
|
|
73
|
+
* const parent = { resource: 'posts', param: 'postId' };
|
|
74
74
|
*
|
|
75
75
|
* buildNestedRestPath(parent, 'comments', { method: 'GET', path: '/:id', hasIdParam: true })
|
|
76
76
|
* // Returns: '/posts/:postId/comments/:id'
|
|
@@ -83,6 +83,42 @@ export declare function buildRestPath(namespace: string, mapping: RestMapping):
|
|
|
83
83
|
* ```
|
|
84
84
|
*/
|
|
85
85
|
export declare function buildNestedRestPath(parentResource: ParentResourceConfig, childNamespace: string, mapping: RestMapping): string;
|
|
86
|
+
/**
|
|
87
|
+
* Build a deeply nested REST path with multiple parent resources
|
|
88
|
+
*
|
|
89
|
+
* Creates paths like `/organizations/:orgId/projects/:projectId/tasks/:id`
|
|
90
|
+
* for deeply nested resources.
|
|
91
|
+
*
|
|
92
|
+
* @param parentResources - Array of parent resource configurations (outermost to innermost)
|
|
93
|
+
* @param childNamespace - Child resource namespace (e.g., 'tasks')
|
|
94
|
+
* @param mapping - REST mapping from parseNamingConvention
|
|
95
|
+
* @returns Full deeply nested path
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* const parents = [
|
|
100
|
+
* { resource: 'organizations', param: 'orgId' },
|
|
101
|
+
* { resource: 'projects', param: 'projectId' },
|
|
102
|
+
* ];
|
|
103
|
+
*
|
|
104
|
+
* buildMultiLevelNestedPath(parents, 'tasks', { method: 'GET', path: '/:id', hasIdParam: true })
|
|
105
|
+
* // Returns: '/organizations/:orgId/projects/:projectId/tasks/:id'
|
|
106
|
+
*
|
|
107
|
+
* buildMultiLevelNestedPath(parents, 'tasks', { method: 'GET', path: '/', hasIdParam: false })
|
|
108
|
+
* // Returns: '/organizations/:orgId/projects/:projectId/tasks'
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export declare function buildMultiLevelNestedPath(parentResources: readonly ParentResourceConfig[], childNamespace: string, mapping: RestMapping): string;
|
|
112
|
+
/**
|
|
113
|
+
* Calculate the nesting depth of a route
|
|
114
|
+
*
|
|
115
|
+
* Returns the number of parent levels plus 1 for the resource itself.
|
|
116
|
+
*
|
|
117
|
+
* @param parentResource - Single parent resource (optional)
|
|
118
|
+
* @param parentResources - Multiple parent resources (optional)
|
|
119
|
+
* @returns The total nesting depth (1 = flat, 2 = one parent, 3+ = deeply nested)
|
|
120
|
+
*/
|
|
121
|
+
export declare function calculateNestingDepth(parentResource?: ParentResourceConfig, parentResources?: readonly ParentResourceConfig[]): number;
|
|
86
122
|
/**
|
|
87
123
|
* Infer the resource name from a procedure name
|
|
88
124
|
*
|
package/dist/rest/naming.js
CHANGED
|
@@ -140,6 +140,16 @@ export function parseNamingConvention(name, type) {
|
|
|
140
140
|
// No convention matched
|
|
141
141
|
return undefined;
|
|
142
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Append the mapping suffix to a base path
|
|
145
|
+
*
|
|
146
|
+
* @param basePath - The base path (e.g., '/users', '/posts/:postId/comments')
|
|
147
|
+
* @param mapping - REST mapping containing the path suffix
|
|
148
|
+
* @returns The complete path with suffix appended (if not just '/')
|
|
149
|
+
*/
|
|
150
|
+
function appendMappingSuffix(basePath, mapping) {
|
|
151
|
+
return mapping.path === '/' ? basePath : `${basePath}${mapping.path}`;
|
|
152
|
+
}
|
|
143
153
|
/**
|
|
144
154
|
* Build the full REST path from namespace and mapping
|
|
145
155
|
*
|
|
@@ -157,16 +167,10 @@ export function parseNamingConvention(name, type) {
|
|
|
157
167
|
* ```
|
|
158
168
|
*/
|
|
159
169
|
export function buildRestPath(namespace, mapping) {
|
|
160
|
-
|
|
161
|
-
// If path is just '/', return the base path without trailing slash
|
|
162
|
-
if (mapping.path === '/') {
|
|
163
|
-
return basePath;
|
|
164
|
-
}
|
|
165
|
-
// Otherwise append the path (e.g., '/:id')
|
|
166
|
-
return `${basePath}${mapping.path}`;
|
|
170
|
+
return appendMappingSuffix(`/${namespace}`, mapping);
|
|
167
171
|
}
|
|
168
172
|
/**
|
|
169
|
-
* Build a nested REST path with parent resource prefix
|
|
173
|
+
* Build a nested REST path with parent resource prefix (single level)
|
|
170
174
|
*
|
|
171
175
|
* Creates paths like `/posts/:postId/comments/:id` for nested resources.
|
|
172
176
|
*
|
|
@@ -177,7 +181,7 @@ export function buildRestPath(namespace, mapping) {
|
|
|
177
181
|
*
|
|
178
182
|
* @example
|
|
179
183
|
* ```typescript
|
|
180
|
-
* const parent = {
|
|
184
|
+
* const parent = { resource: 'posts', param: 'postId' };
|
|
181
185
|
*
|
|
182
186
|
* buildNestedRestPath(parent, 'comments', { method: 'GET', path: '/:id', hasIdParam: true })
|
|
183
187
|
* // Returns: '/posts/:postId/comments/:id'
|
|
@@ -190,16 +194,59 @@ export function buildRestPath(namespace, mapping) {
|
|
|
190
194
|
* ```
|
|
191
195
|
*/
|
|
192
196
|
export function buildNestedRestPath(parentResource, childNamespace, mapping) {
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
197
|
+
const parentPath = `/${parentResource.resource}/:${parentResource.param}`;
|
|
198
|
+
const basePath = `${parentPath}/${childNamespace}`;
|
|
199
|
+
return appendMappingSuffix(basePath, mapping);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Build a deeply nested REST path with multiple parent resources
|
|
203
|
+
*
|
|
204
|
+
* Creates paths like `/organizations/:orgId/projects/:projectId/tasks/:id`
|
|
205
|
+
* for deeply nested resources.
|
|
206
|
+
*
|
|
207
|
+
* @param parentResources - Array of parent resource configurations (outermost to innermost)
|
|
208
|
+
* @param childNamespace - Child resource namespace (e.g., 'tasks')
|
|
209
|
+
* @param mapping - REST mapping from parseNamingConvention
|
|
210
|
+
* @returns Full deeply nested path
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```typescript
|
|
214
|
+
* const parents = [
|
|
215
|
+
* { resource: 'organizations', param: 'orgId' },
|
|
216
|
+
* { resource: 'projects', param: 'projectId' },
|
|
217
|
+
* ];
|
|
218
|
+
*
|
|
219
|
+
* buildMultiLevelNestedPath(parents, 'tasks', { method: 'GET', path: '/:id', hasIdParam: true })
|
|
220
|
+
* // Returns: '/organizations/:orgId/projects/:projectId/tasks/:id'
|
|
221
|
+
*
|
|
222
|
+
* buildMultiLevelNestedPath(parents, 'tasks', { method: 'GET', path: '/', hasIdParam: false })
|
|
223
|
+
* // Returns: '/organizations/:orgId/projects/:projectId/tasks'
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
export function buildMultiLevelNestedPath(parentResources, childNamespace, mapping) {
|
|
227
|
+
const parentSegments = parentResources
|
|
228
|
+
.map((parent) => `/${parent.resource}/:${parent.param}`)
|
|
229
|
+
.join('');
|
|
230
|
+
const basePath = `${parentSegments}/${childNamespace}`;
|
|
231
|
+
return appendMappingSuffix(basePath, mapping);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Calculate the nesting depth of a route
|
|
235
|
+
*
|
|
236
|
+
* Returns the number of parent levels plus 1 for the resource itself.
|
|
237
|
+
*
|
|
238
|
+
* @param parentResource - Single parent resource (optional)
|
|
239
|
+
* @param parentResources - Multiple parent resources (optional)
|
|
240
|
+
* @returns The total nesting depth (1 = flat, 2 = one parent, 3+ = deeply nested)
|
|
241
|
+
*/
|
|
242
|
+
export function calculateNestingDepth(parentResource, parentResources) {
|
|
243
|
+
if (parentResources && parentResources.length > 0) {
|
|
244
|
+
return parentResources.length + 1;
|
|
245
|
+
}
|
|
246
|
+
if (parentResource) {
|
|
247
|
+
return 2;
|
|
200
248
|
}
|
|
201
|
-
|
|
202
|
-
return `${parentPath}${childBasePath}${mapping.path}`;
|
|
249
|
+
return 1;
|
|
203
250
|
}
|
|
204
251
|
/**
|
|
205
252
|
* Infer the resource name from a procedure name
|
package/dist/rpc.d.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RPC helper for type-safe tRPC registration
|
|
3
|
+
*
|
|
4
|
+
* Provides a symmetric API to `rest()` for registering tRPC endpoints
|
|
5
|
+
* with full type preservation for client inference.
|
|
6
|
+
*
|
|
7
|
+
* @module rpc
|
|
8
|
+
*/
|
|
9
|
+
import { type VeloxApp } from '@veloxts/core';
|
|
10
|
+
import type { FastifyInstance } from 'fastify';
|
|
11
|
+
import { type AnyRouter, type InferRouterFromCollections } from './trpc/index.js';
|
|
12
|
+
import type { ProcedureCollection } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Options for RPC registration
|
|
15
|
+
*/
|
|
16
|
+
export interface RpcOptions {
|
|
17
|
+
/**
|
|
18
|
+
* tRPC endpoint prefix
|
|
19
|
+
*
|
|
20
|
+
* @default '/trpc'
|
|
21
|
+
*/
|
|
22
|
+
prefix?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Result of rpc() for type-safe router access
|
|
26
|
+
*
|
|
27
|
+
* Contains both the typed router (for type export) and an async
|
|
28
|
+
* registration function (for registering with Fastify).
|
|
29
|
+
*/
|
|
30
|
+
export interface RpcResult<T extends readonly ProcedureCollection[]> {
|
|
31
|
+
/**
|
|
32
|
+
* The typed tRPC router
|
|
33
|
+
*
|
|
34
|
+
* Use `typeof router` to export the AppRouter type for clients.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const { router } = rpc([userProcedures, postProcedures] as const);
|
|
39
|
+
* export type AppRouter = typeof router;
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
readonly router: AnyRouter & InferRouterFromCollections<T>;
|
|
43
|
+
/**
|
|
44
|
+
* Register the tRPC routes with a Fastify instance
|
|
45
|
+
*
|
|
46
|
+
* This is an async function that registers the tRPC plugin.
|
|
47
|
+
*
|
|
48
|
+
* @param server - Fastify instance or VeloxApp
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const { register } = rpc([userProcedures] as const);
|
|
53
|
+
* await register(app.server);
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
readonly register: (server: FastifyInstance) => Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Create a type-safe tRPC router from procedure collections
|
|
60
|
+
*
|
|
61
|
+
* This is the RPC equivalent of `rest()`. It returns a typed router
|
|
62
|
+
* and a registration function, enabling proper type inference for
|
|
63
|
+
* client-side usage.
|
|
64
|
+
*
|
|
65
|
+
* **IMPORTANT**: Use `as const` on the collections array to preserve
|
|
66
|
+
* literal types for full type inference.
|
|
67
|
+
*
|
|
68
|
+
* @param collections - Array of procedure collections (use `as const`)
|
|
69
|
+
* @param options - Optional RPC configuration
|
|
70
|
+
* @returns RpcResult with typed router and register function
|
|
71
|
+
*
|
|
72
|
+
* @example Basic usage with VeloxApp
|
|
73
|
+
* ```typescript
|
|
74
|
+
* import { veloxApp } from '@veloxts/core';
|
|
75
|
+
* import { rpc } from '@veloxts/router';
|
|
76
|
+
*
|
|
77
|
+
* const app = await veloxApp({ port: 3030 });
|
|
78
|
+
*
|
|
79
|
+
* const { router, register } = rpc([
|
|
80
|
+
* userProcedures,
|
|
81
|
+
* postProcedures,
|
|
82
|
+
* ] as const);
|
|
83
|
+
*
|
|
84
|
+
* // Register tRPC routes
|
|
85
|
+
* await register(app.server);
|
|
86
|
+
*
|
|
87
|
+
* // Export type for clients - fully typed!
|
|
88
|
+
* export type AppRouter = typeof router;
|
|
89
|
+
*
|
|
90
|
+
* await app.start();
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @example With custom prefix
|
|
94
|
+
* ```typescript
|
|
95
|
+
* const { router, register } = rpc([userProcedures] as const, {
|
|
96
|
+
* prefix: '/api/trpc',
|
|
97
|
+
* });
|
|
98
|
+
*
|
|
99
|
+
* await register(app.server);
|
|
100
|
+
* export type AppRouter = typeof router;
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* @example Combined with REST
|
|
104
|
+
* ```typescript
|
|
105
|
+
* // Serve same procedures via both REST and tRPC
|
|
106
|
+
* const collections = [userProcedures, postProcedures] as const;
|
|
107
|
+
*
|
|
108
|
+
* // REST endpoints at /api/*
|
|
109
|
+
* app.routes(rest([...collections], { prefix: '/api' }));
|
|
110
|
+
*
|
|
111
|
+
* // tRPC endpoints at /trpc/*
|
|
112
|
+
* const { router, register } = rpc(collections);
|
|
113
|
+
* await register(app.server);
|
|
114
|
+
*
|
|
115
|
+
* export type AppRouter = typeof router;
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export declare function rpc<const T extends readonly ProcedureCollection[]>(collections: T, options?: RpcOptions): RpcResult<T>;
|
|
119
|
+
/**
|
|
120
|
+
* Register tRPC routes and return the typed router
|
|
121
|
+
*
|
|
122
|
+
* This is a convenience function that combines router creation and
|
|
123
|
+
* registration in a single async call. Use this when you don't need
|
|
124
|
+
* to separate router creation from registration.
|
|
125
|
+
*
|
|
126
|
+
* **IMPORTANT**: Use `as const` on the collections array to preserve
|
|
127
|
+
* literal types for full type inference.
|
|
128
|
+
*
|
|
129
|
+
* @param app - VeloxApp instance
|
|
130
|
+
* @param collections - Array of procedure collections (use `as const`)
|
|
131
|
+
* @param options - Optional RPC configuration
|
|
132
|
+
* @returns The typed tRPC router
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* const router = await registerRpc(app, [
|
|
137
|
+
* userProcedures,
|
|
138
|
+
* postProcedures,
|
|
139
|
+
* ] as const);
|
|
140
|
+
*
|
|
141
|
+
* export type AppRouter = typeof router;
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
export declare function registerRpc<const T extends readonly ProcedureCollection[]>(app: VeloxApp, collections: T, options?: RpcOptions): Promise<AnyRouter & InferRouterFromCollections<T>>;
|
package/dist/rpc.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RPC helper for type-safe tRPC registration
|
|
3
|
+
*
|
|
4
|
+
* Provides a symmetric API to `rest()` for registering tRPC endpoints
|
|
5
|
+
* with full type preservation for client inference.
|
|
6
|
+
*
|
|
7
|
+
* @module rpc
|
|
8
|
+
*/
|
|
9
|
+
import { fail } from '@veloxts/core';
|
|
10
|
+
import { appRouter, registerTRPCPlugin, trpc, } from './trpc/index.js';
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Main Function
|
|
13
|
+
// ============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Create a type-safe tRPC router from procedure collections
|
|
16
|
+
*
|
|
17
|
+
* This is the RPC equivalent of `rest()`. It returns a typed router
|
|
18
|
+
* and a registration function, enabling proper type inference for
|
|
19
|
+
* client-side usage.
|
|
20
|
+
*
|
|
21
|
+
* **IMPORTANT**: Use `as const` on the collections array to preserve
|
|
22
|
+
* literal types for full type inference.
|
|
23
|
+
*
|
|
24
|
+
* @param collections - Array of procedure collections (use `as const`)
|
|
25
|
+
* @param options - Optional RPC configuration
|
|
26
|
+
* @returns RpcResult with typed router and register function
|
|
27
|
+
*
|
|
28
|
+
* @example Basic usage with VeloxApp
|
|
29
|
+
* ```typescript
|
|
30
|
+
* import { veloxApp } from '@veloxts/core';
|
|
31
|
+
* import { rpc } from '@veloxts/router';
|
|
32
|
+
*
|
|
33
|
+
* const app = await veloxApp({ port: 3030 });
|
|
34
|
+
*
|
|
35
|
+
* const { router, register } = rpc([
|
|
36
|
+
* userProcedures,
|
|
37
|
+
* postProcedures,
|
|
38
|
+
* ] as const);
|
|
39
|
+
*
|
|
40
|
+
* // Register tRPC routes
|
|
41
|
+
* await register(app.server);
|
|
42
|
+
*
|
|
43
|
+
* // Export type for clients - fully typed!
|
|
44
|
+
* export type AppRouter = typeof router;
|
|
45
|
+
*
|
|
46
|
+
* await app.start();
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example With custom prefix
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const { router, register } = rpc([userProcedures] as const, {
|
|
52
|
+
* prefix: '/api/trpc',
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* await register(app.server);
|
|
56
|
+
* export type AppRouter = typeof router;
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @example Combined with REST
|
|
60
|
+
* ```typescript
|
|
61
|
+
* // Serve same procedures via both REST and tRPC
|
|
62
|
+
* const collections = [userProcedures, postProcedures] as const;
|
|
63
|
+
*
|
|
64
|
+
* // REST endpoints at /api/*
|
|
65
|
+
* app.routes(rest([...collections], { prefix: '/api' }));
|
|
66
|
+
*
|
|
67
|
+
* // tRPC endpoints at /trpc/*
|
|
68
|
+
* const { router, register } = rpc(collections);
|
|
69
|
+
* await register(app.server);
|
|
70
|
+
*
|
|
71
|
+
* export type AppRouter = typeof router;
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export function rpc(collections, options = {}) {
|
|
75
|
+
const { prefix = '/trpc' } = options;
|
|
76
|
+
// Validate inputs
|
|
77
|
+
if (collections.length === 0) {
|
|
78
|
+
throw fail('VELOX-2006');
|
|
79
|
+
}
|
|
80
|
+
// Create the typed router immediately
|
|
81
|
+
const t = trpc();
|
|
82
|
+
const router = appRouter(t, collections);
|
|
83
|
+
// Create the registration function
|
|
84
|
+
const register = async (server) => {
|
|
85
|
+
await registerTRPCPlugin(server, {
|
|
86
|
+
prefix,
|
|
87
|
+
router,
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
return {
|
|
91
|
+
router,
|
|
92
|
+
register,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
// ============================================================================
|
|
96
|
+
// Async Helper (Alternative API)
|
|
97
|
+
// ============================================================================
|
|
98
|
+
/**
|
|
99
|
+
* Register tRPC routes and return the typed router
|
|
100
|
+
*
|
|
101
|
+
* This is a convenience function that combines router creation and
|
|
102
|
+
* registration in a single async call. Use this when you don't need
|
|
103
|
+
* to separate router creation from registration.
|
|
104
|
+
*
|
|
105
|
+
* **IMPORTANT**: Use `as const` on the collections array to preserve
|
|
106
|
+
* literal types for full type inference.
|
|
107
|
+
*
|
|
108
|
+
* @param app - VeloxApp instance
|
|
109
|
+
* @param collections - Array of procedure collections (use `as const`)
|
|
110
|
+
* @param options - Optional RPC configuration
|
|
111
|
+
* @returns The typed tRPC router
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* const router = await registerRpc(app, [
|
|
116
|
+
* userProcedures,
|
|
117
|
+
* postProcedures,
|
|
118
|
+
* ] as const);
|
|
119
|
+
*
|
|
120
|
+
* export type AppRouter = typeof router;
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export async function registerRpc(app, collections, options = {}) {
|
|
124
|
+
const { router, register } = rpc(collections, options);
|
|
125
|
+
await register(app.server);
|
|
126
|
+
return router;
|
|
127
|
+
}
|
package/dist/trpc/adapter.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module trpc/adapter
|
|
8
8
|
*/
|
|
9
|
-
import type { AnyRouter as TRPCAnyRouter } from '@trpc/server';
|
|
9
|
+
import type { AnyRouter as TRPCAnyRouter, TRPCMutationProcedure, TRPCQueryProcedure } from '@trpc/server';
|
|
10
10
|
import { TRPCError } from '@trpc/server';
|
|
11
11
|
import type { BaseContext } from '@veloxts/core';
|
|
12
12
|
import type { FastifyInstance } from 'fastify';
|
|
@@ -17,7 +17,83 @@ import type { FastifyInstance } from 'fastify';
|
|
|
17
17
|
* which helps avoid TypeScript compilation memory issues with tRPC v11.7+.
|
|
18
18
|
*/
|
|
19
19
|
export type AnyRouter = TRPCAnyRouter;
|
|
20
|
-
import type { ProcedureCollection } from '../types.js';
|
|
20
|
+
import type { CompiledProcedure, ProcedureCollection, ProcedureRecord } from '../types.js';
|
|
21
|
+
/**
|
|
22
|
+
* Maps a VeloxTS CompiledProcedure to the corresponding tRPC procedure type
|
|
23
|
+
*
|
|
24
|
+
* This preserves the input/output types through the type mapping, enabling
|
|
25
|
+
* proper type inference when using the router on the client.
|
|
26
|
+
*
|
|
27
|
+
* Note: The `meta` field is required by tRPC's BuiltProcedureDef interface.
|
|
28
|
+
* We use `unknown` since VeloxTS doesn't use procedure-level metadata.
|
|
29
|
+
*/
|
|
30
|
+
export type MapProcedureToTRPC<T extends CompiledProcedure> = T extends CompiledProcedure<infer TInput, infer TOutput, BaseContext, 'query'> ? TRPCQueryProcedure<{
|
|
31
|
+
input: TInput;
|
|
32
|
+
output: TOutput;
|
|
33
|
+
meta: unknown;
|
|
34
|
+
}> : T extends CompiledProcedure<infer TInput, infer TOutput, BaseContext, 'mutation'> ? TRPCMutationProcedure<{
|
|
35
|
+
input: TInput;
|
|
36
|
+
output: TOutput;
|
|
37
|
+
meta: unknown;
|
|
38
|
+
}> : never;
|
|
39
|
+
/**
|
|
40
|
+
* Maps a ProcedureRecord to a tRPC router record with proper types
|
|
41
|
+
*
|
|
42
|
+
* This preserves each procedure's input/output types through the mapping.
|
|
43
|
+
*/
|
|
44
|
+
export type MapProcedureRecordToTRPC<T extends ProcedureRecord> = {
|
|
45
|
+
[K in keyof T]: MapProcedureToTRPC<T[K]>;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Extracts the namespace from a ProcedureCollection
|
|
49
|
+
*/
|
|
50
|
+
export type ExtractNamespace<T> = T extends ProcedureCollection<infer N, ProcedureRecord> ? N : never;
|
|
51
|
+
/**
|
|
52
|
+
* Extracts the procedures record from a ProcedureCollection
|
|
53
|
+
*/
|
|
54
|
+
export type ExtractProcedures<T> = T extends ProcedureCollection<string, infer P> ? P : never;
|
|
55
|
+
/**
|
|
56
|
+
* Maps a tuple of ProcedureCollections to a tRPC router record
|
|
57
|
+
*
|
|
58
|
+
* This creates a properly typed object where each key is the namespace
|
|
59
|
+
* and each value is the mapped procedure record.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* type Collections = [
|
|
64
|
+
* ProcedureCollection<'users', { getUser: CompiledProcedure<...> }>,
|
|
65
|
+
* ProcedureCollection<'posts', { listPosts: CompiledProcedure<...> }>
|
|
66
|
+
* ];
|
|
67
|
+
*
|
|
68
|
+
* type Result = CollectionsToRouterRecord<Collections>;
|
|
69
|
+
* // Result = {
|
|
70
|
+
* // users: { getUser: TRPCQueryProcedure<...> },
|
|
71
|
+
* // posts: { listPosts: TRPCQueryProcedure<...> }
|
|
72
|
+
* // }
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export type CollectionsToRouterRecord<T extends readonly ProcedureCollection[]> = T extends readonly [] ? object : T extends readonly [infer First extends ProcedureCollection, ...infer Rest] ? Rest extends readonly ProcedureCollection[] ? {
|
|
76
|
+
[K in ExtractNamespace<First>]: MapProcedureRecordToTRPC<ExtractProcedures<First>>;
|
|
77
|
+
} & CollectionsToRouterRecord<Rest> : {
|
|
78
|
+
[K in ExtractNamespace<First>]: MapProcedureRecordToTRPC<ExtractProcedures<First>>;
|
|
79
|
+
} : object;
|
|
80
|
+
/**
|
|
81
|
+
* Infers the complete router type from procedure collections
|
|
82
|
+
*
|
|
83
|
+
* This is the main type that should be used for `export type AppRouter = ...`
|
|
84
|
+
* to ensure full type preservation for the tRPC client.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* const collections = [userProcedures, postProcedures] as const;
|
|
89
|
+
* const router = await rpc(app, collections);
|
|
90
|
+
* export type AppRouter = InferRouterFromCollections<typeof collections>;
|
|
91
|
+
*
|
|
92
|
+
* // Client usage:
|
|
93
|
+
* // client.users.getUser({ id: '123' }) // Fully typed!
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export type InferRouterFromCollections<T extends readonly ProcedureCollection[]> = CollectionsToRouterRecord<T>;
|
|
21
97
|
declare const baseTRPC: import("@trpc/server").TRPCRootObject<BaseContext, object, import("@trpc/server").TRPCRuntimeConfigOptions<BaseContext, object>, {
|
|
22
98
|
ctx: BaseContext;
|
|
23
99
|
meta: object;
|
|
@@ -73,10 +149,11 @@ export declare function buildTRPCRouter(t: TRPCInstance<BaseContext>, collection
|
|
|
73
149
|
* Create a namespaced app router from multiple procedure collections
|
|
74
150
|
*
|
|
75
151
|
* Each collection becomes a nested router under its namespace.
|
|
152
|
+
* Use `as const` on the collections array to preserve literal types.
|
|
76
153
|
*
|
|
77
154
|
* @param t - tRPC instance
|
|
78
|
-
* @param collections - Array of procedure collections
|
|
79
|
-
* @returns Merged app router
|
|
155
|
+
* @param collections - Array of procedure collections (use `as const` for best type inference)
|
|
156
|
+
* @returns Merged app router with preserved types
|
|
80
157
|
*
|
|
81
158
|
* @example
|
|
82
159
|
* ```typescript
|
|
@@ -84,21 +161,62 @@ export declare function buildTRPCRouter(t: TRPCInstance<BaseContext>, collection
|
|
|
84
161
|
* const router = appRouter(t, [
|
|
85
162
|
* userProcedures, // namespace: 'users'
|
|
86
163
|
* postProcedures, // namespace: 'posts'
|
|
87
|
-
* ]);
|
|
164
|
+
* ] as const);
|
|
88
165
|
*
|
|
89
166
|
* // Usage:
|
|
90
167
|
* // router.users.getUser({ id: '123' })
|
|
91
168
|
* // router.posts.listPosts({ page: 1 })
|
|
92
169
|
*
|
|
93
|
-
* // Export type for client
|
|
170
|
+
* // Export type for client - fully typed!
|
|
94
171
|
* export type AppRouter = typeof router;
|
|
95
172
|
* ```
|
|
96
173
|
*/
|
|
97
|
-
export declare function appRouter(t: TRPCInstance<BaseContext>, collections:
|
|
174
|
+
export declare function appRouter<const T extends readonly ProcedureCollection[]>(t: TRPCInstance<BaseContext>, collections: T): AnyRouter & InferRouterFromCollections<T>;
|
|
98
175
|
/**
|
|
99
|
-
* Helper type to infer the AppRouter type
|
|
176
|
+
* Helper type to infer the AppRouter type from procedure collections
|
|
177
|
+
*
|
|
178
|
+
* @deprecated Use `InferRouterFromCollections<T>` instead for better type inference.
|
|
179
|
+
* This type alias is kept for backward compatibility.
|
|
100
180
|
*/
|
|
101
|
-
export type InferAppRouter =
|
|
181
|
+
export type InferAppRouter<T extends readonly ProcedureCollection[] = readonly ProcedureCollection[]> = InferRouterFromCollections<T>;
|
|
182
|
+
/**
|
|
183
|
+
* Converts a VeloxTS router to a tRPC-compatible type for `@trpc/react-query`.
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```typescript
|
|
187
|
+
* import { createTRPCReact } from '@trpc/react-query';
|
|
188
|
+
* import type { TRPCRouter } from '@veloxts/router';
|
|
189
|
+
* import type { AppRouter } from '../api';
|
|
190
|
+
*
|
|
191
|
+
* export const trpc = createTRPCReact<TRPCRouter<AppRouter>>();
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* @see {@link InferRouterFromCollections} for transforming collections array types
|
|
195
|
+
*/
|
|
196
|
+
export type TRPCRouter<TRouter> = TRouter extends Record<string, ProcedureCollection<string, ProcedureRecord>> ? TRPCRouterBase & {
|
|
197
|
+
[K in keyof TRouter]: TRouter[K] extends ProcedureCollection<string, infer P extends ProcedureRecord> ? MapProcedureRecordToTRPC<P> : never;
|
|
198
|
+
} : never;
|
|
199
|
+
/**
|
|
200
|
+
* @deprecated Use `TRPCRouter` instead. Will be removed in v1.0.
|
|
201
|
+
*/
|
|
202
|
+
export type AsTRPCRouter<TRouter> = TRPCRouter<TRouter>;
|
|
203
|
+
/**
|
|
204
|
+
* tRPC router structural requirements for type compatibility.
|
|
205
|
+
* @internal
|
|
206
|
+
*/
|
|
207
|
+
type TRPCRouterBase = {
|
|
208
|
+
_def: {
|
|
209
|
+
_config: {
|
|
210
|
+
$types: {
|
|
211
|
+
ctx: BaseContext;
|
|
212
|
+
meta: unknown;
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
record: Record<string, unknown>;
|
|
216
|
+
procedures: Record<string, unknown>;
|
|
217
|
+
};
|
|
218
|
+
createCaller: (ctx: unknown) => unknown;
|
|
219
|
+
};
|
|
102
220
|
/**
|
|
103
221
|
* Create a tRPC context factory for Fastify
|
|
104
222
|
*
|
|
@@ -126,6 +244,17 @@ export declare function createTRPCContextFactory(): ({ req }: {
|
|
|
126
244
|
context?: BaseContext;
|
|
127
245
|
};
|
|
128
246
|
}) => BaseContext;
|
|
247
|
+
/**
|
|
248
|
+
* Cause structure for VeloxTS errors converted to tRPC errors
|
|
249
|
+
*/
|
|
250
|
+
export interface VeloxTRPCCause {
|
|
251
|
+
/** Discriminator for VeloxTS errors */
|
|
252
|
+
readonly source: 'velox';
|
|
253
|
+
/** VeloxTS error code */
|
|
254
|
+
readonly code?: string;
|
|
255
|
+
/** Guard name (only present for GuardError) */
|
|
256
|
+
readonly guardName?: string;
|
|
257
|
+
}
|
|
129
258
|
/**
|
|
130
259
|
* Convert a VeloxTS error to a tRPC error
|
|
131
260
|
*
|
|
@@ -147,7 +276,7 @@ export declare function veloxErrorToTRPCError(error: Error & {
|
|
|
147
276
|
* using veloxErrorToTRPCError().
|
|
148
277
|
*/
|
|
149
278
|
export declare function isVeloxTRPCError(error: TRPCError): error is TRPCError & {
|
|
150
|
-
cause:
|
|
279
|
+
cause: VeloxTRPCCause;
|
|
151
280
|
};
|
|
152
281
|
/**
|
|
153
282
|
* Options for tRPC plugin registration
|