@veloxts/router 0.7.1 → 0.7.3
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 +17 -0
- package/GUIDE.md +14 -14
- package/dist/openapi/generator.js +42 -101
- package/dist/openapi/path-extractor.js +1 -1
- package/dist/procedure/builder.js +2 -47
- package/dist/rest/adapter.js +2 -21
- package/dist/trpc/adapter.js +6 -22
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @veloxts/router
|
|
2
2
|
|
|
3
|
+
## 0.7.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- feat(cli): auto-populate Zod schemas from Prisma model fields
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @veloxts/core@0.7.3
|
|
10
|
+
- @veloxts/validation@0.7.3
|
|
11
|
+
|
|
12
|
+
## 0.7.2
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- simplify code for clarity and maintainability
|
|
17
|
+
- Updated dependencies
|
|
18
|
+
- @veloxts/core@0.7.2
|
|
19
|
+
|
|
3
20
|
## 0.7.1
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/GUIDE.md
CHANGED
|
@@ -503,7 +503,7 @@ export const userProcedures = procedures('users', {
|
|
|
503
503
|
.input(z.object({ id: z.string().uuid() }))
|
|
504
504
|
.query(async ({ input, ctx }) => {
|
|
505
505
|
const user = await ctx.db.user.findUniqueOrThrow({ where: { id: input.id } });
|
|
506
|
-
return resource(user, UserSchema
|
|
506
|
+
return resource(user, UserSchema.public);
|
|
507
507
|
}),
|
|
508
508
|
|
|
509
509
|
// Conditional projection based on ownership
|
|
@@ -514,9 +514,9 @@ export const userProcedures = procedures('users', {
|
|
|
514
514
|
const user = await ctx.db.user.findUniqueOrThrow({ where: { id: input.id } });
|
|
515
515
|
// Show more fields if viewing own profile
|
|
516
516
|
if (user.id === ctx.user?.id) {
|
|
517
|
-
return resource(user, UserSchema
|
|
517
|
+
return resource(user, UserSchema.authenticated);
|
|
518
518
|
}
|
|
519
|
-
return resource(user, UserSchema
|
|
519
|
+
return resource(user, UserSchema.public);
|
|
520
520
|
}),
|
|
521
521
|
|
|
522
522
|
// Admin with explicit projection
|
|
@@ -525,7 +525,7 @@ export const userProcedures = procedures('users', {
|
|
|
525
525
|
.input(z.object({ id: z.string().uuid() }))
|
|
526
526
|
.query(async ({ input, ctx }) => {
|
|
527
527
|
const user = await ctx.db.user.findUniqueOrThrow({ where: { id: input.id } });
|
|
528
|
-
return resource(user, UserSchema
|
|
528
|
+
return resource(user, UserSchema.admin);
|
|
529
529
|
}),
|
|
530
530
|
});
|
|
531
531
|
```
|
|
@@ -554,7 +554,7 @@ const listUsersManual = procedure()
|
|
|
554
554
|
.guard(authenticated)
|
|
555
555
|
.query(async ({ ctx }) => {
|
|
556
556
|
const users = await ctx.db.user.findMany({ take: 50 });
|
|
557
|
-
return resourceCollection(users, UserSchema
|
|
557
|
+
return resourceCollection(users, UserSchema.authenticated);
|
|
558
558
|
});
|
|
559
559
|
```
|
|
560
560
|
|
|
@@ -577,9 +577,9 @@ const getUser = procedure()
|
|
|
577
577
|
|
|
578
578
|
| Method | Fields Included | Use Case |
|
|
579
579
|
|--------|-----------------|----------|
|
|
580
|
-
|
|
|
581
|
-
|
|
|
582
|
-
|
|
|
580
|
+
| `UserSchema.public` | `public` only | Public APIs, unauthenticated users |
|
|
581
|
+
| `UserSchema.authenticated` | `public` + `authenticated` | Logged-in users |
|
|
582
|
+
| `UserSchema.admin` | All fields | Admin dashboards, internal tools |
|
|
583
583
|
| `.for(ctx)` | Auto-detected from context | Dynamic access control |
|
|
584
584
|
|
|
585
585
|
### Type Safety
|
|
@@ -596,14 +596,14 @@ const getProfile = procedure()
|
|
|
596
596
|
});
|
|
597
597
|
// Return type: { id: string; name: string; email: string; createdAt: Date }
|
|
598
598
|
|
|
599
|
-
//
|
|
600
|
-
const result = resource(user, UserSchema
|
|
599
|
+
// Tagged view projection - type inferred from schema view
|
|
600
|
+
const result = resource(user, UserSchema.public);
|
|
601
601
|
// Type: { id: string; name: string }
|
|
602
602
|
|
|
603
|
-
const authResult = resource(user, UserSchema
|
|
603
|
+
const authResult = resource(user, UserSchema.authenticated);
|
|
604
604
|
// Type: { id: string; name: string; email: string; createdAt: Date }
|
|
605
605
|
|
|
606
|
-
const adminResult = resource(user, UserSchema
|
|
606
|
+
const adminResult = resource(user, UserSchema.admin);
|
|
607
607
|
// Type: { id: string; name: string; email: string; createdAt: Date; internalNotes: string | null; lastLoginIp: string | null }
|
|
608
608
|
```
|
|
609
609
|
|
|
@@ -612,8 +612,8 @@ const adminResult = resource(user, UserSchema).forAdmin();
|
|
|
612
612
|
| Scenario | Approach |
|
|
613
613
|
|----------|----------|
|
|
614
614
|
| Guard determines access level | **Automatic** (`.guardNarrow().resource()`) |
|
|
615
|
-
| Public endpoints (no guard) |
|
|
616
|
-
| Conditional/dynamic projection |
|
|
615
|
+
| Public endpoints (no guard) | Tagged view (`UserSchema.public`) |
|
|
616
|
+
| Conditional/dynamic projection | Tagged view or `.for(ctx)` in handler |
|
|
617
617
|
| Simple, declarative code | **Automatic** |
|
|
618
618
|
| Complex access logic | Manual
|
|
619
619
|
|
|
@@ -201,6 +201,42 @@ function hasProperties(schema) {
|
|
|
201
201
|
// ============================================================================
|
|
202
202
|
// Response Generation
|
|
203
203
|
// ============================================================================
|
|
204
|
+
/**
|
|
205
|
+
* Creates a standard error response schema with the given example code
|
|
206
|
+
*
|
|
207
|
+
* @param exampleCode - Example error code (e.g., 'VALIDATION_ERROR', 'NOT_FOUND')
|
|
208
|
+
* @param extraProperties - Additional properties on the error object (e.g., details)
|
|
209
|
+
*/
|
|
210
|
+
function createErrorSchema(exampleCode, extraProperties) {
|
|
211
|
+
return {
|
|
212
|
+
type: 'object',
|
|
213
|
+
properties: {
|
|
214
|
+
error: {
|
|
215
|
+
type: 'object',
|
|
216
|
+
properties: {
|
|
217
|
+
code: { type: 'string', example: exampleCode },
|
|
218
|
+
message: { type: 'string' },
|
|
219
|
+
...extraProperties,
|
|
220
|
+
},
|
|
221
|
+
required: ['code', 'message'],
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
required: ['error'],
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Creates a standard error response with the given description and example code
|
|
229
|
+
*/
|
|
230
|
+
function createErrorResponse(description, exampleCode) {
|
|
231
|
+
return {
|
|
232
|
+
description,
|
|
233
|
+
content: {
|
|
234
|
+
'application/json': {
|
|
235
|
+
schema: createErrorSchema(exampleCode),
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}
|
|
204
240
|
/**
|
|
205
241
|
* Builds response definitions for an operation
|
|
206
242
|
*/
|
|
@@ -211,7 +247,6 @@ function buildResponses(method, outputSchema, hasAuth) {
|
|
|
211
247
|
const successDescription = getSuccessDescription(method);
|
|
212
248
|
// Success response
|
|
213
249
|
if (successCode === '204') {
|
|
214
|
-
// No content
|
|
215
250
|
responses['204'] = { description: successDescription };
|
|
216
251
|
}
|
|
217
252
|
else {
|
|
@@ -224,120 +259,26 @@ function buildResponses(method, outputSchema, hasAuth) {
|
|
|
224
259
|
}),
|
|
225
260
|
};
|
|
226
261
|
}
|
|
227
|
-
//
|
|
262
|
+
// Validation error
|
|
228
263
|
responses['400'] = {
|
|
229
264
|
description: 'Bad Request - Validation error',
|
|
230
265
|
content: {
|
|
231
266
|
'application/json': {
|
|
232
|
-
schema: {
|
|
233
|
-
type: 'object',
|
|
234
|
-
properties: {
|
|
235
|
-
error: {
|
|
236
|
-
type: 'object',
|
|
237
|
-
properties: {
|
|
238
|
-
code: { type: 'string', example: 'VALIDATION_ERROR' },
|
|
239
|
-
message: { type: 'string' },
|
|
240
|
-
details: { type: 'object' },
|
|
241
|
-
},
|
|
242
|
-
required: ['code', 'message'],
|
|
243
|
-
},
|
|
244
|
-
},
|
|
245
|
-
required: ['error'],
|
|
246
|
-
},
|
|
267
|
+
schema: createErrorSchema('VALIDATION_ERROR', { details: { type: 'object' } }),
|
|
247
268
|
},
|
|
248
269
|
},
|
|
249
270
|
};
|
|
250
271
|
// Auth-related responses
|
|
251
272
|
if (hasAuth) {
|
|
252
|
-
responses['401'] =
|
|
253
|
-
|
|
254
|
-
content: {
|
|
255
|
-
'application/json': {
|
|
256
|
-
schema: {
|
|
257
|
-
type: 'object',
|
|
258
|
-
properties: {
|
|
259
|
-
error: {
|
|
260
|
-
type: 'object',
|
|
261
|
-
properties: {
|
|
262
|
-
code: { type: 'string', example: 'UNAUTHORIZED' },
|
|
263
|
-
message: { type: 'string' },
|
|
264
|
-
},
|
|
265
|
-
required: ['code', 'message'],
|
|
266
|
-
},
|
|
267
|
-
},
|
|
268
|
-
required: ['error'],
|
|
269
|
-
},
|
|
270
|
-
},
|
|
271
|
-
},
|
|
272
|
-
};
|
|
273
|
-
responses['403'] = {
|
|
274
|
-
description: 'Forbidden - Insufficient permissions',
|
|
275
|
-
content: {
|
|
276
|
-
'application/json': {
|
|
277
|
-
schema: {
|
|
278
|
-
type: 'object',
|
|
279
|
-
properties: {
|
|
280
|
-
error: {
|
|
281
|
-
type: 'object',
|
|
282
|
-
properties: {
|
|
283
|
-
code: { type: 'string', example: 'FORBIDDEN' },
|
|
284
|
-
message: { type: 'string' },
|
|
285
|
-
},
|
|
286
|
-
required: ['code', 'message'],
|
|
287
|
-
},
|
|
288
|
-
},
|
|
289
|
-
required: ['error'],
|
|
290
|
-
},
|
|
291
|
-
},
|
|
292
|
-
},
|
|
293
|
-
};
|
|
273
|
+
responses['401'] = createErrorResponse('Unauthorized - Authentication required', 'UNAUTHORIZED');
|
|
274
|
+
responses['403'] = createErrorResponse('Forbidden - Insufficient permissions', 'FORBIDDEN');
|
|
294
275
|
}
|
|
295
276
|
// Not found for single-resource operations
|
|
296
277
|
if (['GET', 'PUT', 'PATCH', 'DELETE'].includes(method)) {
|
|
297
|
-
responses['404'] =
|
|
298
|
-
description: 'Not Found - Resource does not exist',
|
|
299
|
-
content: {
|
|
300
|
-
'application/json': {
|
|
301
|
-
schema: {
|
|
302
|
-
type: 'object',
|
|
303
|
-
properties: {
|
|
304
|
-
error: {
|
|
305
|
-
type: 'object',
|
|
306
|
-
properties: {
|
|
307
|
-
code: { type: 'string', example: 'NOT_FOUND' },
|
|
308
|
-
message: { type: 'string' },
|
|
309
|
-
},
|
|
310
|
-
required: ['code', 'message'],
|
|
311
|
-
},
|
|
312
|
-
},
|
|
313
|
-
required: ['error'],
|
|
314
|
-
},
|
|
315
|
-
},
|
|
316
|
-
},
|
|
317
|
-
};
|
|
278
|
+
responses['404'] = createErrorResponse('Not Found - Resource does not exist', 'NOT_FOUND');
|
|
318
279
|
}
|
|
319
280
|
// Internal server error
|
|
320
|
-
responses['500'] =
|
|
321
|
-
description: 'Internal Server Error',
|
|
322
|
-
content: {
|
|
323
|
-
'application/json': {
|
|
324
|
-
schema: {
|
|
325
|
-
type: 'object',
|
|
326
|
-
properties: {
|
|
327
|
-
error: {
|
|
328
|
-
type: 'object',
|
|
329
|
-
properties: {
|
|
330
|
-
code: { type: 'string', example: 'INTERNAL_ERROR' },
|
|
331
|
-
message: { type: 'string' },
|
|
332
|
-
},
|
|
333
|
-
required: ['code', 'message'],
|
|
334
|
-
},
|
|
335
|
-
},
|
|
336
|
-
required: ['error'],
|
|
337
|
-
},
|
|
338
|
-
},
|
|
339
|
-
},
|
|
340
|
-
};
|
|
281
|
+
responses['500'] = createErrorResponse('Internal Server Error', 'INTERNAL_ERROR');
|
|
341
282
|
return responses;
|
|
342
283
|
}
|
|
343
284
|
/**
|
|
@@ -97,7 +97,7 @@ export function parsePathParameters(path, schemas) {
|
|
|
97
97
|
* @returns True if path contains parameters
|
|
98
98
|
*/
|
|
99
99
|
export function hasPathParameters(path) {
|
|
100
|
-
return
|
|
100
|
+
return path.includes(':');
|
|
101
101
|
}
|
|
102
102
|
/**
|
|
103
103
|
* Extracts query parameters from a JSON Schema
|
|
@@ -199,26 +199,6 @@ function createBuilder(state) {
|
|
|
199
199
|
mutation(handler) {
|
|
200
200
|
return compileProcedure('mutation', handler, state);
|
|
201
201
|
},
|
|
202
|
-
/**
|
|
203
|
-
* Sets the output type based on a resource schema
|
|
204
|
-
*
|
|
205
|
-
* Accepts either a plain `ResourceSchema` or a tagged schema
|
|
206
|
-
* (e.g., `UserSchema.authenticated`) for declarative auto-projection.
|
|
207
|
-
*
|
|
208
|
-
* @example
|
|
209
|
-
* ```typescript
|
|
210
|
-
* // Tagged schema — auto-projects to authenticated fields
|
|
211
|
-
* procedure()
|
|
212
|
-
* .guard(authenticated)
|
|
213
|
-
* .resource(UserSchema.authenticated)
|
|
214
|
-
* .query(handler);
|
|
215
|
-
*
|
|
216
|
-
* // Plain schema — defaults to public, or derives from guardNarrow
|
|
217
|
-
* procedure()
|
|
218
|
-
* .resource(UserSchema)
|
|
219
|
-
* .query(handler);
|
|
220
|
-
* ```
|
|
221
|
-
*/
|
|
222
202
|
/**
|
|
223
203
|
* Sets the output type based on a resource schema
|
|
224
204
|
*
|
|
@@ -248,9 +228,7 @@ function compileProcedure(type, handler, state) {
|
|
|
248
228
|
const typedMiddlewares = state.middlewares;
|
|
249
229
|
// Pre-compile the middleware chain executor if middlewares exist
|
|
250
230
|
// This avoids rebuilding the chain on every request
|
|
251
|
-
const precompiledExecutor = typedMiddlewares.length > 0
|
|
252
|
-
? createPrecompiledMiddlewareExecutor(typedMiddlewares, handler)
|
|
253
|
-
: undefined;
|
|
231
|
+
const precompiledExecutor = typedMiddlewares.length > 0 ? createMiddlewareExecutor(typedMiddlewares, handler) : undefined;
|
|
254
232
|
// Create the final procedure object
|
|
255
233
|
return {
|
|
256
234
|
type,
|
|
@@ -272,18 +250,6 @@ function compileProcedure(type, handler, state) {
|
|
|
272
250
|
_resourceLevel: state.resourceLevel,
|
|
273
251
|
};
|
|
274
252
|
}
|
|
275
|
-
/**
|
|
276
|
-
* Creates a pre-compiled middleware chain executor
|
|
277
|
-
*
|
|
278
|
-
* PERFORMANCE: This function builds the middleware chain once during procedure
|
|
279
|
-
* compilation, creating a single reusable function that executes the entire chain.
|
|
280
|
-
* This eliminates the need to rebuild closures on every request.
|
|
281
|
-
*
|
|
282
|
-
* @internal
|
|
283
|
-
*/
|
|
284
|
-
function createPrecompiledMiddlewareExecutor(middlewares, handler) {
|
|
285
|
-
return createMiddlewareExecutor(middlewares, handler);
|
|
286
|
-
}
|
|
287
253
|
/**
|
|
288
254
|
* Defines a collection of procedures under a namespace
|
|
289
255
|
*
|
|
@@ -477,7 +443,7 @@ export async function executeProcedure(procedure, rawInput, ctx) {
|
|
|
477
443
|
}
|
|
478
444
|
else {
|
|
479
445
|
// Fallback: Build middleware chain dynamically (should not normally happen)
|
|
480
|
-
result = await
|
|
446
|
+
result = await executeMiddlewareChain(procedure.middlewares, input, ctxWithLevel, async () => procedure.handler({ input, ctx: ctxWithLevel }));
|
|
481
447
|
}
|
|
482
448
|
// Step 4: Auto-project if resource schema is set
|
|
483
449
|
if (procedure._resourceSchema) {
|
|
@@ -508,17 +474,6 @@ export async function executeProcedure(procedure, rawInput, ctx) {
|
|
|
508
474
|
}
|
|
509
475
|
return result;
|
|
510
476
|
}
|
|
511
|
-
/**
|
|
512
|
-
* Fallback middleware chain executor for edge cases
|
|
513
|
-
*
|
|
514
|
-
* This function is only used when _precompiledExecutor is not available,
|
|
515
|
-
* which should be rare in normal operation.
|
|
516
|
-
*
|
|
517
|
-
* @internal
|
|
518
|
-
*/
|
|
519
|
-
async function executeMiddlewareChainFallback(middlewares, input, ctx, handler) {
|
|
520
|
-
return executeMiddlewareChain(middlewares, input, ctx, handler);
|
|
521
|
-
}
|
|
522
477
|
// ============================================================================
|
|
523
478
|
// Type Utilities
|
|
524
479
|
// ============================================================================
|
package/dist/rest/adapter.js
CHANGED
|
@@ -222,10 +222,8 @@ function gatherInput(request, route) {
|
|
|
222
222
|
(route.procedure.parentResources !== undefined && route.procedure.parentResources.length > 0);
|
|
223
223
|
switch (route.method) {
|
|
224
224
|
case 'GET':
|
|
225
|
-
// GET: params (for :id and all parent params) + query (for filters/pagination)
|
|
226
|
-
return { ...params, ...query };
|
|
227
225
|
case 'DELETE':
|
|
228
|
-
// DELETE: params (for :id and all parent params) + query (for options)
|
|
226
|
+
// GET/DELETE: params (for :id and all parent params) + query (for filters/pagination/options)
|
|
229
227
|
return { ...params, ...query };
|
|
230
228
|
case 'PUT':
|
|
231
229
|
case 'PATCH':
|
|
@@ -320,24 +318,7 @@ export function registerRestRoutes(server, collections, options = {}) {
|
|
|
320
318
|
// When used in legacy mode, we prepend the prefix manually.
|
|
321
319
|
const fullPath = _prefixHandledByFastify ? route.path : `${prefix}${route.path}`;
|
|
322
320
|
const handler = createRouteHandler(route);
|
|
323
|
-
|
|
324
|
-
switch (route.method) {
|
|
325
|
-
case 'GET':
|
|
326
|
-
server.get(fullPath, handler);
|
|
327
|
-
break;
|
|
328
|
-
case 'POST':
|
|
329
|
-
server.post(fullPath, handler);
|
|
330
|
-
break;
|
|
331
|
-
case 'PUT':
|
|
332
|
-
server.put(fullPath, handler);
|
|
333
|
-
break;
|
|
334
|
-
case 'PATCH':
|
|
335
|
-
server.patch(fullPath, handler);
|
|
336
|
-
break;
|
|
337
|
-
case 'DELETE':
|
|
338
|
-
server.delete(fullPath, handler);
|
|
339
|
-
break;
|
|
340
|
-
}
|
|
321
|
+
server.route({ method: route.method, url: fullPath, handler });
|
|
341
322
|
}
|
|
342
323
|
}
|
|
343
324
|
}
|
package/dist/trpc/adapter.js
CHANGED
|
@@ -86,38 +86,22 @@ function buildTRPCProcedure(t, procedure) {
|
|
|
86
86
|
if (procedure.outputSchema) {
|
|
87
87
|
builder = builder.output(procedure.outputSchema);
|
|
88
88
|
}
|
|
89
|
-
//
|
|
90
|
-
const handler = procedure
|
|
91
|
-
? createHandler(procedure)
|
|
92
|
-
: createNoInputHandler(procedure);
|
|
89
|
+
// Create handler that works with or without input
|
|
90
|
+
const handler = createProcedureHandler(procedure);
|
|
93
91
|
// Finalize as query or mutation
|
|
94
92
|
return procedure.type === 'query' ? builder.query(handler) : builder.mutation(handler);
|
|
95
93
|
}
|
|
96
94
|
/**
|
|
97
|
-
* Create a handler function
|
|
95
|
+
* Create a tRPC handler function from a compiled procedure
|
|
98
96
|
*
|
|
99
|
-
*
|
|
100
|
-
*/
|
|
101
|
-
function createHandler(procedure) {
|
|
102
|
-
return async (opts) => {
|
|
103
|
-
const { input, ctx } = opts;
|
|
104
|
-
// Execute middleware chain if any
|
|
105
|
-
if (procedure.middlewares.length > 0) {
|
|
106
|
-
return executeWithMiddleware(procedure, input, ctx);
|
|
107
|
-
}
|
|
108
|
-
// Direct handler execution
|
|
109
|
-
return procedure.handler({ input, ctx });
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Create a handler function for a procedure without input
|
|
97
|
+
* Works for both procedures with and without input schemas.
|
|
114
98
|
*
|
|
115
99
|
* @internal
|
|
116
100
|
*/
|
|
117
|
-
function
|
|
101
|
+
function createProcedureHandler(procedure) {
|
|
118
102
|
return async (opts) => {
|
|
119
103
|
const { ctx } = opts;
|
|
120
|
-
const input = undefined;
|
|
104
|
+
const input = opts.input ?? undefined;
|
|
121
105
|
// Execute middleware chain if any
|
|
122
106
|
if (procedure.middlewares.length > 0) {
|
|
123
107
|
return executeWithMiddleware(procedure, input, ctx);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veloxts/router",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "Procedure definitions with tRPC and REST routing for VeloxTS framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@trpc/server": "11.10.0",
|
|
41
41
|
"fastify": "5.7.4",
|
|
42
|
-
"@veloxts/core": "0.7.
|
|
43
|
-
"@veloxts/validation": "0.7.
|
|
42
|
+
"@veloxts/core": "0.7.3",
|
|
43
|
+
"@veloxts/validation": "0.7.3"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@vitest/coverage-v8": "4.0.18",
|