@veloxts/router 0.6.68 → 0.6.70
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 +87 -0
- package/GUIDE.md +178 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/procedure/builder.js +12 -0
- package/dist/procedure/types.d.ts +35 -0
- package/dist/router-utils.d.ts +91 -0
- package/dist/router-utils.js +73 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,92 @@
|
|
|
1
1
|
# @veloxts/router
|
|
2
2
|
|
|
3
|
+
## 0.6.70
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- ### feat(auth): Unified Adapter-Only Architecture
|
|
8
|
+
|
|
9
|
+
**New Features:**
|
|
10
|
+
|
|
11
|
+
- Add `JwtAdapter` implementing the `AuthAdapter` interface for unified JWT authentication
|
|
12
|
+
- Add `jwtAuth()` convenience function for direct adapter usage with optional built-in routes (`/api/auth/refresh`, `/api/auth/logout`)
|
|
13
|
+
- Add `AuthContext` discriminated union (`NativeAuthContext | AdapterAuthContext`) for type-safe auth mode handling
|
|
14
|
+
- Add double-registration protection to prevent conflicting auth system setups
|
|
15
|
+
- Add shared decoration utilities (`decorateAuth`, `setRequestAuth`, `checkDoubleRegistration`)
|
|
16
|
+
|
|
17
|
+
**Architecture Changes:**
|
|
18
|
+
|
|
19
|
+
- `authPlugin` now uses `JwtAdapter` internally - all authentication flows through the adapter pattern
|
|
20
|
+
- Single code path for authentication (no more dual native/adapter modes)
|
|
21
|
+
- `authContext.authMode` is now always `'adapter'` with `providerId='jwt'` when using `authPlugin`
|
|
22
|
+
|
|
23
|
+
**Breaking Changes:**
|
|
24
|
+
|
|
25
|
+
- Remove deprecated `LegacySessionConfig` interface (use `sessionMiddleware` instead)
|
|
26
|
+
- Remove deprecated `session` field from `AuthConfig`
|
|
27
|
+
- `User` interface no longer has index signature (extend via declaration merging)
|
|
28
|
+
|
|
29
|
+
**Type Safety Improvements:**
|
|
30
|
+
|
|
31
|
+
- `AuthContext` discriminated union enables exhaustive type narrowing based on `authMode`
|
|
32
|
+
- Export `NativeAuthContext` and `AdapterAuthContext` types for explicit typing
|
|
33
|
+
|
|
34
|
+
**Migration:**
|
|
35
|
+
|
|
36
|
+
- Existing `authPlugin` usage remains backward-compatible
|
|
37
|
+
- If checking `authContext.token`, use `authContext.session` instead (token stored in session for adapter mode)
|
|
38
|
+
|
|
39
|
+
- Updated dependencies
|
|
40
|
+
- @veloxts/core@0.6.70
|
|
41
|
+
- @veloxts/validation@0.6.70
|
|
42
|
+
|
|
43
|
+
## 0.6.69
|
|
44
|
+
|
|
45
|
+
### Patch Changes
|
|
46
|
+
|
|
47
|
+
- implement user feedback improvements across packages
|
|
48
|
+
|
|
49
|
+
## Summary
|
|
50
|
+
|
|
51
|
+
Addresses 9 user feedback items to improve DX, reduce boilerplate, and eliminate template duplications.
|
|
52
|
+
|
|
53
|
+
### Phase 1: Validation Helpers (`@veloxts/validation`)
|
|
54
|
+
|
|
55
|
+
- Add `prismaDecimal()`, `prismaDecimalNullable()`, `prismaDecimalOptional()` for Prisma Decimal → number conversion
|
|
56
|
+
- Add `dateToIso`, `dateToIsoNullable`, `dateToIsoOptional` aliases for consistency
|
|
57
|
+
|
|
58
|
+
### Phase 2: Template Deduplication (`@veloxts/auth`)
|
|
59
|
+
|
|
60
|
+
- Export `createEnhancedTokenStore()` with token revocation and refresh token reuse detection
|
|
61
|
+
- Export `parseUserRoles()` and `DEFAULT_ALLOWED_ROLES`
|
|
62
|
+
- Fix memory leak: track pending timeouts for proper cleanup on `destroy()`
|
|
63
|
+
- Update templates to import from `@veloxts/auth` instead of duplicating code
|
|
64
|
+
- Fix jwtManager singleton pattern in templates
|
|
65
|
+
|
|
66
|
+
### Phase 3: Router Helpers (`@veloxts/router`)
|
|
67
|
+
|
|
68
|
+
- Add `createRouter()` returning `{ collections, router }` for DRY setup
|
|
69
|
+
- Add `toRouter()` for router-only use cases
|
|
70
|
+
- Update all router templates to use `createRouter()`
|
|
71
|
+
|
|
72
|
+
### Phase 4: Guard Type Narrowing - Experimental (`@veloxts/auth`, `@veloxts/router`)
|
|
73
|
+
|
|
74
|
+
- Add `NarrowingGuard` interface with phantom `_narrows` type
|
|
75
|
+
- Add `authenticatedNarrow` and `hasRoleNarrow()` guards
|
|
76
|
+
- Add `guardNarrow()` method to `ProcedureBuilder` for context narrowing
|
|
77
|
+
- Enables `ctx.user` to be non-null after guard passes
|
|
78
|
+
|
|
79
|
+
### Phase 5: Documentation (`@veloxts/router`)
|
|
80
|
+
|
|
81
|
+
- Document `.rest()` override patterns
|
|
82
|
+
- Document `createRouter()` helper usage
|
|
83
|
+
- Document `guardNarrow()` experimental API
|
|
84
|
+
- Add schema browser-safety patterns for RSC apps
|
|
85
|
+
|
|
86
|
+
- Updated dependencies
|
|
87
|
+
- @veloxts/core@0.6.69
|
|
88
|
+
- @veloxts/validation@0.6.69
|
|
89
|
+
|
|
3
90
|
## 0.6.68
|
|
4
91
|
|
|
5
92
|
### Patch Changes
|
package/GUIDE.md
CHANGED
|
@@ -48,6 +48,81 @@ Procedure names auto-map to HTTP methods:
|
|
|
48
48
|
| `patch*` | PATCH | `/:id` |
|
|
49
49
|
| `delete*`, `remove*` | DELETE | `/:id` |
|
|
50
50
|
|
|
51
|
+
## REST Overrides with `.rest()`
|
|
52
|
+
|
|
53
|
+
When naming conventions don't fit your use case, use `.rest()` as an escape hatch:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
const userProcedures = procedures('users', {
|
|
57
|
+
// Override method only
|
|
58
|
+
activateUser: procedure()
|
|
59
|
+
.input(z.object({ id: z.string().uuid() }))
|
|
60
|
+
.rest({ method: 'POST' }) // Would be PUT by default
|
|
61
|
+
.mutation(async ({ input, ctx }) => {
|
|
62
|
+
return ctx.db.user.update({ where: { id: input.id }, data: { active: true } });
|
|
63
|
+
}),
|
|
64
|
+
|
|
65
|
+
// Override path with parameters
|
|
66
|
+
getUserByEmail: procedure()
|
|
67
|
+
.input(z.object({ email: z.string().email() }))
|
|
68
|
+
.rest({ method: 'GET', path: '/users/by-email/:email' })
|
|
69
|
+
.query(async ({ input, ctx }) => {
|
|
70
|
+
return ctx.db.user.findUnique({ where: { email: input.email } });
|
|
71
|
+
}),
|
|
72
|
+
|
|
73
|
+
// Custom action endpoint
|
|
74
|
+
sendPasswordReset: procedure()
|
|
75
|
+
.input(z.object({ userId: z.string().uuid() }))
|
|
76
|
+
.rest({ method: 'POST', path: '/users/:userId/password-reset' })
|
|
77
|
+
.mutation(async ({ input, ctx }) => {
|
|
78
|
+
// ...
|
|
79
|
+
}),
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Important**: Do NOT include the API prefix in `.rest()` paths:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// Correct - prefix is added automatically
|
|
87
|
+
.rest({ method: 'POST', path: '/users/:id/activate' })
|
|
88
|
+
|
|
89
|
+
// Wrong - results in /api/api/users/:id/activate
|
|
90
|
+
.rest({ method: 'POST', path: '/api/users/:id/activate' })
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Router Helper (`createRouter`)
|
|
94
|
+
|
|
95
|
+
Use `createRouter()` to eliminate redundancy when defining both collections and router:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { createRouter, extractRoutes } from '@veloxts/router';
|
|
99
|
+
|
|
100
|
+
// Before (redundant):
|
|
101
|
+
// export const collections = [healthProcedures, userProcedures];
|
|
102
|
+
// export const router = {
|
|
103
|
+
// health: healthProcedures,
|
|
104
|
+
// users: userProcedures,
|
|
105
|
+
// };
|
|
106
|
+
|
|
107
|
+
// After (DRY):
|
|
108
|
+
export const { collections, router } = createRouter(
|
|
109
|
+
healthProcedures,
|
|
110
|
+
userProcedures
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
export type AppRouter = typeof router;
|
|
114
|
+
export const routes = extractRoutes(collections);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
If you only need the router object (not collections), use `toRouter()`:
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { toRouter } from '@veloxts/router';
|
|
121
|
+
|
|
122
|
+
export const router = toRouter(healthProcedures, userProcedures);
|
|
123
|
+
// Result: { health: healthProcedures, users: userProcedures }
|
|
124
|
+
```
|
|
125
|
+
|
|
51
126
|
## Registering Routes
|
|
52
127
|
|
|
53
128
|
```typescript
|
|
@@ -320,6 +395,109 @@ const getUser = procedure()
|
|
|
320
395
|
.query(handler);
|
|
321
396
|
```
|
|
322
397
|
|
|
398
|
+
## Guard Type Narrowing (Experimental)
|
|
399
|
+
|
|
400
|
+
When using guards like `authenticated`, TypeScript doesn't know that `ctx.user` is guaranteed non-null after the guard passes. Use `guardNarrow()` to narrow the context type:
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
import { authenticatedNarrow, hasRoleNarrow } from '@veloxts/auth';
|
|
404
|
+
|
|
405
|
+
// ctx.user is guaranteed non-null after guard passes
|
|
406
|
+
const getProfile = procedure()
|
|
407
|
+
.guardNarrow(authenticatedNarrow)
|
|
408
|
+
.query(({ ctx }) => {
|
|
409
|
+
return { email: ctx.user.email }; // No null check needed!
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
// Chain multiple narrowing guards
|
|
413
|
+
const adminAction = procedure()
|
|
414
|
+
.guardNarrow(authenticatedNarrow)
|
|
415
|
+
.guardNarrow(hasRoleNarrow('admin'))
|
|
416
|
+
.mutation(({ ctx }) => {
|
|
417
|
+
// ctx.user is non-null with roles
|
|
418
|
+
});
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
**Note**: This API is experimental. The current stable alternative is to use middleware for context extension:
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
const getProfile = procedure()
|
|
425
|
+
.guard(authenticated)
|
|
426
|
+
.use(async ({ ctx, next }) => {
|
|
427
|
+
if (!ctx.user) throw new Error('Unreachable');
|
|
428
|
+
return next({ ctx: { user: ctx.user } });
|
|
429
|
+
})
|
|
430
|
+
.query(({ ctx }) => {
|
|
431
|
+
// ctx.user is non-null via middleware
|
|
432
|
+
});
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
## Schema Browser-Safety
|
|
436
|
+
|
|
437
|
+
When building full-stack apps, schemas may be imported on both server and client. Avoid importing server-only dependencies in schema files:
|
|
438
|
+
|
|
439
|
+
### Safe Pattern: Pure Zod Schemas
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
// src/schemas/user.ts - Safe for browser import
|
|
443
|
+
import { z } from '@veloxts/validation';
|
|
444
|
+
|
|
445
|
+
export const UserSchema = z.object({
|
|
446
|
+
id: z.string().uuid(),
|
|
447
|
+
name: z.string(),
|
|
448
|
+
email: z.string().email(),
|
|
449
|
+
createdAt: z.string().datetime(),
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
export type User = z.infer<typeof UserSchema>;
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### Unsafe Pattern: Server Dependencies in Schemas
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
// DO NOT import server-only modules in schema files
|
|
459
|
+
import { db } from '@/database'; // BAD - pulls Prisma into client bundle
|
|
460
|
+
|
|
461
|
+
export const UserSchema = z.object({
|
|
462
|
+
// ...
|
|
463
|
+
});
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Separating Input/Output Schemas
|
|
467
|
+
|
|
468
|
+
Keep input schemas (for mutations) separate from output schemas (with transforms):
|
|
469
|
+
|
|
470
|
+
```typescript
|
|
471
|
+
// src/schemas/user.input.ts - For mutations
|
|
472
|
+
export const CreateUserInput = z.object({
|
|
473
|
+
name: z.string().min(1),
|
|
474
|
+
email: z.string().email(),
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
// src/schemas/user.output.ts - May have transforms
|
|
478
|
+
import { dateToIso, prismaDecimal } from '@veloxts/validation';
|
|
479
|
+
|
|
480
|
+
export const UserOutput = z.object({
|
|
481
|
+
id: z.string().uuid(),
|
|
482
|
+
name: z.string(),
|
|
483
|
+
email: z.string().email(),
|
|
484
|
+
balance: prismaDecimal(), // Transforms Prisma Decimal
|
|
485
|
+
createdAt: dateToIso(), // Transforms Date to string
|
|
486
|
+
});
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Type-Only Imports
|
|
490
|
+
|
|
491
|
+
In server actions, use type-only imports to avoid bundling server code:
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
// GOOD - Type stripped at build time
|
|
495
|
+
import type { User } from '@/schemas/user';
|
|
496
|
+
|
|
497
|
+
// BAD - Pulls in full module graph
|
|
498
|
+
import { User } from '@/schemas/user';
|
|
499
|
+
```
|
|
500
|
+
|
|
323
501
|
## Learn More
|
|
324
502
|
|
|
325
503
|
See [@veloxts/velox](https://www.npmjs.com/package/@veloxts/velox) for complete documentation.
|
package/dist/index.d.ts
CHANGED
|
@@ -47,6 +47,8 @@ export type { DefineProceduresOptions, } from './procedure/builder.js';
|
|
|
47
47
|
export { defineProcedures, executeProcedure, isCompiledProcedure, isProcedureCollection, procedure, procedures, } from './procedure/builder.js';
|
|
48
48
|
export { createProcedure, typedProcedure } from './procedure/factory.js';
|
|
49
49
|
export type { BuilderRuntimeState, InferProcedures, InferSchemaOutput, ProcedureBuilder, ProcedureBuilderState, ProcedureDefinitions, ValidSchema, } from './procedure/types.js';
|
|
50
|
+
export type { RouterResult } from './router-utils.js';
|
|
51
|
+
export { createRouter, toRouter } from './router-utils.js';
|
|
50
52
|
export type { NamingWarning, NamingWarningType, WarningConfig, WarningOption } from './warnings.js';
|
|
51
53
|
export { analyzeNamingConvention, isDevelopment, normalizeWarningOption } from './warnings.js';
|
|
52
54
|
export type { ExtractRoutesType, RestAdapterOptions, RestMapping, RestRoute, RouteMap, } from './rest/index.js';
|
package/dist/index.js
CHANGED
|
@@ -51,8 +51,12 @@ export {
|
|
|
51
51
|
// Builder functions
|
|
52
52
|
defineProcedures, executeProcedure, isCompiledProcedure, isProcedureCollection, procedure, procedures, // Short alias for defineProcedures
|
|
53
53
|
} from './procedure/builder.js';
|
|
54
|
+
// ============================================================================
|
|
55
|
+
// Router Utilities
|
|
56
|
+
// ============================================================================
|
|
54
57
|
// Typed procedure factory
|
|
55
58
|
export { createProcedure, typedProcedure } from './procedure/factory.js';
|
|
59
|
+
export { createRouter, toRouter } from './router-utils.js';
|
|
56
60
|
export { analyzeNamingConvention, isDevelopment, normalizeWarningOption } from './warnings.js';
|
|
57
61
|
export { buildNestedRestPath, buildRestPath, extractRoutes, followsNamingConvention, generateRestRoutes, getRouteSummary, inferResourceName, parseNamingConvention, registerRestRoutes, rest, } from './rest/index.js';
|
|
58
62
|
export {
|
|
@@ -175,6 +175,18 @@ function createBuilder(state) {
|
|
|
175
175
|
guards: [...state.guards, guardDef],
|
|
176
176
|
});
|
|
177
177
|
},
|
|
178
|
+
/**
|
|
179
|
+
* Adds an authorization guard with type narrowing (EXPERIMENTAL)
|
|
180
|
+
*
|
|
181
|
+
* Unlike `guard()`, this method narrows the context type based on
|
|
182
|
+
* what the guard guarantees after it passes.
|
|
183
|
+
*/
|
|
184
|
+
guardNarrow(guardDef) {
|
|
185
|
+
return createBuilder({
|
|
186
|
+
...state,
|
|
187
|
+
guards: [...state.guards, guardDef],
|
|
188
|
+
});
|
|
189
|
+
},
|
|
178
190
|
/**
|
|
179
191
|
* Sets REST route override
|
|
180
192
|
*/
|
|
@@ -170,6 +170,41 @@ export interface ProcedureBuilder<TInput = unknown, TOutput = unknown, TContext
|
|
|
170
170
|
* ```
|
|
171
171
|
*/
|
|
172
172
|
guard<TGuardContext extends Partial<TContext>>(guard: GuardLike<TGuardContext>): ProcedureBuilder<TInput, TOutput, TContext>;
|
|
173
|
+
/**
|
|
174
|
+
* Adds an authorization guard with type narrowing (EXPERIMENTAL)
|
|
175
|
+
*
|
|
176
|
+
* Unlike `.guard()`, this method narrows the context type based on
|
|
177
|
+
* what the guard guarantees. For example, `authenticatedNarrow` narrows
|
|
178
|
+
* `ctx.user` from `User | undefined` to `User`.
|
|
179
|
+
*
|
|
180
|
+
* **EXPERIMENTAL**: This API may change. Consider using middleware
|
|
181
|
+
* for context type extension as the current stable alternative.
|
|
182
|
+
*
|
|
183
|
+
* @template TNarrowedContext - The context type guaranteed by the guard
|
|
184
|
+
* @param guard - Narrowing guard definition with `_narrows` type
|
|
185
|
+
* @returns New builder with narrowed context type
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* import { authenticatedNarrow, hasRoleNarrow } from '@veloxts/auth';
|
|
190
|
+
*
|
|
191
|
+
* // ctx.user is guaranteed non-null after guard passes
|
|
192
|
+
* procedure()
|
|
193
|
+
* .guardNarrow(authenticatedNarrow)
|
|
194
|
+
* .query(({ ctx }) => {
|
|
195
|
+
* return { email: ctx.user.email }; // No null check needed!
|
|
196
|
+
* });
|
|
197
|
+
*
|
|
198
|
+
* // Chain multiple narrowing guards
|
|
199
|
+
* procedure()
|
|
200
|
+
* .guardNarrow(authenticatedNarrow)
|
|
201
|
+
* .guardNarrow(hasRoleNarrow('admin'))
|
|
202
|
+
* .mutation(({ ctx }) => { ... });
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
guardNarrow<TNarrowedContext>(guard: GuardLike<Partial<TContext>> & {
|
|
206
|
+
readonly _narrows: TNarrowedContext;
|
|
207
|
+
}): ProcedureBuilder<TInput, TOutput, TContext & TNarrowedContext>;
|
|
173
208
|
/**
|
|
174
209
|
* Configures REST route override
|
|
175
210
|
*
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router Utility Functions
|
|
3
|
+
*
|
|
4
|
+
* Helpers for creating type-safe router definitions from procedure collections.
|
|
5
|
+
*
|
|
6
|
+
* @module router-utils
|
|
7
|
+
*/
|
|
8
|
+
import type { ProcedureCollection, ProcedureRecord } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Extracts the namespace from a ProcedureCollection as a literal type
|
|
11
|
+
*/
|
|
12
|
+
type ExtractNamespace<T> = T extends ProcedureCollection<infer _P> & {
|
|
13
|
+
readonly namespace: infer N;
|
|
14
|
+
} ? N extends string ? N : never : never;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a union of namespaces from an array of ProcedureCollections
|
|
17
|
+
*/
|
|
18
|
+
type CollectionNamespaces<T extends readonly ProcedureCollection[]> = {
|
|
19
|
+
[K in keyof T]: ExtractNamespace<T[K]>;
|
|
20
|
+
}[number];
|
|
21
|
+
/**
|
|
22
|
+
* Maps namespaces to their corresponding ProcedureCollections
|
|
23
|
+
*/
|
|
24
|
+
type RouterFromCollections<T extends readonly ProcedureCollection[]> = {
|
|
25
|
+
[K in CollectionNamespaces<T>]: Extract<T[number], {
|
|
26
|
+
namespace: K;
|
|
27
|
+
}>;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Result type from createRouter
|
|
31
|
+
*/
|
|
32
|
+
export interface RouterResult<T extends readonly ProcedureCollection[]> {
|
|
33
|
+
/** Array of procedure collections for routing */
|
|
34
|
+
readonly collections: T;
|
|
35
|
+
/** Object mapping namespaces to procedure collections */
|
|
36
|
+
readonly router: RouterFromCollections<T>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Creates both collections array and router object from procedure collections.
|
|
40
|
+
*
|
|
41
|
+
* This helper eliminates the redundancy of defining both `collections` and `router`
|
|
42
|
+
* separately. The router object is automatically keyed by each collection's namespace.
|
|
43
|
+
*
|
|
44
|
+
* @param collections - Procedure collections to include in the router
|
|
45
|
+
* @returns Object containing both `collections` array and `router` object
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* import { createRouter, extractRoutes } from '@veloxts/router';
|
|
50
|
+
* import { healthProcedures } from './procedures/health.js';
|
|
51
|
+
* import { userProcedures } from './procedures/users.js';
|
|
52
|
+
*
|
|
53
|
+
* // Before (redundant):
|
|
54
|
+
* // export const collections = [healthProcedures, userProcedures];
|
|
55
|
+
* // export const router = {
|
|
56
|
+
* // health: healthProcedures,
|
|
57
|
+
* // users: userProcedures,
|
|
58
|
+
* // };
|
|
59
|
+
*
|
|
60
|
+
* // After (DRY):
|
|
61
|
+
* export const { collections, router } = createRouter(
|
|
62
|
+
* healthProcedures,
|
|
63
|
+
* userProcedures
|
|
64
|
+
* );
|
|
65
|
+
*
|
|
66
|
+
* export type AppRouter = typeof router;
|
|
67
|
+
* export const routes = extractRoutes(collections);
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function createRouter<T extends ProcedureCollection<ProcedureRecord>[]>(...collections: T): RouterResult<T>;
|
|
71
|
+
/**
|
|
72
|
+
* Creates a router object from procedure collections.
|
|
73
|
+
*
|
|
74
|
+
* This is an alternative to `createRouter` when you only need the router object
|
|
75
|
+
* and not the collections array. Useful for frontend-only type imports.
|
|
76
|
+
*
|
|
77
|
+
* @param collections - Procedure collections to include in the router
|
|
78
|
+
* @returns Object mapping namespaces to procedure collections
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* import { toRouter } from '@veloxts/router';
|
|
83
|
+
*
|
|
84
|
+
* export const router = toRouter(healthProcedures, userProcedures);
|
|
85
|
+
* // Result: { health: healthProcedures, users: userProcedures }
|
|
86
|
+
*
|
|
87
|
+
* export type AppRouter = typeof router;
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare function toRouter<T extends ProcedureCollection<ProcedureRecord>[]>(...collections: T): RouterFromCollections<T>;
|
|
91
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router Utility Functions
|
|
3
|
+
*
|
|
4
|
+
* Helpers for creating type-safe router definitions from procedure collections.
|
|
5
|
+
*
|
|
6
|
+
* @module router-utils
|
|
7
|
+
*/
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Router Creation
|
|
10
|
+
// ============================================================================
|
|
11
|
+
/**
|
|
12
|
+
* Creates both collections array and router object from procedure collections.
|
|
13
|
+
*
|
|
14
|
+
* This helper eliminates the redundancy of defining both `collections` and `router`
|
|
15
|
+
* separately. The router object is automatically keyed by each collection's namespace.
|
|
16
|
+
*
|
|
17
|
+
* @param collections - Procedure collections to include in the router
|
|
18
|
+
* @returns Object containing both `collections` array and `router` object
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* import { createRouter, extractRoutes } from '@veloxts/router';
|
|
23
|
+
* import { healthProcedures } from './procedures/health.js';
|
|
24
|
+
* import { userProcedures } from './procedures/users.js';
|
|
25
|
+
*
|
|
26
|
+
* // Before (redundant):
|
|
27
|
+
* // export const collections = [healthProcedures, userProcedures];
|
|
28
|
+
* // export const router = {
|
|
29
|
+
* // health: healthProcedures,
|
|
30
|
+
* // users: userProcedures,
|
|
31
|
+
* // };
|
|
32
|
+
*
|
|
33
|
+
* // After (DRY):
|
|
34
|
+
* export const { collections, router } = createRouter(
|
|
35
|
+
* healthProcedures,
|
|
36
|
+
* userProcedures
|
|
37
|
+
* );
|
|
38
|
+
*
|
|
39
|
+
* export type AppRouter = typeof router;
|
|
40
|
+
* export const routes = extractRoutes(collections);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function createRouter(...collections) {
|
|
44
|
+
const router = Object.fromEntries(collections.map((collection) => [collection.namespace, collection]));
|
|
45
|
+
return {
|
|
46
|
+
// Cast required: rest params are typed as T[] but we need to preserve
|
|
47
|
+
// the exact tuple type T for proper namespace inference in RouterResult
|
|
48
|
+
collections: collections,
|
|
49
|
+
router,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Creates a router object from procedure collections.
|
|
54
|
+
*
|
|
55
|
+
* This is an alternative to `createRouter` when you only need the router object
|
|
56
|
+
* and not the collections array. Useful for frontend-only type imports.
|
|
57
|
+
*
|
|
58
|
+
* @param collections - Procedure collections to include in the router
|
|
59
|
+
* @returns Object mapping namespaces to procedure collections
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* import { toRouter } from '@veloxts/router';
|
|
64
|
+
*
|
|
65
|
+
* export const router = toRouter(healthProcedures, userProcedures);
|
|
66
|
+
* // Result: { health: healthProcedures, users: userProcedures }
|
|
67
|
+
*
|
|
68
|
+
* export type AppRouter = typeof router;
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export function toRouter(...collections) {
|
|
72
|
+
return Object.fromEntries(collections.map((collection) => [collection.namespace, collection]));
|
|
73
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veloxts/router",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.70",
|
|
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/core": "0.6.
|
|
44
|
-
"@veloxts/validation": "0.6.
|
|
43
|
+
"@veloxts/core": "0.6.70",
|
|
44
|
+
"@veloxts/validation": "0.6.70"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@vitest/coverage-v8": "4.0.16",
|