@stacksjs/bun-router 0.0.17 → 0.0.18
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/dist/cli.js +1 -1
- package/dist/container/service-provider.d.ts +3 -3
- package/dist/development/performance-profiler.d.ts +3 -3
- package/dist/development/route-debugger.d.ts +1 -1
- package/dist/development/route-inspector.d.ts +2 -2
- package/dist/observability/integration.d.ts +1 -1
- package/dist/response/macros.d.ts +1 -1
- package/dist/router/index.d.ts +7 -7
- package/dist/router/router.d.ts +0 -32
- package/dist/testing/performance-testing.d.ts +2 -2
- package/dist/testing/test-client.d.ts +1 -1
- package/dist/testing/websocket-testing.d.ts +1 -1
- package/package.json +2 -3
- package/src/auth.ts +0 -489
- package/src/cache/lru-cache.ts +0 -457
- package/src/cache/middleware-memoization.ts +0 -531
- package/src/cache/route-cache-warmer.ts +0 -486
- package/src/cache/sqlite-cache.ts +0 -783
- package/src/cache/streaming-cache.ts +0 -572
- package/src/cli/colors.ts +0 -29
- package/src/cli/index.ts +0 -287
- package/src/cli/middleware.ts +0 -291
- package/src/cli/openapi.ts +0 -407
- package/src/cli/router.ts +0 -188
- package/src/cli/routes.ts +0 -265
- package/src/cli/utils.ts +0 -531
- package/src/cli.ts +0 -5
- package/src/config.ts +0 -322
- package/src/container/container.ts +0 -786
- package/src/container/contextual-binding.ts +0 -606
- package/src/container/decorators.ts +0 -368
- package/src/container/index.ts +0 -49
- package/src/container/service-provider.ts +0 -596
- package/src/development/hot-reload.ts +0 -673
- package/src/development/index.ts +0 -499
- package/src/development/performance-profiler.ts +0 -717
- package/src/development/route-debugger.ts +0 -527
- package/src/development/route-inspector.ts +0 -749
- package/src/development/typescript-utilities.ts +0 -682
- package/src/docs.ts +0 -397
- package/src/errors/circuit-breaker.ts +0 -733
- package/src/errors/error-handler.ts +0 -569
- package/src/errors/error-reporting.ts +0 -672
- package/src/errors/exceptions.ts +0 -536
- package/src/errors/graceful-degradation.ts +0 -623
- package/src/errors/index.ts +0 -21
- package/src/errors/router-errors.ts +0 -632
- package/src/file-serving/static-files.ts +0 -718
- package/src/index.ts +0 -66
- package/src/middleware/auth.ts +0 -220
- package/src/middleware/content_security_policy.ts +0 -215
- package/src/middleware/cors.ts +0 -142
- package/src/middleware/csrf.ts +0 -166
- package/src/middleware/ddos_protection.ts +0 -279
- package/src/middleware/file_security.ts +0 -191
- package/src/middleware/file_upload.ts +0 -275
- package/src/middleware/helmet.ts +0 -268
- package/src/middleware/index.ts +0 -117
- package/src/middleware/input_validation.ts +0 -453
- package/src/middleware/json_body.ts +0 -37
- package/src/middleware/performance_alerting.ts +0 -540
- package/src/middleware/performance_dashboard.ts +0 -661
- package/src/middleware/performance_monitor.ts +0 -945
- package/src/middleware/pipeline.ts +0 -489
- package/src/middleware/rate_limit.ts +0 -251
- package/src/middleware/request_id.ts +0 -36
- package/src/middleware/request_signing.ts +0 -638
- package/src/middleware/request_tracer.ts +0 -653
- package/src/middleware/response_cache.ts +0 -778
- package/src/middleware/security.ts +0 -482
- package/src/middleware/security_suite.ts +0 -257
- package/src/middleware/session.ts +0 -91
- package/src/model-binding/index.ts +0 -18
- package/src/model-binding/model-middleware.ts +0 -425
- package/src/model-binding/model-registry.ts +0 -550
- package/src/model-binding.ts +0 -370
- package/src/model-resolver-factory.ts +0 -106
- package/src/observability/correlation.ts +0 -691
- package/src/observability/health-checks.ts +0 -729
- package/src/observability/index.ts +0 -184
- package/src/observability/integration.ts +0 -548
- package/src/observability/metrics.ts +0 -753
- package/src/observability/tracing.ts +0 -638
- package/src/optimization/bun-utilities.ts +0 -778
- package/src/query-builder-integration.ts +0 -137
- package/src/request/context.ts +0 -109
- package/src/request/enhanced-request.ts +0 -876
- package/src/request/macros.ts +0 -822
- package/src/response/macros.ts +0 -665
- package/src/response/response-factory.ts +0 -596
- package/src/router/api-routes.ts +0 -243
- package/src/router/file-based-routing.ts +0 -697
- package/src/router/file-streaming.ts +0 -383
- package/src/router/fluent-routing.ts +0 -866
- package/src/router/group-organization.ts +0 -229
- package/src/router/handler-resolver.ts +0 -327
- package/src/router/http-methods.ts +0 -407
- package/src/router/index.ts +0 -193
- package/src/router/middleware-groups.ts +0 -222
- package/src/router/middleware-integration.ts +0 -399
- package/src/router/middleware.ts +0 -234
- package/src/router/model-binding.ts +0 -215
- package/src/router/optimized-route-matching.ts +0 -302
- package/src/router/route-building.ts +0 -221
- package/src/router/route-compiler.ts +0 -691
- package/src/router/route-matching.ts +0 -368
- package/src/router/route-trie.ts +0 -450
- package/src/router/router.ts +0 -1616
- package/src/router/server.ts +0 -684
- package/src/router/validation-integration.ts +0 -449
- package/src/router/view-rendering.ts +0 -233
- package/src/router/websocket.ts +0 -100
- package/src/routing/route-caching.ts +0 -402
- package/src/routing/route-throttling.ts +0 -469
- package/src/routing/subdomain-routing.ts +0 -492
- package/src/session/database-store.ts +0 -109
- package/src/session/file-store.ts +0 -148
- package/src/session/index.ts +0 -244
- package/src/session/memory-store.ts +0 -88
- package/src/session/redis-store.ts +0 -93
- package/src/streaming/index.ts +0 -17
- package/src/streaming/sse-handler.ts +0 -482
- package/src/streaming/stream-handler.ts +0 -552
- package/src/testing/auth-testing.ts +0 -448
- package/src/testing/file-upload-testing.ts +0 -543
- package/src/testing/index.ts +0 -10
- package/src/testing/middleware-testing.ts +0 -322
- package/src/testing/model-binding-testing.ts +0 -645
- package/src/testing/performance-testing.ts +0 -738
- package/src/testing/test-client.ts +0 -310
- package/src/testing/test-request.ts +0 -315
- package/src/testing/test-response.ts +0 -332
- package/src/testing/types.ts +0 -224
- package/src/testing/websocket-testing.ts +0 -590
- package/src/types/controller-types.ts +0 -385
- package/src/types/core.ts +0 -683
- package/src/types/middleware-types.ts +0 -422
- package/src/types/request-response-augmentation.ts +0 -489
- package/src/types/route-inference.ts +0 -372
- package/src/types.ts +0 -2123
- package/src/url.ts +0 -131
- package/src/utils/index.ts +0 -1
- package/src/utils/query-preservation.ts +0 -201
- package/src/utils.ts +0 -395
- package/src/validation/validator.ts +0 -688
- package/src/websocket/clustering.ts +0 -769
|
@@ -1,425 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
EnhancedRequest,
|
|
3
|
-
ExtractRouteParams,
|
|
4
|
-
} from '../types'
|
|
5
|
-
import { modelRegistry } from './model-registry'
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Model binding middleware options
|
|
9
|
-
*/
|
|
10
|
-
export interface ModelBindingMiddlewareOptions {
|
|
11
|
-
failOnError?: boolean
|
|
12
|
-
attachToRequest?: boolean
|
|
13
|
-
paramMapping?: Record<string, string>
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Simplified model binding configuration for middleware
|
|
18
|
-
*/
|
|
19
|
-
export interface ModelBindingRef {
|
|
20
|
-
model: string
|
|
21
|
-
parameter: string
|
|
22
|
-
required?: boolean
|
|
23
|
-
as?: string
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Create model binding middleware
|
|
28
|
-
*/
|
|
29
|
-
export function createModelBindingMiddleware(
|
|
30
|
-
bindings: ModelBindingRef[],
|
|
31
|
-
options: ModelBindingMiddlewareOptions = {},
|
|
32
|
-
) {
|
|
33
|
-
const {
|
|
34
|
-
failOnError = true,
|
|
35
|
-
attachToRequest = true,
|
|
36
|
-
paramMapping = {},
|
|
37
|
-
} = options
|
|
38
|
-
|
|
39
|
-
return async (req: EnhancedRequest, next: () => Promise<Response>): Promise<Response> => {
|
|
40
|
-
const models: Record<string, any> = {}
|
|
41
|
-
const errors: Record<string, string> = {}
|
|
42
|
-
|
|
43
|
-
// Resolve all model bindings
|
|
44
|
-
for (const binding of bindings) {
|
|
45
|
-
const paramName = paramMapping[binding.model] || binding.parameter
|
|
46
|
-
const paramValue = req.params?.[paramName]
|
|
47
|
-
|
|
48
|
-
if (!paramValue && binding.required !== false) {
|
|
49
|
-
const error = `Required parameter '${paramName}' for model '${binding.model}' not found`
|
|
50
|
-
errors[binding.model] = error
|
|
51
|
-
|
|
52
|
-
if (failOnError) {
|
|
53
|
-
return new Response(
|
|
54
|
-
JSON.stringify({
|
|
55
|
-
error,
|
|
56
|
-
status: 400,
|
|
57
|
-
message: 'Missing required parameter',
|
|
58
|
-
}),
|
|
59
|
-
{
|
|
60
|
-
status: 400,
|
|
61
|
-
headers: { 'Content-Type': 'application/json' },
|
|
62
|
-
},
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
continue
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (!paramValue) {
|
|
69
|
-
continue // Skip optional parameters that are not provided
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const params = { [paramName]: paramValue, ...req.params }
|
|
73
|
-
const result = await modelRegistry.resolve(binding.model, params, req)
|
|
74
|
-
|
|
75
|
-
if (result.model === null) {
|
|
76
|
-
errors[binding.model] = result.error || 'Model not found'
|
|
77
|
-
|
|
78
|
-
if (failOnError) {
|
|
79
|
-
return modelRegistry.createErrorResponse(binding.model, result, params)
|
|
80
|
-
}
|
|
81
|
-
continue
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
models[binding.model] = result.model
|
|
85
|
-
|
|
86
|
-
// Attach to request if enabled
|
|
87
|
-
if (attachToRequest) {
|
|
88
|
-
const propertyName = binding.as || binding.model
|
|
89
|
-
;(req as any)[propertyName] = result.model
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Add models and errors to request context
|
|
94
|
-
req.models = models
|
|
95
|
-
req.modelErrors = errors
|
|
96
|
-
|
|
97
|
-
return next()
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Single model binding middleware
|
|
103
|
-
*/
|
|
104
|
-
export function bindModel(
|
|
105
|
-
modelName: string,
|
|
106
|
-
parameterName: string,
|
|
107
|
-
options: {
|
|
108
|
-
required?: boolean
|
|
109
|
-
as?: string
|
|
110
|
-
failOnError?: boolean
|
|
111
|
-
} = {},
|
|
112
|
-
): (req: EnhancedRequest, next: () => Promise<Response>) => Promise<Response> {
|
|
113
|
-
const {
|
|
114
|
-
required = true,
|
|
115
|
-
as,
|
|
116
|
-
failOnError = true,
|
|
117
|
-
} = options
|
|
118
|
-
|
|
119
|
-
return createModelBindingMiddleware(
|
|
120
|
-
[
|
|
121
|
-
{
|
|
122
|
-
model: modelName,
|
|
123
|
-
parameter: parameterName,
|
|
124
|
-
required,
|
|
125
|
-
as,
|
|
126
|
-
},
|
|
127
|
-
],
|
|
128
|
-
{ failOnError, attachToRequest: true },
|
|
129
|
-
)
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Route parameter model binding decorator
|
|
134
|
-
*/
|
|
135
|
-
export function withModelBinding<TPath extends string>(
|
|
136
|
-
bindings: ModelBindingRef[],
|
|
137
|
-
) {
|
|
138
|
-
return function (
|
|
139
|
-
_target: any,
|
|
140
|
-
_propertyKey: string,
|
|
141
|
-
descriptor: PropertyDescriptor,
|
|
142
|
-
): PropertyDescriptor {
|
|
143
|
-
const originalMethod = descriptor.value
|
|
144
|
-
|
|
145
|
-
descriptor.value = async function (
|
|
146
|
-
req: EnhancedRequest & { params: ExtractRouteParams<TPath> },
|
|
147
|
-
...args: any[]
|
|
148
|
-
) {
|
|
149
|
-
const middleware = createModelBindingMiddleware(bindings, {
|
|
150
|
-
failOnError: true,
|
|
151
|
-
attachToRequest: true,
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
const mockNext = () => {
|
|
155
|
-
return Promise.resolve(new Response('OK'))
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const response = await middleware(req, mockNext)
|
|
159
|
-
|
|
160
|
-
// If middleware returned an error response, return it
|
|
161
|
-
if (response.status >= 400) {
|
|
162
|
-
return response
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Otherwise, call the original method
|
|
166
|
-
return originalMethod.call(this, req, ...args)
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return descriptor
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Model binding utilities for middleware
|
|
175
|
-
*/
|
|
176
|
-
export const ModelBindingUtils = {
|
|
177
|
-
/**
|
|
178
|
-
* Create middleware for a specific model type
|
|
179
|
-
*/
|
|
180
|
-
forModel<T>(
|
|
181
|
-
modelName: string,
|
|
182
|
-
paramName: string,
|
|
183
|
-
options: {
|
|
184
|
-
validator?: (model: T) => boolean | Promise<boolean>
|
|
185
|
-
transformer?: (model: T) => T | Promise<T>
|
|
186
|
-
cache?: boolean
|
|
187
|
-
} = {},
|
|
188
|
-
) {
|
|
189
|
-
return async (req: EnhancedRequest, next: () => Promise<Response>): Promise<Response> => {
|
|
190
|
-
const paramValue = req.params?.[paramName]
|
|
191
|
-
if (!paramValue) {
|
|
192
|
-
return new Response('Missing required parameter', { status: 400 })
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const result = await modelRegistry.resolve<T>(
|
|
196
|
-
modelName,
|
|
197
|
-
{ [paramName]: paramValue, ...req.params },
|
|
198
|
-
req,
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
if (result.model === null) {
|
|
202
|
-
return modelRegistry.createErrorResponse(modelName, result, req.params || {})
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
let model: T = result.model as T
|
|
206
|
-
|
|
207
|
-
// Apply custom validation
|
|
208
|
-
if (options.validator && !(await options.validator(model))) {
|
|
209
|
-
return new Response('Model validation failed', { status: 422 })
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Apply custom transformation
|
|
213
|
-
if (options.transformer) {
|
|
214
|
-
model = await options.transformer(model)
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Attach to request
|
|
218
|
-
;(req as any)[modelName] = model
|
|
219
|
-
|
|
220
|
-
return next()
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Create middleware that binds multiple models
|
|
226
|
-
*/
|
|
227
|
-
multiple(bindings: Array<{ model: string, param: string, required?: boolean }>): (req: EnhancedRequest, next: () => Promise<Response>) => Promise<Response> {
|
|
228
|
-
return createModelBindingMiddleware(
|
|
229
|
-
bindings.map(binding => ({
|
|
230
|
-
model: binding.model,
|
|
231
|
-
parameter: binding.param,
|
|
232
|
-
required: binding.required ?? true,
|
|
233
|
-
})),
|
|
234
|
-
)
|
|
235
|
-
},
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Create middleware that validates model ownership
|
|
239
|
-
*/
|
|
240
|
-
requireOwnership<T extends { userId?: string | number }>(
|
|
241
|
-
modelName: string,
|
|
242
|
-
userIdField: string = 'userId',
|
|
243
|
-
) {
|
|
244
|
-
return async (req: EnhancedRequest, next: () => Promise<Response>): Promise<Response> => {
|
|
245
|
-
const model = (req as any)[modelName] as T
|
|
246
|
-
if (!model) {
|
|
247
|
-
return new Response(`Model '${modelName}' not found in request`, { status: 500 })
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const userId = req.user?.id
|
|
251
|
-
if (!userId) {
|
|
252
|
-
return new Response('Authentication required', { status: 401 })
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const modelUserId = (model as any)[userIdField]
|
|
256
|
-
if (modelUserId && modelUserId.toString() !== userId.toString()) {
|
|
257
|
-
return new Response('Access denied', { status: 403 })
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return next()
|
|
261
|
-
}
|
|
262
|
-
},
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Create middleware that caches resolved models
|
|
266
|
-
*/
|
|
267
|
-
withCache(
|
|
268
|
-
modelName: string,
|
|
269
|
-
paramName: string,
|
|
270
|
-
_options: {
|
|
271
|
-
ttl?: number
|
|
272
|
-
keyGenerator?: (params: Record<string, string>) => string
|
|
273
|
-
} = {},
|
|
274
|
-
) {
|
|
275
|
-
return async (req: EnhancedRequest, next: () => Promise<Response>): Promise<Response> => {
|
|
276
|
-
// This would integrate with the model registry's caching system
|
|
277
|
-
// For now, just resolve normally
|
|
278
|
-
const paramValue = req.params?.[paramName]
|
|
279
|
-
if (!paramValue) {
|
|
280
|
-
return new Response('Missing required parameter', { status: 400 })
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const result = await modelRegistry.resolve(
|
|
284
|
-
modelName,
|
|
285
|
-
{ [paramName]: paramValue, ...req.params },
|
|
286
|
-
req,
|
|
287
|
-
)
|
|
288
|
-
|
|
289
|
-
if (result.model === null) {
|
|
290
|
-
return modelRegistry.createErrorResponse(modelName, result, req.params || {})
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
;(req as any)[modelName] = result.model
|
|
294
|
-
return next()
|
|
295
|
-
}
|
|
296
|
-
},
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Create middleware that handles optional model binding
|
|
300
|
-
*/
|
|
301
|
-
optional(modelName: string, paramName: string) {
|
|
302
|
-
return async (req: EnhancedRequest, next: () => Promise<Response>): Promise<Response> => {
|
|
303
|
-
const paramValue = req.params?.[paramName]
|
|
304
|
-
if (!paramValue) {
|
|
305
|
-
// Set model to null if parameter is not provided
|
|
306
|
-
;(req as any)[modelName] = null
|
|
307
|
-
return next()
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
const result = await modelRegistry.resolve(
|
|
311
|
-
modelName,
|
|
312
|
-
{ [paramName]: paramValue, ...req.params },
|
|
313
|
-
req,
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
// For optional bindings, we don't fail on resolution errors
|
|
317
|
-
;(req as any)[modelName] = result.model || null
|
|
318
|
-
|
|
319
|
-
return next()
|
|
320
|
-
}
|
|
321
|
-
},
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Model binding middleware factory
|
|
326
|
-
*/
|
|
327
|
-
export class ModelBindingFactory {
|
|
328
|
-
/**
|
|
329
|
-
* Create binding for user model
|
|
330
|
-
*/
|
|
331
|
-
static user(paramName: string = 'id', as: string = 'user'): (req: EnhancedRequest, next: () => Promise<Response>) => Promise<Response> {
|
|
332
|
-
return bindModel('user', paramName, { as, required: true })
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* Create binding for post model
|
|
337
|
-
*/
|
|
338
|
-
static post(paramName: string = 'postId', as: string = 'post'): (req: EnhancedRequest, next: () => Promise<Response>) => Promise<Response> {
|
|
339
|
-
return bindModel('post', paramName, { as, required: true })
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
/**
|
|
343
|
-
* Create binding for category model
|
|
344
|
-
*/
|
|
345
|
-
static category(paramName: string = 'categoryId', as: string = 'category'): (req: EnhancedRequest, next: () => Promise<Response>) => Promise<Response> {
|
|
346
|
-
return bindModel('category', paramName, { as, required: true })
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/**
|
|
350
|
-
* Create binding for any resource with ownership validation
|
|
351
|
-
*/
|
|
352
|
-
static ownedResource(
|
|
353
|
-
modelName: string,
|
|
354
|
-
paramName: string,
|
|
355
|
-
userIdField: string = 'userId',
|
|
356
|
-
): Array<(req: EnhancedRequest, next: () => Promise<Response>) => Promise<Response>> {
|
|
357
|
-
return [
|
|
358
|
-
bindModel(modelName, paramName),
|
|
359
|
-
ModelBindingUtils.requireOwnership(modelName, userIdField),
|
|
360
|
-
] as const
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Create nested resource bindings (e.g., user -> posts)
|
|
365
|
-
*/
|
|
366
|
-
static nested(
|
|
367
|
-
parentModel: string,
|
|
368
|
-
parentParam: string,
|
|
369
|
-
childModel: string,
|
|
370
|
-
childParam: string,
|
|
371
|
-
): (req: EnhancedRequest, next: () => Promise<Response>) => Promise<Response> {
|
|
372
|
-
return createModelBindingMiddleware([
|
|
373
|
-
{
|
|
374
|
-
model: parentModel,
|
|
375
|
-
parameter: parentParam,
|
|
376
|
-
required: true,
|
|
377
|
-
},
|
|
378
|
-
{
|
|
379
|
-
model: childModel,
|
|
380
|
-
parameter: childParam,
|
|
381
|
-
required: true,
|
|
382
|
-
},
|
|
383
|
-
])
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* Type-safe model binding helpers
|
|
389
|
-
*/
|
|
390
|
-
export const TypedModelBinding = {
|
|
391
|
-
/**
|
|
392
|
-
* Create a typed model binding that preserves route parameter types
|
|
393
|
-
*/
|
|
394
|
-
create<TPath extends string>(
|
|
395
|
-
bindings: Array<{
|
|
396
|
-
model: string
|
|
397
|
-
param: keyof ExtractRouteParams<TPath>
|
|
398
|
-
required?: boolean
|
|
399
|
-
as?: string
|
|
400
|
-
}>,
|
|
401
|
-
): (req: EnhancedRequest, next: () => Promise<Response>) => Promise<Response> {
|
|
402
|
-
return createModelBindingMiddleware(
|
|
403
|
-
bindings.map(binding => ({
|
|
404
|
-
model: binding.model,
|
|
405
|
-
parameter: String(binding.param),
|
|
406
|
-
required: binding.required ?? true,
|
|
407
|
-
as: binding.as,
|
|
408
|
-
})),
|
|
409
|
-
)
|
|
410
|
-
},
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Create a single typed model binding
|
|
414
|
-
*/
|
|
415
|
-
single<TPath extends string>(
|
|
416
|
-
modelName: string,
|
|
417
|
-
param: keyof ExtractRouteParams<TPath>,
|
|
418
|
-
options: {
|
|
419
|
-
required?: boolean
|
|
420
|
-
as?: string
|
|
421
|
-
} = {},
|
|
422
|
-
): (req: EnhancedRequest, next: () => Promise<Response>) => Promise<Response> {
|
|
423
|
-
return bindModel(modelName, String(param), options)
|
|
424
|
-
},
|
|
425
|
-
}
|