@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/trpc/adapter.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { initTRPC, TRPCError } from '@trpc/server';
|
|
10
10
|
import { isGuardError } from '../errors.js';
|
|
11
|
+
import { executeMiddlewareChain } from '../middleware/chain.js';
|
|
11
12
|
// ============================================================================
|
|
12
13
|
// tRPC Initialization
|
|
13
14
|
// ============================================================================
|
|
@@ -74,33 +75,23 @@ export function buildTRPCRouter(t, collection) {
|
|
|
74
75
|
* @internal
|
|
75
76
|
*/
|
|
76
77
|
function buildTRPCProcedure(t, procedure) {
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
// Both input and output schemas
|
|
82
|
-
const withInput = baseProcedure.input(procedure.inputSchema);
|
|
83
|
-
const withOutput = withInput.output(procedure.outputSchema);
|
|
84
|
-
const handler = createHandler(procedure);
|
|
85
|
-
return procedure.type === 'query' ? withOutput.query(handler) : withOutput.mutation(handler);
|
|
86
|
-
}
|
|
78
|
+
// Build the procedure chain incrementally
|
|
79
|
+
// biome-ignore lint/suspicious/noExplicitAny: tRPC procedure builder has complex types that vary by chain state
|
|
80
|
+
let builder = t.procedure;
|
|
81
|
+
// Add input schema if present
|
|
87
82
|
if (procedure.inputSchema) {
|
|
88
|
-
|
|
89
|
-
const withInput = baseProcedure.input(procedure.inputSchema);
|
|
90
|
-
const handler = createHandler(procedure);
|
|
91
|
-
return procedure.type === 'query' ? withInput.query(handler) : withInput.mutation(handler);
|
|
83
|
+
builder = builder.input(procedure.inputSchema);
|
|
92
84
|
}
|
|
85
|
+
// Add output schema if present
|
|
93
86
|
if (procedure.outputSchema) {
|
|
94
|
-
|
|
95
|
-
const withOutput = baseProcedure.output(procedure.outputSchema);
|
|
96
|
-
const handler = createNoInputHandler(procedure);
|
|
97
|
-
return procedure.type === 'query' ? withOutput.query(handler) : withOutput.mutation(handler);
|
|
87
|
+
builder = builder.output(procedure.outputSchema);
|
|
98
88
|
}
|
|
99
|
-
//
|
|
100
|
-
const handler =
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
89
|
+
// Select handler based on whether input is expected
|
|
90
|
+
const handler = procedure.inputSchema
|
|
91
|
+
? createHandler(procedure)
|
|
92
|
+
: createNoInputHandler(procedure);
|
|
93
|
+
// Finalize as query or mutation
|
|
94
|
+
return procedure.type === 'query' ? builder.query(handler) : builder.mutation(handler);
|
|
104
95
|
}
|
|
105
96
|
/**
|
|
106
97
|
* Create a handler function for a procedure with input
|
|
@@ -141,31 +132,7 @@ function createNoInputHandler(procedure) {
|
|
|
141
132
|
* @internal
|
|
142
133
|
*/
|
|
143
134
|
async function executeWithMiddleware(procedure, input, ctx) {
|
|
144
|
-
|
|
145
|
-
let next = async () => {
|
|
146
|
-
const output = await procedure.handler({ input, ctx });
|
|
147
|
-
return { output };
|
|
148
|
-
};
|
|
149
|
-
// Wrap each middleware from last to first
|
|
150
|
-
for (let i = procedure.middlewares.length - 1; i >= 0; i--) {
|
|
151
|
-
const middleware = procedure.middlewares[i];
|
|
152
|
-
const currentNext = next;
|
|
153
|
-
next = async () => {
|
|
154
|
-
return middleware({
|
|
155
|
-
input,
|
|
156
|
-
ctx,
|
|
157
|
-
next: async (opts) => {
|
|
158
|
-
// Allow middleware to extend context
|
|
159
|
-
if (opts?.ctx) {
|
|
160
|
-
Object.assign(ctx, opts.ctx);
|
|
161
|
-
}
|
|
162
|
-
return currentNext();
|
|
163
|
-
},
|
|
164
|
-
});
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
const result = await next();
|
|
168
|
-
return result.output;
|
|
135
|
+
return executeMiddlewareChain(procedure.middlewares, input, ctx, async () => procedure.handler({ input, ctx }));
|
|
169
136
|
}
|
|
170
137
|
// ============================================================================
|
|
171
138
|
// App Router Creation
|
|
@@ -174,10 +141,11 @@ async function executeWithMiddleware(procedure, input, ctx) {
|
|
|
174
141
|
* Create a namespaced app router from multiple procedure collections
|
|
175
142
|
*
|
|
176
143
|
* Each collection becomes a nested router under its namespace.
|
|
144
|
+
* Use `as const` on the collections array to preserve literal types.
|
|
177
145
|
*
|
|
178
146
|
* @param t - tRPC instance
|
|
179
|
-
* @param collections - Array of procedure collections
|
|
180
|
-
* @returns Merged app router
|
|
147
|
+
* @param collections - Array of procedure collections (use `as const` for best type inference)
|
|
148
|
+
* @returns Merged app router with preserved types
|
|
181
149
|
*
|
|
182
150
|
* @example
|
|
183
151
|
* ```typescript
|
|
@@ -185,13 +153,13 @@ async function executeWithMiddleware(procedure, input, ctx) {
|
|
|
185
153
|
* const router = appRouter(t, [
|
|
186
154
|
* userProcedures, // namespace: 'users'
|
|
187
155
|
* postProcedures, // namespace: 'posts'
|
|
188
|
-
* ]);
|
|
156
|
+
* ] as const);
|
|
189
157
|
*
|
|
190
158
|
* // Usage:
|
|
191
159
|
* // router.users.getUser({ id: '123' })
|
|
192
160
|
* // router.posts.listPosts({ page: 1 })
|
|
193
161
|
*
|
|
194
|
-
* // Export type for client
|
|
162
|
+
* // Export type for client - fully typed!
|
|
195
163
|
* export type AppRouter = typeof router;
|
|
196
164
|
* ```
|
|
197
165
|
*/
|
|
@@ -239,9 +207,6 @@ export function createTRPCContextFactory() {
|
|
|
239
207
|
return req.context;
|
|
240
208
|
};
|
|
241
209
|
}
|
|
242
|
-
// ============================================================================
|
|
243
|
-
// Error Utilities
|
|
244
|
-
// ============================================================================
|
|
245
210
|
/**
|
|
246
211
|
* Convert a VeloxTS error to a tRPC error
|
|
247
212
|
*
|
|
@@ -268,19 +233,25 @@ export function veloxErrorToTRPCError(error, defaultCode = 'INTERNAL_SERVER_ERRO
|
|
|
268
233
|
const trpcCode = error.statusCode ? (statusToTRPC[error.statusCode] ?? defaultCode) : defaultCode;
|
|
269
234
|
// Handle GuardError specifically to preserve guard metadata
|
|
270
235
|
if (isGuardError(error)) {
|
|
236
|
+
const cause = {
|
|
237
|
+
source: 'velox',
|
|
238
|
+
code: error.code,
|
|
239
|
+
guardName: error.guardName,
|
|
240
|
+
};
|
|
271
241
|
return new TRPCError({
|
|
272
242
|
code: trpcCode,
|
|
273
243
|
message: error.message,
|
|
274
|
-
cause
|
|
275
|
-
code: error.code,
|
|
276
|
-
guardName: error.guardName,
|
|
277
|
-
},
|
|
244
|
+
cause,
|
|
278
245
|
});
|
|
279
246
|
}
|
|
247
|
+
const cause = {
|
|
248
|
+
source: 'velox',
|
|
249
|
+
code: error.code,
|
|
250
|
+
};
|
|
280
251
|
return new TRPCError({
|
|
281
252
|
code: trpcCode,
|
|
282
253
|
message: error.message,
|
|
283
|
-
cause
|
|
254
|
+
cause,
|
|
284
255
|
});
|
|
285
256
|
}
|
|
286
257
|
/**
|
|
@@ -290,7 +261,8 @@ export function veloxErrorToTRPCError(error, defaultCode = 'INTERNAL_SERVER_ERRO
|
|
|
290
261
|
* using veloxErrorToTRPCError().
|
|
291
262
|
*/
|
|
292
263
|
export function isVeloxTRPCError(error) {
|
|
293
|
-
|
|
264
|
+
const cause = error.cause;
|
|
265
|
+
return (cause != null && typeof cause === 'object' && 'source' in cause && cause.source === 'velox');
|
|
294
266
|
}
|
|
295
267
|
/**
|
|
296
268
|
* Register tRPC plugin with Fastify server
|
package/dist/trpc/index.d.ts
CHANGED
|
@@ -3,5 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module trpc
|
|
5
5
|
*/
|
|
6
|
-
export type { AnyRouter,
|
|
6
|
+
export type { AnyRouter,
|
|
7
|
+
/** @deprecated Use `TRPCRouter` instead */
|
|
8
|
+
AsTRPCRouter, CollectionsToRouterRecord, ExtractNamespace, ExtractProcedures, InferAppRouter, InferRouterFromCollections, MapProcedureRecordToTRPC, MapProcedureToTRPC, TRPCInstance, TRPCPluginOptions, TRPCRouter, } from './adapter.js';
|
|
7
9
|
export { appRouter, buildTRPCRouter, createTRPCContextFactory, isVeloxTRPCError, registerTRPCPlugin, trpc, veloxErrorToTRPCError, } from './adapter.js';
|
package/dist/types.d.ts
CHANGED
|
@@ -193,7 +193,7 @@ export interface RestRouteOverride {
|
|
|
193
193
|
/**
|
|
194
194
|
* Parent resource configuration for nested routes
|
|
195
195
|
*
|
|
196
|
-
* Defines
|
|
196
|
+
* Defines a single parent resource relationship for generating nested REST routes
|
|
197
197
|
* like `/posts/:postId/comments/:id`.
|
|
198
198
|
*
|
|
199
199
|
* @example
|
|
@@ -207,16 +207,39 @@ export interface RestRouteOverride {
|
|
|
207
207
|
*/
|
|
208
208
|
export interface ParentResourceConfig {
|
|
209
209
|
/**
|
|
210
|
-
* Parent resource
|
|
211
|
-
* Used to build the parent path segment: `/${
|
|
210
|
+
* Parent resource name (e.g., 'posts', 'users')
|
|
211
|
+
* Used to build the parent path segment: `/${resource}/:${param}`
|
|
212
212
|
*/
|
|
213
|
-
readonly
|
|
213
|
+
readonly resource: string;
|
|
214
214
|
/**
|
|
215
215
|
* Parent resource parameter name in the path
|
|
216
|
-
* Defaults to `${
|
|
216
|
+
* Defaults to `${singularResource}Id` if not specified
|
|
217
217
|
* (e.g., 'posts' -> 'postId', 'users' -> 'userId')
|
|
218
218
|
*/
|
|
219
|
-
readonly
|
|
219
|
+
readonly param: string;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Multi-level parent resource configuration for deeply nested routes
|
|
223
|
+
*
|
|
224
|
+
* Defines multiple parent resources for generating deeply nested REST routes
|
|
225
|
+
* like `/organizations/:orgId/projects/:projectId/tasks/:id`.
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* ```typescript
|
|
229
|
+
* // Multi-level nesting
|
|
230
|
+
* procedure().parents([
|
|
231
|
+
* { resource: 'organizations', param: 'orgId' },
|
|
232
|
+
* { resource: 'projects', param: 'projectId' },
|
|
233
|
+
* ])
|
|
234
|
+
* // Generates: /organizations/:orgId/projects/:projectId/tasks/:id
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
export interface ParentResourceChain {
|
|
238
|
+
/**
|
|
239
|
+
* Array of parent resources from outermost to innermost
|
|
240
|
+
* E.g., [organizations, projects] for /organizations/:orgId/projects/:projectId/tasks
|
|
241
|
+
*/
|
|
242
|
+
readonly parents: readonly ParentResourceConfig[];
|
|
220
243
|
}
|
|
221
244
|
/**
|
|
222
245
|
* Compiled procedure with all metadata and handlers
|
|
@@ -248,8 +271,12 @@ export interface CompiledProcedure<TInput = unknown, TOutput = unknown, TContext
|
|
|
248
271
|
readonly guards: ReadonlyArray<GuardLike<TContext>>;
|
|
249
272
|
/** REST route override (if specified) */
|
|
250
273
|
readonly restOverride?: RestRouteOverride;
|
|
274
|
+
/** Whether this procedure is deprecated */
|
|
275
|
+
readonly deprecated?: boolean;
|
|
276
|
+
/** Deprecation message explaining why and what to use instead */
|
|
277
|
+
readonly deprecationMessage?: string;
|
|
251
278
|
/**
|
|
252
|
-
* Parent resource configuration for nested routes
|
|
279
|
+
* Parent resource configuration for nested routes (single level)
|
|
253
280
|
*
|
|
254
281
|
* When specified, the REST path will be prefixed with the parent resource:
|
|
255
282
|
* `/${parent.namespace}/:${parent.paramName}/${childNamespace}/:id`
|
|
@@ -262,6 +289,23 @@ export interface CompiledProcedure<TInput = unknown, TOutput = unknown, TContext
|
|
|
262
289
|
* ```
|
|
263
290
|
*/
|
|
264
291
|
readonly parentResource?: ParentResourceConfig;
|
|
292
|
+
/**
|
|
293
|
+
* Multi-level parent resource configuration for deeply nested routes
|
|
294
|
+
*
|
|
295
|
+
* When specified, the REST path will be prefixed with all parent resources:
|
|
296
|
+
* `/${parent1.namespace}/:${parent1.paramName}/${parent2.namespace}/:${parent2.paramName}/...`
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* ```typescript
|
|
300
|
+
* // With parentResources: [
|
|
301
|
+
* // { namespace: 'organizations', paramName: 'orgId' },
|
|
302
|
+
* // { namespace: 'projects', paramName: 'projectId' }
|
|
303
|
+
* // ]
|
|
304
|
+
* // and namespace: 'tasks'
|
|
305
|
+
* // Generates: /organizations/:orgId/projects/:projectId/tasks/:id
|
|
306
|
+
* ```
|
|
307
|
+
*/
|
|
308
|
+
readonly parentResources?: readonly ParentResourceConfig[];
|
|
265
309
|
/**
|
|
266
310
|
* Pre-compiled middleware chain executor
|
|
267
311
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veloxts/router",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.86",
|
|
4
4
|
"description": "Procedure definitions with tRPC and REST routing for VeloxTS framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"@trpc/server": "11.8.0",
|
|
41
41
|
"fastify": "5.6.2",
|
|
42
42
|
"zod-to-json-schema": "3.24.5",
|
|
43
|
-
"@veloxts/
|
|
44
|
-
"@veloxts/
|
|
43
|
+
"@veloxts/validation": "0.6.86",
|
|
44
|
+
"@veloxts/core": "0.6.86"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@vitest/coverage-v8": "4.0.16",
|