@stacksjs/bun-router 0.0.13 → 0.0.14
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 +770 -0
- package/README.md +584 -261
- package/package.json +43 -47
- package/bin/cli.ts +0 -9
- package/dist/auth.d.ts +0 -134
- package/dist/cache/lru-cache.d.ts +0 -139
- package/dist/cache/middleware-memoization.d.ts +0 -151
- package/dist/cache/route-cache-warmer.d.ts +0 -161
- package/dist/cache/sqlite-cache.d.ts +0 -209
- package/dist/cache/streaming-cache.d.ts +0 -132
- package/dist/chunk-1mvtv6jw.js +0 -13012
- package/dist/cli/colors.d.ts +0 -15
- package/dist/cli/index.d.ts +0 -10
- package/dist/cli/middleware.d.ts +0 -31
- package/dist/cli/openapi.d.ts +0 -17
- package/dist/cli/router.d.ts +0 -15
- package/dist/cli/routes.d.ts +0 -29
- package/dist/cli/utils.d.ts +0 -74
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -3195
- package/dist/config.d.ts +0 -7
- package/dist/container/container.d.ts +0 -273
- package/dist/container/contextual-binding.d.ts +0 -240
- package/dist/container/decorators.d.ts +0 -141
- package/dist/container/service-provider.d.ts +0 -285
- package/dist/development/hot-reload.d.ts +0 -187
- package/dist/development/index.d.ts +0 -167
- package/dist/development/performance-profiler.d.ts +0 -217
- package/dist/development/route-debugger.d.ts +0 -154
- package/dist/development/route-inspector.d.ts +0 -211
- package/dist/development/typescript-utilities.d.ts +0 -209
- package/dist/docs.d.ts +0 -11
- package/dist/errors/circuit-breaker.d.ts +0 -195
- package/dist/errors/error-handler.d.ts +0 -88
- package/dist/errors/error-reporting.d.ts +0 -144
- package/dist/errors/exceptions.d.ts +0 -184
- package/dist/errors/graceful-degradation.d.ts +0 -154
- package/dist/errors/index.d.ts +0 -9
- package/dist/errors/router-errors.d.ts +0 -110
- package/dist/file-serving/static-files.d.ts +0 -143
- package/dist/index.d.ts +0 -14
- package/dist/index.js +0 -13933
- package/dist/middleware/auth.d.ts +0 -63
- package/dist/middleware/content_security_policy.d.ts +0 -53
- package/dist/middleware/cors.d.ts +0 -5
- package/dist/middleware/csrf.d.ts +0 -7
- package/dist/middleware/ddos_protection.d.ts +0 -39
- package/dist/middleware/file_security.d.ts +0 -26
- package/dist/middleware/file_upload.d.ts +0 -38
- package/dist/middleware/helmet.d.ts +0 -54
- package/dist/middleware/index.d.ts +0 -44
- package/dist/middleware/input_validation.d.ts +0 -45
- package/dist/middleware/json_body.d.ts +0 -4
- package/dist/middleware/performance_alerting.d.ts +0 -87
- package/dist/middleware/performance_dashboard.d.ts +0 -87
- package/dist/middleware/performance_monitor.d.ts +0 -209
- package/dist/middleware/pipeline.d.ts +0 -131
- package/dist/middleware/rate_limit.d.ts +0 -36
- package/dist/middleware/request_id.d.ts +0 -4
- package/dist/middleware/request_signing.d.ts +0 -153
- package/dist/middleware/request_tracer.d.ts +0 -72
- package/dist/middleware/response_cache.d.ts +0 -97
- package/dist/middleware/security.d.ts +0 -69
- package/dist/middleware/security_suite.d.ts +0 -46
- package/dist/middleware/session.d.ts +0 -23
- package/dist/model-binding/index.d.ts +0 -2
- package/dist/model-binding/model-middleware.d.ts +0 -118
- package/dist/model-binding/model-registry.d.ts +0 -164
- package/dist/model-binding.d.ts +0 -185
- package/dist/model-resolver-factory.d.ts +0 -31
- package/dist/observability/correlation.d.ts +0 -187
- package/dist/observability/health-checks.d.ts +0 -186
- package/dist/observability/index.d.ts +0 -60
- package/dist/observability/integration.d.ts +0 -147
- package/dist/observability/metrics.d.ts +0 -184
- package/dist/observability/tracing.d.ts +0 -187
- package/dist/optimization/bun-utilities.d.ts +0 -224
- package/dist/query-builder-integration.d.ts +0 -36
- package/dist/request/context.d.ts +0 -34
- package/dist/request/enhanced-request.d.ts +0 -213
- package/dist/request/macros.d.ts +0 -300
- package/dist/response/macros.d.ts +0 -245
- package/dist/response/response-factory.d.ts +0 -133
- package/dist/router/api-routes.d.ts +0 -5
- package/dist/router/file-based-routing.d.ts +0 -118
- package/dist/router/file-streaming.d.ts +0 -5
- package/dist/router/fluent-router.d.ts +0 -315
- package/dist/router/fluent-routing.d.ts +0 -271
- package/dist/router/group-organization.d.ts +0 -5
- package/dist/router/handler-resolver.d.ts +0 -24
- package/dist/router/http-methods.d.ts +0 -10
- package/dist/router/index.d.ts +0 -114
- package/dist/router/middleware-groups.d.ts +0 -94
- package/dist/router/middleware-integration.d.ts +0 -112
- package/dist/router/middleware.d.ts +0 -5
- package/dist/router/model-binding.d.ts +0 -5
- package/dist/router/optimized-route-matching.d.ts +0 -6
- package/dist/router/route-building.d.ts +0 -5
- package/dist/router/route-compiler.d.ts +0 -153
- package/dist/router/route-matching.d.ts +0 -5
- package/dist/router/route-trie.d.ts +0 -114
- package/dist/router/router.d.ts +0 -294
- package/dist/router/server.d.ts +0 -5
- package/dist/router/validation-integration.d.ts +0 -170
- package/dist/router/view-rendering.d.ts +0 -5
- package/dist/router/websocket.d.ts +0 -5
- package/dist/routing/route-caching.d.ts +0 -129
- package/dist/routing/route-throttling.d.ts +0 -150
- package/dist/routing/subdomain-routing.d.ts +0 -206
- package/dist/session/database-store.d.ts +0 -51
- package/dist/session/file-store.d.ts +0 -22
- package/dist/session/index.d.ts +0 -106
- package/dist/session/memory-store.d.ts +0 -21
- package/dist/session/redis-store.d.ts +0 -31
- package/dist/streaming/index.d.ts +0 -3
- package/dist/streaming/sse-handler.d.ts +0 -138
- package/dist/streaming/stream-handler.d.ts +0 -114
- package/dist/testing/auth-testing.d.ts +0 -156
- package/dist/testing/file-upload-testing.d.ts +0 -190
- package/dist/testing/index.d.ts +0 -10
- package/dist/testing/middleware-testing.d.ts +0 -138
- package/dist/testing/model-binding-testing.d.ts +0 -186
- package/dist/testing/performance-testing.d.ts +0 -235
- package/dist/testing/test-client.d.ts +0 -117
- package/dist/testing/test-request.d.ts +0 -85
- package/dist/testing/test-response.d.ts +0 -90
- package/dist/testing/types.d.ts +0 -207
- package/dist/testing/websocket-testing.d.ts +0 -227
- package/dist/types/controller-types.d.ts +0 -208
- package/dist/types/core.d.ts +0 -543
- package/dist/types/middleware-types.d.ts +0 -227
- package/dist/types/request-response-augmentation.d.ts +0 -261
- package/dist/types/route-inference.d.ts +0 -168
- package/dist/types.d.ts +0 -1782
- package/dist/url.d.ts +0 -56
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/query-preservation.d.ts +0 -48
- package/dist/utils.d.ts +0 -69
- package/dist/validation/validator.d.ts +0 -140
- package/dist/websocket/clustering.d.ts +0 -185
- package/src/auth.ts +0 -469
- 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 -740
- package/src/container/contextual-binding.ts +0 -603
- package/src/container/decorators.ts +0 -359
- 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 -732
- 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 -621
- package/src/errors/index.ts +0 -21
- package/src/errors/router-errors.ts +0 -632
- package/src/file-serving/static-files.ts +0 -581
- package/src/index.ts +0 -14
- package/src/middleware/auth.ts +0 -219
- package/src/middleware/content_security_policy.ts +0 -215
- package/src/middleware/cors.ts +0 -74
- package/src/middleware/csrf.ts +0 -108
- package/src/middleware/ddos_protection.ts +0 -255
- package/src/middleware/file_security.ts +0 -191
- package/src/middleware/file_upload.ts +0 -264
- package/src/middleware/helmet.ts +0 -268
- package/src/middleware/index.ts +0 -117
- package/src/middleware/input_validation.ts +0 -449
- package/src/middleware/json_body.ts +0 -37
- package/src/middleware/performance_alerting.ts +0 -538
- package/src/middleware/performance_dashboard.ts +0 -661
- package/src/middleware/performance_monitor.ts +0 -943
- package/src/middleware/pipeline.ts +0 -489
- package/src/middleware/rate_limit.ts +0 -245
- package/src/middleware/request_id.ts +0 -36
- package/src/middleware/request_signing.ts +0 -636
- package/src/middleware/request_tracer.ts +0 -636
- package/src/middleware/response_cache.ts +0 -743
- 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 -62
- package/src/request/enhanced-request.ts +0 -857
- package/src/request/macros.ts +0 -688
- package/src/response/macros.ts +0 -612
- package/src/response/response-factory.ts +0 -596
- package/src/router/api-routes.ts +0 -243
- package/src/router/file-based-routing.ts +0 -670
- package/src/router/file-streaming.ts +0 -372
- package/src/router/fluent-router.ts +0 -927
- package/src/router/fluent-routing.ts +0 -797
- package/src/router/group-organization.ts +0 -213
- package/src/router/handler-resolver.ts +0 -291
- package/src/router/http-methods.ts +0 -377
- package/src/router/index.ts +0 -187
- package/src/router/middleware-groups.ts +0 -222
- package/src/router/middleware-integration.ts +0 -399
- package/src/router/middleware.ts +0 -231
- package/src/router/model-binding.ts +0 -215
- package/src/router/optimized-route-matching.ts +0 -253
- package/src/router/route-building.ts +0 -212
- package/src/router/route-compiler.ts +0 -702
- package/src/router/route-matching.ts +0 -349
- package/src/router/route-trie.ts +0 -464
- package/src/router/router.ts +0 -1581
- package/src/router/server.ts +0 -462
- package/src/router/validation-integration.ts +0 -443
- 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 -446
- 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 -419
- package/src/types/request-response-augmentation.ts +0 -489
- package/src/types/route-inference.ts +0 -357
- package/src/types.ts +0 -2055
- package/src/url.ts +0 -126
- package/src/utils/index.ts +0 -1
- package/src/utils/query-preservation.ts +0 -201
- package/src/utils.ts +0 -327
- package/src/validation/validator.ts +0 -685
- package/src/websocket/clustering.ts +0 -762
package/src/model-binding.ts
DELETED
|
@@ -1,370 +0,0 @@
|
|
|
1
|
-
import type { EnhancedRequest } from './types'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Laravel-style model binding that integrates with bun-query-builder models
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Base model interface compatible with bun-query-builder
|
|
9
|
-
*/
|
|
10
|
-
export interface Model {
|
|
11
|
-
id: string | number
|
|
12
|
-
[key: string]: any
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Get the route key for the model (Laravel-style)
|
|
16
|
-
*/
|
|
17
|
-
getRouteKeyName?: () => string
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Resolve route binding for this model instance (Laravel-style)
|
|
21
|
-
*/
|
|
22
|
-
resolveRouteBinding?: (value: string | number, field?: string) => Promise<this | null>
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Query builder model resolver interface for integration layer
|
|
27
|
-
*/
|
|
28
|
-
export interface QueryBuilderModelResolver<TModel extends Model = Model> {
|
|
29
|
-
table: string
|
|
30
|
-
queryBuilder?: any
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Find a model by ID or custom key
|
|
34
|
-
*/
|
|
35
|
-
find: (id: string | number, keyName?: string) => Promise<TModel | null>
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Find a model by ID or throw if not found
|
|
39
|
-
*/
|
|
40
|
-
findOrFail: (id: string | number, keyName?: string) => Promise<TModel>
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Get the route key name for this model
|
|
44
|
-
*/
|
|
45
|
-
getRouteKeyName?: () => string
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Apply constraints to a query (for scoped binding)
|
|
49
|
-
*/
|
|
50
|
-
applyConstraints?: (query: any, context: Record<string, Model>) => any
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Wrapper for bun-query-builder models to add Laravel-style route binding
|
|
55
|
-
*/
|
|
56
|
-
export class BunQueryBuilderModel<T extends Model = Model> {
|
|
57
|
-
constructor(
|
|
58
|
-
public definition: any, // bun-query-builder model definition
|
|
59
|
-
public queryBuilder: any, // bun-query-builder instance
|
|
60
|
-
) {}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Get table name from bun-query-builder definition
|
|
64
|
-
*/
|
|
65
|
-
getTableName(): string {
|
|
66
|
-
return this.definition.table || `${this.definition.name.toLowerCase()}s`
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Find a model by ID using bun-query-builder's find method
|
|
71
|
-
*/
|
|
72
|
-
async find(id: string | number): Promise<T | null> {
|
|
73
|
-
try {
|
|
74
|
-
const result = await this.queryBuilder.find(this.getTableName(), id)
|
|
75
|
-
return result || null
|
|
76
|
-
}
|
|
77
|
-
catch (error) {
|
|
78
|
-
console.error(`Error finding ${this.definition.name}:`, error)
|
|
79
|
-
return null
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Find a model by ID or throw using bun-query-builder's findOrFail method
|
|
85
|
-
*/
|
|
86
|
-
async findOrFail(id: string | number): Promise<T> {
|
|
87
|
-
try {
|
|
88
|
-
return await this.queryBuilder.findOrFail(this.getTableName(), id)
|
|
89
|
-
}
|
|
90
|
-
catch (error) {
|
|
91
|
-
console.error(error)
|
|
92
|
-
throw new ModelNotFoundError(this.definition.name, id)
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Find by custom field using bun-query-builder's where method
|
|
98
|
-
*/
|
|
99
|
-
async where(field: string, value: any): Promise<T | null> {
|
|
100
|
-
try {
|
|
101
|
-
const result = await this.queryBuilder
|
|
102
|
-
.selectFrom(this.getTableName())
|
|
103
|
-
.where(field, '=', value)
|
|
104
|
-
.first()
|
|
105
|
-
return result || null
|
|
106
|
-
}
|
|
107
|
-
catch (error) {
|
|
108
|
-
console.error(`Error finding ${this.definition.name} by ${field}:`, error)
|
|
109
|
-
return null
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Get the default route key name for this model
|
|
115
|
-
*/
|
|
116
|
-
getRouteKeyName(): string {
|
|
117
|
-
return this.definition.primaryKey || 'id'
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Custom route binding resolution (can be overridden)
|
|
122
|
-
*/
|
|
123
|
-
async resolveRouteBinding(value: string | number, field?: string): Promise<T | null> {
|
|
124
|
-
const keyName = field || this.getRouteKeyName()
|
|
125
|
-
|
|
126
|
-
if (keyName === 'id' || keyName === this.definition.primaryKey) {
|
|
127
|
-
return await this.find(value)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return await this.where(keyName, value)
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Parse route parameter to extract model name and custom key
|
|
136
|
-
* Examples: {user} -> {name: 'user', key: undefined}
|
|
137
|
-
* {post:slug} -> {name: 'post', key: 'slug'}
|
|
138
|
-
*/
|
|
139
|
-
/**
|
|
140
|
-
* Parse multiple route parameters from path
|
|
141
|
-
*/
|
|
142
|
-
export function parseRouteParameters(path: string): { name: string, key?: string }[] {
|
|
143
|
-
return extractModelParameters(path)
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export function parseRouteParameter(param: string): { name: string, key?: string } {
|
|
147
|
-
const match = param.match(/^\{(\w+)(?::(\w+))?\}$/)
|
|
148
|
-
if (!match) {
|
|
149
|
-
throw new Error(`Invalid route parameter format: ${param}`)
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return {
|
|
153
|
-
name: match[1],
|
|
154
|
-
key: match[2],
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Extract model parameters from route path
|
|
160
|
-
*/
|
|
161
|
-
export function extractModelParameters(path: string): { name: string, key?: string }[] {
|
|
162
|
-
const paramMatches = path.match(/\{[^}]+\}/g) || []
|
|
163
|
-
return paramMatches.map(parseRouteParameter)
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Model not found error
|
|
168
|
-
*/
|
|
169
|
-
export class ModelNotFoundError extends Error {
|
|
170
|
-
constructor(
|
|
171
|
-
public modelName: string,
|
|
172
|
-
public value: string | number,
|
|
173
|
-
public field: string = 'id',
|
|
174
|
-
) {
|
|
175
|
-
super(`${modelName} not found with ${field}: ${value}`)
|
|
176
|
-
this.name = 'ModelNotFoundError'
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Model binding registry for explicit bindings (Laravel Route::model and Route::bind)
|
|
182
|
-
*/
|
|
183
|
-
export class ModelBindingRegistry {
|
|
184
|
-
private bindings = new Map<string, BunQueryBuilderModel | ((_value: string) => Promise<Model | null>)>()
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Register explicit model binding (Laravel Route::model style)
|
|
188
|
-
*/
|
|
189
|
-
model<T extends Model>(parameter: string, modelWrapper: BunQueryBuilderModel<T>): void {
|
|
190
|
-
this.bindings.set(parameter, modelWrapper)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Register custom binding resolver (Laravel Route::bind style)
|
|
195
|
-
*/
|
|
196
|
-
bind(parameter: string, resolver: (value: string) => Promise<Model | null>): void {
|
|
197
|
-
this.bindings.set(parameter, resolver)
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Get binding for parameter
|
|
202
|
-
*/
|
|
203
|
-
getBinding(parameter: string): BunQueryBuilderModel | ((_value: string) => Promise<Model | null>) | undefined {
|
|
204
|
-
return this.bindings.get(parameter)
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Check if parameter has explicit binding
|
|
209
|
-
*/
|
|
210
|
-
hasBinding(parameter: string): boolean {
|
|
211
|
-
return this.bindings.has(parameter)
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Global model binding registry instance
|
|
217
|
-
*/
|
|
218
|
-
export const modelRegistry: ModelBindingRegistry = new ModelBindingRegistry()
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Model binding configuration interface
|
|
222
|
-
*/
|
|
223
|
-
export interface ModelBindingConfig {
|
|
224
|
-
model: string
|
|
225
|
-
key?: string
|
|
226
|
-
constraints?: Record<string, any>
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Model class interface
|
|
231
|
-
*/
|
|
232
|
-
export interface ModelClass<T extends Model = Model> {
|
|
233
|
-
new (...args: any[]): T
|
|
234
|
-
find: (id: string | number) => Promise<T | null>
|
|
235
|
-
findOrFail: (id: string | number) => Promise<T>
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Model resolver interface
|
|
240
|
-
*/
|
|
241
|
-
export interface ModelResolver<T extends Model = Model> {
|
|
242
|
-
find: (id: string | number, keyName?: string) => Promise<T | null>
|
|
243
|
-
findOrFail: (id: string | number, keyName?: string) => Promise<T>
|
|
244
|
-
getRouteKeyName?: () => string
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Route binding options interface
|
|
249
|
-
*/
|
|
250
|
-
export interface RouteBindingOptions {
|
|
251
|
-
model?: string
|
|
252
|
-
key?: string
|
|
253
|
-
constraints?: Record<string, any>
|
|
254
|
-
middleware?: string[]
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Resolve model from route parameter using bun-query-builder
|
|
259
|
-
*/
|
|
260
|
-
export async function resolveModel<T extends Model>(
|
|
261
|
-
_paramName: string,
|
|
262
|
-
value: string | number,
|
|
263
|
-
modelWrapper: BunQueryBuilderModel<T>,
|
|
264
|
-
customKey?: string,
|
|
265
|
-
_context: Record<string, Model> = {},
|
|
266
|
-
): Promise<T | null> {
|
|
267
|
-
// Use custom key if provided in route (e.g., {post:slug})
|
|
268
|
-
if (customKey) {
|
|
269
|
-
return await modelWrapper.resolveRouteBinding(value, customKey)
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// Use model's default route key or ID
|
|
273
|
-
const routeKey = modelWrapper.getRouteKeyName()
|
|
274
|
-
if (routeKey !== 'id') {
|
|
275
|
-
return await modelWrapper.resolveRouteBinding(value, routeKey)
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Default to ID lookup
|
|
279
|
-
return await modelWrapper.find(value)
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Route model binding middleware factory for bun-query-builder models
|
|
284
|
-
*/
|
|
285
|
-
export function createModelBindingMiddleware(
|
|
286
|
-
modelParameters: { name: string, key?: string }[],
|
|
287
|
-
modelWrappers: Record<string, BunQueryBuilderModel>,
|
|
288
|
-
): (req: EnhancedRequest, next: () => Promise<Response>) => Promise<Response> {
|
|
289
|
-
return async (req: EnhancedRequest, next: () => Promise<Response>): Promise<Response> => {
|
|
290
|
-
const resolvedModels: Record<string, Model> = {}
|
|
291
|
-
|
|
292
|
-
try {
|
|
293
|
-
// Resolve models in order (for potential scoped binding)
|
|
294
|
-
for (const param of modelParameters) {
|
|
295
|
-
const value = req.params?.[param.name]
|
|
296
|
-
if (!value)
|
|
297
|
-
continue
|
|
298
|
-
|
|
299
|
-
// Check for explicit binding first
|
|
300
|
-
const explicitBinding = modelRegistry.getBinding(param.name)
|
|
301
|
-
if (explicitBinding) {
|
|
302
|
-
let model: Model | null = null
|
|
303
|
-
|
|
304
|
-
if (typeof explicitBinding === 'function') {
|
|
305
|
-
// Custom resolver function
|
|
306
|
-
model = await explicitBinding(value)
|
|
307
|
-
}
|
|
308
|
-
else {
|
|
309
|
-
// Model wrapper
|
|
310
|
-
model = await resolveModel(param.name, value, explicitBinding, param.key, resolvedModels)
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
if (!model) {
|
|
314
|
-
throw new ModelNotFoundError(param.name, value, param.key || 'id')
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
resolvedModels[param.name] = model
|
|
318
|
-
continue
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Implicit binding - look for registered model wrapper
|
|
322
|
-
const modelWrapper = modelWrappers[param.name]
|
|
323
|
-
if (!modelWrapper) {
|
|
324
|
-
// Skip if no model wrapper registered for this parameter
|
|
325
|
-
continue
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
const model = await resolveModel(param.name, value, modelWrapper, param.key, resolvedModels)
|
|
329
|
-
if (!model) {
|
|
330
|
-
throw new ModelNotFoundError(param.name, value, param.key || 'id')
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
resolvedModels[param.name] = model
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// Attach resolved models to request
|
|
337
|
-
;(req as any).models = resolvedModels
|
|
338
|
-
|
|
339
|
-
return await next()
|
|
340
|
-
}
|
|
341
|
-
catch (error) {
|
|
342
|
-
if (error instanceof ModelNotFoundError) {
|
|
343
|
-
return new Response(`${error.modelName} not found`, { status: 404 })
|
|
344
|
-
}
|
|
345
|
-
throw error
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Create a model wrapper from bun-query-builder model definition
|
|
352
|
-
*/
|
|
353
|
-
export function createModelWrapper<T extends Model>(
|
|
354
|
-
modelDefinition: any,
|
|
355
|
-
queryBuilder: any,
|
|
356
|
-
): BunQueryBuilderModel<T> {
|
|
357
|
-
return new BunQueryBuilderModel<T>(modelDefinition, queryBuilder)
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Apply model bindings to a route
|
|
362
|
-
*/
|
|
363
|
-
export function applyModelBindings(
|
|
364
|
-
path: string,
|
|
365
|
-
modelWrappers: Record<string, BunQueryBuilderModel>,
|
|
366
|
-
_options?: RouteBindingOptions,
|
|
367
|
-
): (req: EnhancedRequest, next: () => Promise<Response>) => Promise<Response> {
|
|
368
|
-
const modelParameters = extractModelParameters(path)
|
|
369
|
-
return createModelBindingMiddleware(modelParameters, modelWrappers)
|
|
370
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import type { Model, QueryBuilderModelResolver } from './model-binding'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Factory function to create model resolvers with bun-query-builder integration
|
|
5
|
-
*/
|
|
6
|
-
export function createModelResolver<TModel extends Model = Model>(
|
|
7
|
-
tableName: string,
|
|
8
|
-
options: {
|
|
9
|
-
keyName?: string
|
|
10
|
-
applyConstraints?: (query: any, context: Record<string, Model>) => any
|
|
11
|
-
} = {},
|
|
12
|
-
): QueryBuilderModelResolver<TModel> {
|
|
13
|
-
const { keyName = 'id', applyConstraints } = options
|
|
14
|
-
|
|
15
|
-
return {
|
|
16
|
-
table: tableName,
|
|
17
|
-
queryBuilder: undefined, // Will be injected by the router
|
|
18
|
-
|
|
19
|
-
async find(id: string | number, searchKey = keyName): Promise<TModel | null> {
|
|
20
|
-
if (!this.queryBuilder) {
|
|
21
|
-
throw new Error(`Query builder not initialized for table: ${tableName}`)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
const result = await this.queryBuilder
|
|
26
|
-
.select()
|
|
27
|
-
.from(this.table)
|
|
28
|
-
.where(searchKey, '=', id)
|
|
29
|
-
.first()
|
|
30
|
-
|
|
31
|
-
return result || null
|
|
32
|
-
}
|
|
33
|
-
catch (error) {
|
|
34
|
-
console.error(`Error finding ${tableName} with ${searchKey}: ${id}`, error)
|
|
35
|
-
return null
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
async findOrFail(id: string | number, searchKey = keyName): Promise<TModel> {
|
|
40
|
-
const model = await this.find(id, searchKey)
|
|
41
|
-
if (!model) {
|
|
42
|
-
throw new Error(`${tableName} not found with ${searchKey}: ${id}`)
|
|
43
|
-
}
|
|
44
|
-
return model
|
|
45
|
-
},
|
|
46
|
-
|
|
47
|
-
getRouteKeyName(): string {
|
|
48
|
-
return keyName
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
applyConstraints,
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Create a scoped model resolver that applies constraints based on parent models
|
|
57
|
-
*/
|
|
58
|
-
export function createScopedModelResolver<TModel extends Model = Model>(
|
|
59
|
-
tableName: string,
|
|
60
|
-
constraintFn: (query: any, context: Record<string, Model>) => any,
|
|
61
|
-
options: {
|
|
62
|
-
keyName?: string
|
|
63
|
-
} = {},
|
|
64
|
-
): QueryBuilderModelResolver<TModel> {
|
|
65
|
-
return createModelResolver<TModel>(tableName, {
|
|
66
|
-
...options,
|
|
67
|
-
applyConstraints: constraintFn,
|
|
68
|
-
})
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Common constraint functions for scoped bindings
|
|
73
|
-
*/
|
|
74
|
-
export const constraints = {
|
|
75
|
-
/**
|
|
76
|
-
* Ensure a model belongs to a specific parent model
|
|
77
|
-
*/
|
|
78
|
-
belongsTo: (parentKey: string, foreignKey: string): ((_query: any, _context: Record<string, Model>) => any) =>
|
|
79
|
-
(query: any, context: Record<string, Model>) => {
|
|
80
|
-
const parent = context[parentKey]
|
|
81
|
-
if (parent) {
|
|
82
|
-
return query.where(foreignKey, '=', parent.id)
|
|
83
|
-
}
|
|
84
|
-
return query
|
|
85
|
-
},
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Ensure a model belongs to the authenticated user
|
|
89
|
-
*/
|
|
90
|
-
belongsToUser: (userKey = 'user', foreignKey = 'user_id'): ((_query: any, _context: Record<string, Model>) => any) =>
|
|
91
|
-
(query: any, context: Record<string, Model>) => {
|
|
92
|
-
const user = context[userKey]
|
|
93
|
-
if (user) {
|
|
94
|
-
return query.where(foreignKey, '=', user.id)
|
|
95
|
-
}
|
|
96
|
-
return query
|
|
97
|
-
},
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Apply multiple constraints
|
|
101
|
-
*/
|
|
102
|
-
combine: (...constraintFns: Array<(query: any, context: Record<string, Model>) => any>): ((query: any, context: Record<string, Model>) => any) =>
|
|
103
|
-
(query: any, context: Record<string, Model>) => {
|
|
104
|
-
return constraintFns.reduce((q, fn) => fn(q, context), query)
|
|
105
|
-
},
|
|
106
|
-
}
|