@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
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import type { ActionHandler, RouteGroup } from '../types'
|
|
2
|
-
import type { Router } from './router'
|
|
3
|
-
import { joinPaths } from '../utils'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Route grouping and organization extension for Router class
|
|
7
|
-
*/
|
|
8
|
-
export function registerGroupOrganization(RouterClass: typeof Router): void {
|
|
9
|
-
Object.defineProperties(RouterClass.prototype, {
|
|
10
|
-
/**
|
|
11
|
-
* Create a route group with shared attributes
|
|
12
|
-
*/
|
|
13
|
-
group: {
|
|
14
|
-
value(options: RouteGroup, callback: () => void): Router {
|
|
15
|
-
// Save the current group if there is one
|
|
16
|
-
const previousGroup = this.currentGroup
|
|
17
|
-
|
|
18
|
-
// Create a new group by merging with previous group
|
|
19
|
-
const newGroup: RouteGroup = { ...previousGroup }
|
|
20
|
-
|
|
21
|
-
// Handle prefix nesting
|
|
22
|
-
if (options.prefix && previousGroup?.prefix) {
|
|
23
|
-
newGroup.prefix = joinPaths(previousGroup.prefix, options.prefix)
|
|
24
|
-
}
|
|
25
|
-
else if (options.prefix) {
|
|
26
|
-
newGroup.prefix = options.prefix
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Merge middleware
|
|
30
|
-
if (options.middleware) {
|
|
31
|
-
newGroup.middleware = [
|
|
32
|
-
...(previousGroup?.middleware || []),
|
|
33
|
-
...options.middleware,
|
|
34
|
-
]
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Set the new group
|
|
38
|
-
this.currentGroup = newGroup
|
|
39
|
-
|
|
40
|
-
// Execute the callback to register routes in this group
|
|
41
|
-
callback()
|
|
42
|
-
|
|
43
|
-
// Restore the previous group
|
|
44
|
-
this.currentGroup = previousGroup
|
|
45
|
-
|
|
46
|
-
return this
|
|
47
|
-
},
|
|
48
|
-
writable: true,
|
|
49
|
-
configurable: true,
|
|
50
|
-
},
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Create a route group with a name prefix
|
|
54
|
-
*/
|
|
55
|
-
name: {
|
|
56
|
-
value(prefix: string, callback: () => void): Router {
|
|
57
|
-
// Save previous group
|
|
58
|
-
const previousGroup = this.currentGroup || {}
|
|
59
|
-
|
|
60
|
-
// Create a new group with the name prefix
|
|
61
|
-
const newGroup: RouteGroup = { ...previousGroup }
|
|
62
|
-
this.currentGroup = newGroup
|
|
63
|
-
|
|
64
|
-
// Keep track of routes before the callback
|
|
65
|
-
const routeCountBefore = this.routes.length
|
|
66
|
-
|
|
67
|
-
// Execute the callback to register routes
|
|
68
|
-
callback()
|
|
69
|
-
|
|
70
|
-
// Apply name prefix to newly added routes
|
|
71
|
-
for (let i = routeCountBefore; i < this.routes.length; i++) {
|
|
72
|
-
const route = this.routes[i]
|
|
73
|
-
if (route.name) {
|
|
74
|
-
route.name = `${prefix}.${route.name}`
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Restore previous group
|
|
79
|
-
this.currentGroup = previousGroup
|
|
80
|
-
|
|
81
|
-
return this
|
|
82
|
-
},
|
|
83
|
-
writable: true,
|
|
84
|
-
configurable: true,
|
|
85
|
-
},
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Create a route group with a controller
|
|
89
|
-
*/
|
|
90
|
-
controller: {
|
|
91
|
-
value(controller: string | (new () => any), callback: () => void): Router {
|
|
92
|
-
// Save previous group
|
|
93
|
-
const previousGroup = this.currentGroup || {}
|
|
94
|
-
|
|
95
|
-
// Create a new group with the controller
|
|
96
|
-
const newGroup: RouteGroup = { ...previousGroup, controller }
|
|
97
|
-
this.currentGroup = newGroup
|
|
98
|
-
|
|
99
|
-
// Execute the callback to register routes
|
|
100
|
-
callback()
|
|
101
|
-
|
|
102
|
-
// Restore previous group
|
|
103
|
-
this.currentGroup = previousGroup
|
|
104
|
-
|
|
105
|
-
return this
|
|
106
|
-
},
|
|
107
|
-
writable: true,
|
|
108
|
-
configurable: true,
|
|
109
|
-
},
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Create a route group with a domain
|
|
113
|
-
*/
|
|
114
|
-
domain: {
|
|
115
|
-
value(domain: string, callback: () => void): Router {
|
|
116
|
-
// Save previous domain
|
|
117
|
-
const previousDomain = this.currentDomain
|
|
118
|
-
|
|
119
|
-
// Set the new domain
|
|
120
|
-
this.currentDomain = domain
|
|
121
|
-
|
|
122
|
-
// Execute the callback to register routes
|
|
123
|
-
callback()
|
|
124
|
-
|
|
125
|
-
// Restore previous domain
|
|
126
|
-
this.currentDomain = previousDomain
|
|
127
|
-
|
|
128
|
-
return this
|
|
129
|
-
},
|
|
130
|
-
writable: true,
|
|
131
|
-
configurable: true,
|
|
132
|
-
},
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Create a route group with a prefix
|
|
136
|
-
*/
|
|
137
|
-
prefix: {
|
|
138
|
-
value(prefix: string, callback: () => void): Router {
|
|
139
|
-
return this.group({ prefix }, callback)
|
|
140
|
-
},
|
|
141
|
-
writable: true,
|
|
142
|
-
configurable: true,
|
|
143
|
-
},
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Create RESTful resource routes
|
|
147
|
-
*/
|
|
148
|
-
resource: {
|
|
149
|
-
value(
|
|
150
|
-
name: string,
|
|
151
|
-
handler: string | { [key: string]: ActionHandler },
|
|
152
|
-
type: 'api' | 'web' = 'api',
|
|
153
|
-
): Router {
|
|
154
|
-
// Normalize the name to build paths
|
|
155
|
-
const pluralName = name.endsWith('s') ? name : `${name}s`
|
|
156
|
-
const singularName = name.endsWith('s') ? name.slice(0, -1) : name
|
|
157
|
-
|
|
158
|
-
// Define the routes to create
|
|
159
|
-
const routes = [
|
|
160
|
-
{ name: 'index', method: 'GET', path: `/${pluralName}`, action: 'index' },
|
|
161
|
-
{ name: 'create', method: 'GET', path: `/${pluralName}/create`, action: 'create' },
|
|
162
|
-
{ name: 'store', method: 'POST', path: `/${pluralName}`, action: 'store' },
|
|
163
|
-
{ name: 'show', method: 'GET', path: `/${pluralName}/{id}`, action: 'show' },
|
|
164
|
-
{ name: 'edit', method: 'GET', path: `/${pluralName}/{id}/edit`, action: 'edit' },
|
|
165
|
-
{ name: 'update', method: 'PUT', path: `/${pluralName}/{id}`, action: 'update' },
|
|
166
|
-
{ name: 'destroy', method: 'DELETE', path: `/${pluralName}/{id}`, action: 'destroy' },
|
|
167
|
-
]
|
|
168
|
-
|
|
169
|
-
// Use the name prefix for route names
|
|
170
|
-
this.name(singularName, () => {
|
|
171
|
-
for (const route of routes) {
|
|
172
|
-
let routeHandler: ActionHandler
|
|
173
|
-
|
|
174
|
-
if (typeof handler === 'string') {
|
|
175
|
-
// If handler is a string, use it as a prefix for the action
|
|
176
|
-
routeHandler = `${handler}${route.action.charAt(0).toUpperCase() + route.action.slice(1)}Action` as any
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
179
|
-
// If handler is an object, get the action handler from it
|
|
180
|
-
if (handler[route.action]) {
|
|
181
|
-
routeHandler = handler[route.action]
|
|
182
|
-
}
|
|
183
|
-
else {
|
|
184
|
-
// Skip this route if no handler is defined
|
|
185
|
-
continue
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Register the route with the appropriate HTTP method
|
|
190
|
-
switch (route.method) {
|
|
191
|
-
case 'GET':
|
|
192
|
-
this.get(route.path, routeHandler, type, route.name)
|
|
193
|
-
break
|
|
194
|
-
case 'POST':
|
|
195
|
-
this.post(route.path, routeHandler, type, route.name)
|
|
196
|
-
break
|
|
197
|
-
case 'PUT':
|
|
198
|
-
this.put(route.path, routeHandler, type, route.name)
|
|
199
|
-
break
|
|
200
|
-
case 'DELETE':
|
|
201
|
-
this.delete(route.path, routeHandler, type, route.name)
|
|
202
|
-
break
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
return this
|
|
208
|
-
},
|
|
209
|
-
writable: true,
|
|
210
|
-
configurable: true,
|
|
211
|
-
},
|
|
212
|
-
})
|
|
213
|
-
}
|
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Handler Resolver
|
|
3
|
-
*
|
|
4
|
-
* Resolves route handlers from various formats:
|
|
5
|
-
* - Functions returning Response
|
|
6
|
-
* - Functions returning strings/objects (auto-wrapped)
|
|
7
|
-
* - String file paths like 'UserAction.ts' or './actions/UserAction'
|
|
8
|
-
* - Controller@method patterns like 'UserController@index'
|
|
9
|
-
* - Class constructors with handle() method
|
|
10
|
-
* - Class instances with handle() method
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import type { EnhancedRequest, RouterConfig } from '../types'
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Wraps a value in a Response object if it's not already a Response
|
|
17
|
-
*/
|
|
18
|
-
export function wrapResponse(value: unknown): Response {
|
|
19
|
-
// Already a Response
|
|
20
|
-
if (value instanceof Response) {
|
|
21
|
-
return value
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Null or undefined - return 204 No Content
|
|
25
|
-
if (value === null || value === undefined) {
|
|
26
|
-
return new Response(null, { status: 204 })
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// String - return as text/plain
|
|
30
|
-
if (typeof value === 'string') {
|
|
31
|
-
return new Response(value, {
|
|
32
|
-
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
|
|
33
|
-
})
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Number or boolean - convert to string
|
|
37
|
-
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
38
|
-
return new Response(String(value), {
|
|
39
|
-
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
|
|
40
|
-
})
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// ArrayBuffer or Uint8Array - return as binary
|
|
44
|
-
if (value instanceof ArrayBuffer || value instanceof Uint8Array) {
|
|
45
|
-
return new Response(value as any, {
|
|
46
|
-
headers: { 'Content-Type': 'application/octet-stream' },
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// ReadableStream - return as stream
|
|
51
|
-
if (value instanceof ReadableStream) {
|
|
52
|
-
return new Response(value)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Object or array - return as JSON
|
|
56
|
-
if (typeof value === 'object') {
|
|
57
|
-
return new Response(JSON.stringify(value), {
|
|
58
|
-
headers: { 'Content-Type': 'application/json; charset=utf-8' },
|
|
59
|
-
})
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Fallback - convert to string
|
|
63
|
-
return new Response(String(value), {
|
|
64
|
-
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Resolves a string handler path to an imported module
|
|
70
|
-
*/
|
|
71
|
-
async function importHandler(handlerPath: string, config: RouterConfig): Promise<unknown> {
|
|
72
|
-
const actionsPath = config.actionsPath || 'actions'
|
|
73
|
-
const controllersPath = config.controllersPath || 'controllers'
|
|
74
|
-
|
|
75
|
-
// Normalize the path - remove .ts/.js extension if present
|
|
76
|
-
const normalizedPath = handlerPath.replace(/\.(ts|js)$/, '')
|
|
77
|
-
|
|
78
|
-
// List of paths to try for importing
|
|
79
|
-
const pathsToTry: string[] = []
|
|
80
|
-
|
|
81
|
-
// Check if it's a Controller@method pattern
|
|
82
|
-
if (normalizedPath.includes('@')) {
|
|
83
|
-
const [controllerName, _methodName] = normalizedPath.split('@')
|
|
84
|
-
pathsToTry.push(
|
|
85
|
-
`${controllersPath}/${controllerName}`,
|
|
86
|
-
`${controllersPath}/${controllerName}.ts`,
|
|
87
|
-
`${controllersPath}/${controllerName}.js`,
|
|
88
|
-
`./${controllersPath}/${controllerName}`,
|
|
89
|
-
`../${controllersPath}/${controllerName}`,
|
|
90
|
-
)
|
|
91
|
-
}
|
|
92
|
-
// Check if it's an Actions/ path pattern
|
|
93
|
-
else if (normalizedPath.startsWith('Actions/') || normalizedPath.startsWith('actions/')) {
|
|
94
|
-
pathsToTry.push(
|
|
95
|
-
normalizedPath,
|
|
96
|
-
`./${normalizedPath}`,
|
|
97
|
-
`../${normalizedPath}`,
|
|
98
|
-
)
|
|
99
|
-
}
|
|
100
|
-
// Check if it's a relative path
|
|
101
|
-
else if (normalizedPath.startsWith('./') || normalizedPath.startsWith('../')) {
|
|
102
|
-
pathsToTry.push(normalizedPath)
|
|
103
|
-
}
|
|
104
|
-
// Otherwise, try various locations
|
|
105
|
-
else {
|
|
106
|
-
pathsToTry.push(
|
|
107
|
-
// Try actionsPath first
|
|
108
|
-
`${actionsPath}/${normalizedPath}`,
|
|
109
|
-
`./${actionsPath}/${normalizedPath}`,
|
|
110
|
-
`../${actionsPath}/${normalizedPath}`,
|
|
111
|
-
// Try direct import
|
|
112
|
-
normalizedPath,
|
|
113
|
-
`./${normalizedPath}`,
|
|
114
|
-
`../${normalizedPath}`,
|
|
115
|
-
)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
let lastError: Error | null = null
|
|
119
|
-
|
|
120
|
-
for (const path of pathsToTry) {
|
|
121
|
-
try {
|
|
122
|
-
const module = await import(path)
|
|
123
|
-
return module
|
|
124
|
-
}
|
|
125
|
-
catch (error) {
|
|
126
|
-
lastError = error as Error
|
|
127
|
-
// Continue trying other paths
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
throw new Error(
|
|
132
|
-
`Failed to import handler "${handlerPath}".\n`
|
|
133
|
-
+ `Tried paths: ${pathsToTry.join(', ')}\n`
|
|
134
|
-
+ `Last error: ${lastError?.message || 'Unknown error'}`,
|
|
135
|
-
)
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Check if a value is a callable function handler
|
|
140
|
-
*/
|
|
141
|
-
function isCallableHandler(handler: unknown): handler is (req: EnhancedRequest) => unknown {
|
|
142
|
-
return typeof handler === 'function' && !handler.prototype?.handle
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Resolves and executes a handler, returning a Response
|
|
147
|
-
*/
|
|
148
|
-
export async function resolveHandler(
|
|
149
|
-
handler: unknown,
|
|
150
|
-
req: EnhancedRequest,
|
|
151
|
-
config: RouterConfig,
|
|
152
|
-
): Promise<Response> {
|
|
153
|
-
// 0. If it's already a Response (static route), clone and return it directly
|
|
154
|
-
if (handler instanceof Response) {
|
|
155
|
-
return handler.clone() as Response
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// 1. If it's a function (not a class with handle method), call it and wrap the result
|
|
159
|
-
if (isCallableHandler(handler)) {
|
|
160
|
-
const result = await handler(req)
|
|
161
|
-
return wrapResponse(result)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// 2. If it's a string, try to import and resolve
|
|
165
|
-
if (typeof handler === 'string') {
|
|
166
|
-
return resolveStringHandler(handler, req, config)
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// 3. If it's a class constructor with handle method
|
|
170
|
-
if (
|
|
171
|
-
typeof handler === 'function'
|
|
172
|
-
&& handler.prototype
|
|
173
|
-
&& typeof handler.prototype.handle === 'function'
|
|
174
|
-
) {
|
|
175
|
-
const HandlerClass = handler as new () => { handle: (req: EnhancedRequest) => unknown }
|
|
176
|
-
const instance = new HandlerClass()
|
|
177
|
-
const result = await instance.handle(req)
|
|
178
|
-
return wrapResponse(result)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// 4. If it's an object with a handle method
|
|
182
|
-
if (handler && typeof handler === 'object' && 'handle' in handler) {
|
|
183
|
-
const handlerObj = handler as { handle: (req: EnhancedRequest) => unknown }
|
|
184
|
-
if (typeof handlerObj.handle === 'function') {
|
|
185
|
-
const result = await handlerObj.handle(req)
|
|
186
|
-
return wrapResponse(result)
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
throw new Error(`Invalid handler type: ${typeof handler}`)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Resolves a string-based handler
|
|
195
|
-
*/
|
|
196
|
-
async function resolveStringHandler(
|
|
197
|
-
handlerPath: string,
|
|
198
|
-
req: EnhancedRequest,
|
|
199
|
-
config: RouterConfig,
|
|
200
|
-
): Promise<Response> {
|
|
201
|
-
const controllersPath = config.controllersPath || 'controllers'
|
|
202
|
-
|
|
203
|
-
// Check if it's a Controller@method pattern
|
|
204
|
-
if (handlerPath.includes('@')) {
|
|
205
|
-
const [controllerName, methodName] = handlerPath.split('@')
|
|
206
|
-
|
|
207
|
-
// Import the controller
|
|
208
|
-
const pathsToTry = [
|
|
209
|
-
`${controllersPath}/${controllerName}`,
|
|
210
|
-
`./${controllersPath}/${controllerName}`,
|
|
211
|
-
`../${controllersPath}/${controllerName}`,
|
|
212
|
-
controllerName,
|
|
213
|
-
`./${controllerName}`,
|
|
214
|
-
`../${controllerName}`,
|
|
215
|
-
]
|
|
216
|
-
|
|
217
|
-
let module: unknown = null
|
|
218
|
-
let lastError: Error | null = null
|
|
219
|
-
|
|
220
|
-
for (const path of pathsToTry) {
|
|
221
|
-
try {
|
|
222
|
-
module = await import(path)
|
|
223
|
-
break
|
|
224
|
-
}
|
|
225
|
-
catch (error) {
|
|
226
|
-
lastError = error as Error
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (!module) {
|
|
231
|
-
throw new Error(
|
|
232
|
-
`Failed to import controller "${controllerName}".\n`
|
|
233
|
-
+ `Tried paths: ${pathsToTry.join(', ')}\n`
|
|
234
|
-
+ `Last error: ${lastError?.message || 'Unknown error'}`,
|
|
235
|
-
)
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const Controller = (module as { default?: unknown }).default || module
|
|
239
|
-
|
|
240
|
-
// Instantiate and call method
|
|
241
|
-
if (typeof Controller === 'function') {
|
|
242
|
-
const instance = new (Controller as new () => Record<string, unknown>)()
|
|
243
|
-
const method = instance[methodName]
|
|
244
|
-
|
|
245
|
-
if (typeof method !== 'function') {
|
|
246
|
-
throw new TypeError(`Method "${methodName}" not found on controller "${controllerName}"`)
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const result = await (method as (req: EnhancedRequest) => unknown).call(instance, req)
|
|
250
|
-
return wrapResponse(result)
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
throw new Error(`Controller "${controllerName}" is not a valid class`)
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Import the action handler
|
|
257
|
-
const module = await importHandler(handlerPath, config)
|
|
258
|
-
const Handler = (module as { default?: unknown }).default || module
|
|
259
|
-
|
|
260
|
-
// If it's a function, call it
|
|
261
|
-
if (typeof Handler === 'function') {
|
|
262
|
-
// Check if it's a class with handle method
|
|
263
|
-
if (Handler.prototype && typeof Handler.prototype.handle === 'function') {
|
|
264
|
-
const instance = new (Handler as new () => { handle: (req: EnhancedRequest) => unknown })()
|
|
265
|
-
const result = await instance.handle(req)
|
|
266
|
-
return wrapResponse(result)
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// It's a regular function
|
|
270
|
-
const result = await (Handler as (req: EnhancedRequest) => unknown)(req)
|
|
271
|
-
return wrapResponse(result)
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// If it's an object with handle method
|
|
275
|
-
if (Handler && typeof Handler === 'object' && 'handle' in Handler) {
|
|
276
|
-
const handlerObj = Handler as { handle: (req: EnhancedRequest) => unknown }
|
|
277
|
-
if (typeof handlerObj.handle === 'function') {
|
|
278
|
-
const result = await handlerObj.handle(req)
|
|
279
|
-
return wrapResponse(result)
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
throw new Error(`Handler "${handlerPath}" does not export a valid handler function or class`)
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Creates a handler resolver bound to a specific config
|
|
288
|
-
*/
|
|
289
|
-
export function createHandlerResolver(config: RouterConfig): (handler: unknown, req: EnhancedRequest) => Promise<Response> {
|
|
290
|
-
return (handler: unknown, req: EnhancedRequest) => resolveHandler(handler, req, config)
|
|
291
|
-
}
|