@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,492 +0,0 @@
|
|
|
1
|
-
import type { EnhancedRequest, MiddlewareHandler, RouteHandler } from '../types'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Domain pattern configuration
|
|
5
|
-
*/
|
|
6
|
-
export interface DomainPattern {
|
|
7
|
-
pattern: string // e.g., '{account}.app.com', 'api.{domain}.com'
|
|
8
|
-
parameters: string[] // Extracted parameter names
|
|
9
|
-
regex: RegExp // Compiled regex for matching
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Domain group configuration
|
|
14
|
-
*/
|
|
15
|
-
export interface DomainGroupConfig {
|
|
16
|
-
domain: string
|
|
17
|
-
middleware?: MiddlewareHandler[]
|
|
18
|
-
prefix?: string
|
|
19
|
-
name?: string
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Subdomain route information
|
|
24
|
-
*/
|
|
25
|
-
export interface SubdomainRouteInfo {
|
|
26
|
-
domain: string
|
|
27
|
-
parameters: Record<string, string>
|
|
28
|
-
subdomain?: string
|
|
29
|
-
rootDomain?: string
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Domain pattern parser and matcher
|
|
34
|
-
*/
|
|
35
|
-
export class DomainMatcher {
|
|
36
|
-
/**
|
|
37
|
-
* Parse domain pattern into regex and parameter names
|
|
38
|
-
*/
|
|
39
|
-
static parseDomainPattern(pattern: string): DomainPattern {
|
|
40
|
-
const parameters: string[] = []
|
|
41
|
-
|
|
42
|
-
// Extract parameters from pattern (e.g., {account}, {subdomain})
|
|
43
|
-
const paramMatches = pattern.match(/\{([^}]+)\}/g) || []
|
|
44
|
-
|
|
45
|
-
for (const match of paramMatches) {
|
|
46
|
-
const paramName = match.slice(1, -1) // Remove { }
|
|
47
|
-
parameters.push(paramName)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Convert pattern to regex
|
|
51
|
-
let regexPattern = pattern
|
|
52
|
-
.replace(/\./g, '\\.') // Escape dots
|
|
53
|
-
.replace(/\{([^}]+)\}/g, '([^.]+)') // Replace {param} with capture group
|
|
54
|
-
|
|
55
|
-
// Ensure full domain match
|
|
56
|
-
regexPattern = `^${regexPattern}$`
|
|
57
|
-
|
|
58
|
-
const regex = new RegExp(regexPattern, 'i') // Case insensitive
|
|
59
|
-
|
|
60
|
-
return {
|
|
61
|
-
pattern,
|
|
62
|
-
parameters,
|
|
63
|
-
regex,
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Match domain against pattern and extract parameters
|
|
69
|
-
*/
|
|
70
|
-
static matchDomain(domain: string, pattern: DomainPattern): Record<string, string> | null {
|
|
71
|
-
const match = domain.match(pattern.regex)
|
|
72
|
-
if (!match) {
|
|
73
|
-
return null
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const parameters: Record<string, string> = {}
|
|
77
|
-
|
|
78
|
-
// Extract parameter values from regex groups
|
|
79
|
-
for (let i = 0; i < pattern.parameters.length; i++) {
|
|
80
|
-
const paramName = pattern.parameters[i]
|
|
81
|
-
const paramValue = match[i + 1] // match[0] is full match, parameters start at index 1
|
|
82
|
-
parameters[paramName] = paramValue
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return parameters
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Extract subdomain information from domain
|
|
90
|
-
*/
|
|
91
|
-
static extractSubdomainInfo(domain: string): SubdomainRouteInfo {
|
|
92
|
-
const parts = domain.split('.')
|
|
93
|
-
|
|
94
|
-
if (parts.length <= 2) {
|
|
95
|
-
// No subdomain (e.g., example.com)
|
|
96
|
-
return {
|
|
97
|
-
domain,
|
|
98
|
-
parameters: {},
|
|
99
|
-
rootDomain: domain,
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Has subdomain (e.g., api.example.com, user.api.example.com)
|
|
104
|
-
const subdomain = parts[0]
|
|
105
|
-
const rootDomain = parts.slice(1).join('.')
|
|
106
|
-
|
|
107
|
-
return {
|
|
108
|
-
domain,
|
|
109
|
-
parameters: { subdomain },
|
|
110
|
-
subdomain,
|
|
111
|
-
rootDomain,
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Domain group for organizing routes by domain patterns
|
|
118
|
-
*/
|
|
119
|
-
export class DomainGroup {
|
|
120
|
-
private routes: Array<{
|
|
121
|
-
method: string
|
|
122
|
-
path: string
|
|
123
|
-
handler: RouteHandler
|
|
124
|
-
middleware: MiddlewareHandler[]
|
|
125
|
-
name?: string
|
|
126
|
-
}> = []
|
|
127
|
-
|
|
128
|
-
constructor(
|
|
129
|
-
public pattern: DomainPattern,
|
|
130
|
-
public config: DomainGroupConfig,
|
|
131
|
-
) {}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Add route to domain group
|
|
135
|
-
*/
|
|
136
|
-
addRoute(
|
|
137
|
-
method: string,
|
|
138
|
-
path: string,
|
|
139
|
-
handler: RouteHandler,
|
|
140
|
-
middleware: MiddlewareHandler[] = [],
|
|
141
|
-
name?: string,
|
|
142
|
-
): void {
|
|
143
|
-
// Combine group middleware with route middleware
|
|
144
|
-
const allMiddleware = [
|
|
145
|
-
...(this.config.middleware || []),
|
|
146
|
-
...middleware,
|
|
147
|
-
]
|
|
148
|
-
|
|
149
|
-
// Add prefix if configured
|
|
150
|
-
const fullPath = this.config.prefix ? `${this.config.prefix}${path}` : path
|
|
151
|
-
|
|
152
|
-
this.routes.push({
|
|
153
|
-
method: method.toUpperCase(),
|
|
154
|
-
path: fullPath,
|
|
155
|
-
handler,
|
|
156
|
-
middleware: allMiddleware,
|
|
157
|
-
name: name || (this.config.name ? `${this.config.name}.${method.toLowerCase()}${path}` : undefined),
|
|
158
|
-
})
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Get all routes in this domain group
|
|
163
|
-
*/
|
|
164
|
-
getRoutes(): Array<{ method: string, path: string, handler: RouteHandler, middleware: MiddlewareHandler[] }> {
|
|
165
|
-
return [...this.routes] as Array<{ method: string, path: string, handler: RouteHandler, middleware: MiddlewareHandler[] }>
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Check if domain matches this group's pattern
|
|
170
|
-
*/
|
|
171
|
-
matchesDomain(domain: string): Record<string, string> | null {
|
|
172
|
-
return DomainMatcher.matchDomain(domain, this.pattern)
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Subdomain router for managing domain-based routing
|
|
178
|
-
*/
|
|
179
|
-
export class SubdomainRouter {
|
|
180
|
-
private domainGroups: DomainGroup[] = []
|
|
181
|
-
private wildcardGroup?: DomainGroup // Fallback for unmatched domains
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Create domain group with pattern
|
|
185
|
-
*/
|
|
186
|
-
domain(pattern: string): DomainGroupBuilder {
|
|
187
|
-
const domainPattern = DomainMatcher.parseDomainPattern(pattern)
|
|
188
|
-
return new DomainGroupBuilder(this, domainPattern)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Add domain group to router
|
|
193
|
-
*/
|
|
194
|
-
addDomainGroup(group: DomainGroup): void {
|
|
195
|
-
// Check if this is a wildcard pattern (no parameters, contains *)
|
|
196
|
-
if (group.pattern.pattern.includes('*') && group.pattern.parameters.length === 0) {
|
|
197
|
-
this.wildcardGroup = group
|
|
198
|
-
}
|
|
199
|
-
else {
|
|
200
|
-
this.domainGroups.push(group)
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Find matching domain group and extract parameters
|
|
206
|
-
*/
|
|
207
|
-
findDomainGroup(domain: string): { group: DomainGroup, parameters: Record<string, string> } | null {
|
|
208
|
-
// Try specific domain patterns first
|
|
209
|
-
for (const group of this.domainGroups) {
|
|
210
|
-
const parameters = group.matchesDomain(domain)
|
|
211
|
-
if (parameters !== null) {
|
|
212
|
-
return { group, parameters }
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Fall back to wildcard group if available
|
|
217
|
-
if (this.wildcardGroup) {
|
|
218
|
-
return {
|
|
219
|
-
group: this.wildcardGroup,
|
|
220
|
-
parameters: DomainMatcher.extractSubdomainInfo(domain).parameters,
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return null
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Get all routes from all domain groups
|
|
229
|
-
*/
|
|
230
|
-
getAllRoutes(): Array<{
|
|
231
|
-
domainPattern: string
|
|
232
|
-
domainParameters: Record<string, string>
|
|
233
|
-
method: string
|
|
234
|
-
path: string
|
|
235
|
-
handler: RouteHandler
|
|
236
|
-
middleware: MiddlewareHandler[]
|
|
237
|
-
name?: string
|
|
238
|
-
}> {
|
|
239
|
-
const allRoutes: Array<{
|
|
240
|
-
domainPattern: string
|
|
241
|
-
domainParameters: Record<string, string>
|
|
242
|
-
method: string
|
|
243
|
-
path: string
|
|
244
|
-
handler: RouteHandler
|
|
245
|
-
middleware: MiddlewareHandler[]
|
|
246
|
-
name?: string
|
|
247
|
-
}> = []
|
|
248
|
-
|
|
249
|
-
for (const group of this.domainGroups) {
|
|
250
|
-
const routes = group.getRoutes()
|
|
251
|
-
for (const route of routes) {
|
|
252
|
-
allRoutes.push({
|
|
253
|
-
domainPattern: group.pattern.pattern,
|
|
254
|
-
domainParameters: {},
|
|
255
|
-
...route,
|
|
256
|
-
})
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
if (this.wildcardGroup) {
|
|
261
|
-
const routes = this.wildcardGroup.getRoutes()
|
|
262
|
-
for (const route of routes) {
|
|
263
|
-
allRoutes.push({
|
|
264
|
-
domainPattern: this.wildcardGroup.pattern.pattern,
|
|
265
|
-
domainParameters: {},
|
|
266
|
-
...route,
|
|
267
|
-
})
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
return allRoutes
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Domain group builder for fluent API
|
|
277
|
-
*/
|
|
278
|
-
export class DomainGroupBuilder {
|
|
279
|
-
private group: DomainGroup
|
|
280
|
-
|
|
281
|
-
constructor(
|
|
282
|
-
private router: SubdomainRouter,
|
|
283
|
-
private pattern: DomainPattern,
|
|
284
|
-
) {
|
|
285
|
-
this.group = new DomainGroup(pattern, { domain: pattern.pattern })
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Set middleware for domain group
|
|
290
|
-
*/
|
|
291
|
-
middleware(middleware: MiddlewareHandler[]): this {
|
|
292
|
-
this.group.config.middleware = middleware
|
|
293
|
-
return this
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Set prefix for all routes in group
|
|
298
|
-
*/
|
|
299
|
-
prefix(prefix: string): this {
|
|
300
|
-
this.group.config.prefix = prefix
|
|
301
|
-
return this
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Set name prefix for routes in group
|
|
306
|
-
*/
|
|
307
|
-
name(name: string): this {
|
|
308
|
-
this.group.config.name = name
|
|
309
|
-
return this
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Define routes within domain group
|
|
314
|
-
*/
|
|
315
|
-
routes(callback: (builder: RouteGroupBuilder) => void): void {
|
|
316
|
-
const routeBuilder = new RouteGroupBuilder(this.group)
|
|
317
|
-
callback(routeBuilder)
|
|
318
|
-
this.router.addDomainGroup(this.group)
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* Add single route (shorthand)
|
|
323
|
-
*/
|
|
324
|
-
get(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[]): void {
|
|
325
|
-
this.group.addRoute('GET', path, handler, middleware)
|
|
326
|
-
this.router.addDomainGroup(this.group)
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
post(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[]): void {
|
|
330
|
-
this.group.addRoute('POST', path, handler, middleware)
|
|
331
|
-
this.router.addDomainGroup(this.group)
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
put(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[]): void {
|
|
335
|
-
this.group.addRoute('PUT', path, handler, middleware)
|
|
336
|
-
this.router.addDomainGroup(this.group)
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
delete(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[]): void {
|
|
340
|
-
this.group.addRoute('DELETE', path, handler, middleware)
|
|
341
|
-
this.router.addDomainGroup(this.group)
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
patch(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[]): void {
|
|
345
|
-
this.group.addRoute('PATCH', path, handler, middleware)
|
|
346
|
-
this.router.addDomainGroup(this.group)
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Route group builder for defining routes within domain groups
|
|
352
|
-
*/
|
|
353
|
-
export class RouteGroupBuilder {
|
|
354
|
-
constructor(private group: DomainGroup) {}
|
|
355
|
-
|
|
356
|
-
get(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[], name?: string): void {
|
|
357
|
-
this.group.addRoute('GET', path, handler, middleware, name)
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
post(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[], name?: string): void {
|
|
361
|
-
this.group.addRoute('POST', path, handler, middleware, name)
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
put(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[], name?: string): void {
|
|
365
|
-
this.group.addRoute('PUT', path, handler, middleware, name)
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
delete(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[], name?: string): void {
|
|
369
|
-
this.group.addRoute('DELETE', path, handler, middleware, name)
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
patch(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[], name?: string): void {
|
|
373
|
-
this.group.addRoute('PATCH', path, handler, middleware, name)
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
options(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[], name?: string): void {
|
|
377
|
-
this.group.addRoute('OPTIONS', path, handler, middleware, name)
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
head(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[], name?: string): void {
|
|
381
|
-
this.group.addRoute('HEAD', path, handler, middleware, name)
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
any(path: string, handler: RouteHandler, middleware?: MiddlewareHandler[], name?: string): void {
|
|
385
|
-
const methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD']
|
|
386
|
-
for (const method of methods) {
|
|
387
|
-
this.group.addRoute(method, path, handler, middleware, name)
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* Create subdomain routing middleware
|
|
394
|
-
*/
|
|
395
|
-
export function createSubdomainMiddleware(subdomainRouter: SubdomainRouter) {
|
|
396
|
-
return async (req: EnhancedRequest, next: () => Promise<Response>): Promise<Response> => {
|
|
397
|
-
const url = new URL(req.url)
|
|
398
|
-
const domain = url.hostname
|
|
399
|
-
|
|
400
|
-
// Find matching domain group
|
|
401
|
-
const match = subdomainRouter.findDomainGroup(domain)
|
|
402
|
-
if (match) {
|
|
403
|
-
// Add domain parameters to request
|
|
404
|
-
const enhancedReq = req as EnhancedRequest & { domainParams?: Record<string, string> }
|
|
405
|
-
enhancedReq.domainParams = match.parameters
|
|
406
|
-
|
|
407
|
-
// Also add to regular params for convenience
|
|
408
|
-
Object.assign(req.params || {}, match.parameters)
|
|
409
|
-
|
|
410
|
-
// Add subdomain info
|
|
411
|
-
const subdomainInfo = DomainMatcher.extractSubdomainInfo(domain)
|
|
412
|
-
;(enhancedReq as any).subdomainInfo = subdomainInfo
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
return await next()
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* Utility functions for subdomain routing
|
|
421
|
-
*/
|
|
422
|
-
export const SubdomainUtils = {
|
|
423
|
-
/**
|
|
424
|
-
* Extract subdomain from request
|
|
425
|
-
*/
|
|
426
|
-
getSubdomain: (req: EnhancedRequest): string | null => {
|
|
427
|
-
const url = new URL(req.url)
|
|
428
|
-
const info = DomainMatcher.extractSubdomainInfo(url.hostname)
|
|
429
|
-
return info.subdomain || null
|
|
430
|
-
},
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* Get domain parameters from request
|
|
434
|
-
*/
|
|
435
|
-
getDomainParams: (req: EnhancedRequest): Record<string, string> => {
|
|
436
|
-
return (req as any).domainParams || {}
|
|
437
|
-
},
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* Check if request matches domain pattern
|
|
441
|
-
*/
|
|
442
|
-
matchesDomain: (req: EnhancedRequest, pattern: string): boolean => {
|
|
443
|
-
const url = new URL(req.url)
|
|
444
|
-
const domainPattern = DomainMatcher.parseDomainPattern(pattern)
|
|
445
|
-
return DomainMatcher.matchDomain(url.hostname, domainPattern) !== null
|
|
446
|
-
},
|
|
447
|
-
|
|
448
|
-
/**
|
|
449
|
-
* Get full subdomain info from request
|
|
450
|
-
*/
|
|
451
|
-
getSubdomainInfo: (req: EnhancedRequest): SubdomainRouteInfo | null => {
|
|
452
|
-
return (req as any).subdomainInfo || null
|
|
453
|
-
},
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
* Factory functions for common subdomain patterns
|
|
458
|
-
*/
|
|
459
|
-
export const SubdomainPatterns = {
|
|
460
|
-
/**
|
|
461
|
-
* Single subdomain pattern (e.g., api.example.com)
|
|
462
|
-
*/
|
|
463
|
-
single: (subdomain: string, domain: string): string => `${subdomain}.${domain}`,
|
|
464
|
-
|
|
465
|
-
/**
|
|
466
|
-
* Wildcard subdomain pattern (e.g., {account}.example.com)
|
|
467
|
-
*/
|
|
468
|
-
wildcard: (domain: string, paramName: string = 'subdomain'): string => `{${paramName}}.${domain}`,
|
|
469
|
-
|
|
470
|
-
/**
|
|
471
|
-
* Multi-level subdomain (e.g., {service}.{env}.example.com)
|
|
472
|
-
*/
|
|
473
|
-
multiLevel: (domain: string, ...paramNames: string[]): string => {
|
|
474
|
-
const params = paramNames.map(name => `{${name}}`).join('.')
|
|
475
|
-
return `${params}.${domain}`
|
|
476
|
-
},
|
|
477
|
-
|
|
478
|
-
/**
|
|
479
|
-
* API versioning pattern (e.g., v1.api.example.com)
|
|
480
|
-
*/
|
|
481
|
-
apiVersion: (domain: string): string => `{version}.api.${domain}`,
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* Tenant pattern (e.g., {tenant}.app.example.com)
|
|
485
|
-
*/
|
|
486
|
-
tenant: (domain: string): string => `{tenant}.app.${domain}`,
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* Environment pattern (e.g., {env}.example.com)
|
|
490
|
-
*/
|
|
491
|
-
environment: (domain: string): string => `{env}.${domain}`,
|
|
492
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import type { SessionData, SessionStore } from '../types/core'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Minimal database adapter interface for session storage.
|
|
5
|
-
* Implement this with your ORM (Kysely, Drizzle, etc.).
|
|
6
|
-
*/
|
|
7
|
-
export interface SessionDatabaseAdapter {
|
|
8
|
-
findSession(sid: string): Promise<{ payload: string, last_activity: number } | null>
|
|
9
|
-
upsertSession(sid: string, payload: string, lastActivity: number): Promise<void>
|
|
10
|
-
deleteSession(sid: string): Promise<void>
|
|
11
|
-
getAllSessions(): Promise<Array<{ id: string, payload: string, last_activity: number }>>
|
|
12
|
-
deleteExpiredSessions(maxAge: number): Promise<void>
|
|
13
|
-
countSessions(): Promise<number>
|
|
14
|
-
clearAllSessions(): Promise<void>
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Database-backed session store.
|
|
19
|
-
* Persists sessions in a database table.
|
|
20
|
-
*
|
|
21
|
-
* Expected table schema:
|
|
22
|
-
* ```sql
|
|
23
|
-
* CREATE TABLE sessions (
|
|
24
|
-
* id VARCHAR(255) PRIMARY KEY,
|
|
25
|
-
* user_id INTEGER NULL,
|
|
26
|
-
* ip_address VARCHAR(45) NULL,
|
|
27
|
-
* user_agent TEXT NULL,
|
|
28
|
-
* payload TEXT NOT NULL,
|
|
29
|
-
* last_activity INTEGER NOT NULL
|
|
30
|
-
* );
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
|
-
export class DatabaseSessionStore implements SessionStore<SessionData> {
|
|
34
|
-
private cleanupInterval: ReturnType<typeof setInterval> | null = null
|
|
35
|
-
|
|
36
|
-
constructor(
|
|
37
|
-
private adapter: SessionDatabaseAdapter,
|
|
38
|
-
private defaultTtl: number = 86400,
|
|
39
|
-
) {
|
|
40
|
-
// Cleanup expired sessions every 30 minutes
|
|
41
|
-
this.cleanupInterval = setInterval(() => {
|
|
42
|
-
const maxAge = Date.now() - this.defaultTtl * 1000
|
|
43
|
-
this.adapter.deleteExpiredSessions(maxAge)
|
|
44
|
-
}, 30 * 60 * 1000)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async get(sid: string): Promise<SessionData | null> {
|
|
48
|
-
const record = await this.adapter.findSession(sid)
|
|
49
|
-
if (!record) return null
|
|
50
|
-
|
|
51
|
-
// Check expiration
|
|
52
|
-
const maxAge = Date.now() - this.defaultTtl * 1000
|
|
53
|
-
if (record.last_activity < maxAge) {
|
|
54
|
-
await this.adapter.deleteSession(sid)
|
|
55
|
-
return null
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
return JSON.parse(record.payload) as SessionData
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
return null
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async set(sid: string, session: SessionData, _ttl?: number): Promise<void> {
|
|
67
|
-
await this.adapter.upsertSession(sid, JSON.stringify(session), Date.now())
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async destroy(sid: string): Promise<void> {
|
|
71
|
-
await this.adapter.deleteSession(sid)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async touch(sid: string, session: SessionData, _ttl?: number): Promise<void> {
|
|
75
|
-
await this.adapter.upsertSession(sid, JSON.stringify(session), Date.now())
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async all(): Promise<Record<string, SessionData>> {
|
|
79
|
-
const records = await this.adapter.getAllSessions()
|
|
80
|
-
const result: Record<string, SessionData> = {}
|
|
81
|
-
const maxAge = Date.now() - this.defaultTtl * 1000
|
|
82
|
-
|
|
83
|
-
for (const record of records) {
|
|
84
|
-
if (record.last_activity >= maxAge) {
|
|
85
|
-
try {
|
|
86
|
-
result[record.id] = JSON.parse(record.payload)
|
|
87
|
-
}
|
|
88
|
-
catch { /* skip invalid data */ }
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return result
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async length(): Promise<number> {
|
|
96
|
-
return this.adapter.countSessions()
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async clear(): Promise<void> {
|
|
100
|
-
await this.adapter.clearAllSessions()
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
dispose(): void {
|
|
104
|
-
if (this.cleanupInterval) {
|
|
105
|
-
clearInterval(this.cleanupInterval)
|
|
106
|
-
this.cleanupInterval = null
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|