@stacksjs/bun-router 0.0.12 → 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 -48
- 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,673 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hot Reload Development
|
|
3
|
-
*
|
|
4
|
-
* Hot reload for development using Bun's --hot mode with state preservation
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { watch } from 'node:fs'
|
|
8
|
-
import { join, resolve } from 'node:path'
|
|
9
|
-
|
|
10
|
-
export interface HotReloadConfig {
|
|
11
|
-
enabled?: boolean
|
|
12
|
-
watchPaths?: string[]
|
|
13
|
-
ignorePaths?: string[]
|
|
14
|
-
extensions?: string[]
|
|
15
|
-
debounceMs?: number
|
|
16
|
-
preserveState?: boolean
|
|
17
|
-
onReload?: (changedFiles: string[]) => void
|
|
18
|
-
onError?: (error: Error) => void
|
|
19
|
-
verbose?: boolean
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface HotReloadState {
|
|
23
|
-
reloadCount: number
|
|
24
|
-
lastReload: number
|
|
25
|
-
changedFiles: string[]
|
|
26
|
-
preservedState: Record<string, any>
|
|
27
|
-
watchers: Map<string, any>
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
declare global {
|
|
31
|
-
// eslint-disable-next-line vars-on-top
|
|
32
|
-
var __HOT_RELOAD_STATE__: HotReloadState | undefined
|
|
33
|
-
// eslint-disable-next-line vars-on-top
|
|
34
|
-
var __HOT_RELOAD_PRESERVE__: Record<string, any>
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Hot reload manager for development
|
|
39
|
-
*/
|
|
40
|
-
export class HotReloadManager {
|
|
41
|
-
private config: Required<HotReloadConfig>
|
|
42
|
-
private state: HotReloadState = {
|
|
43
|
-
reloadCount: 0,
|
|
44
|
-
lastReload: Date.now(),
|
|
45
|
-
changedFiles: [],
|
|
46
|
-
preservedState: {},
|
|
47
|
-
watchers: new Map(),
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
private debounceTimer?: ReturnType<typeof setTimeout>
|
|
51
|
-
private isReloading = false
|
|
52
|
-
|
|
53
|
-
constructor(config: HotReloadConfig = {}) {
|
|
54
|
-
this.config = {
|
|
55
|
-
enabled: config.enabled ?? true,
|
|
56
|
-
watchPaths: config.watchPaths ?? ['.'],
|
|
57
|
-
ignorePaths: config.ignorePaths ?? ['node_modules', '.git', 'dist', 'build'],
|
|
58
|
-
extensions: config.extensions ?? ['.ts', '.js', '.json', '.env'],
|
|
59
|
-
debounceMs: config.debounceMs ?? 100,
|
|
60
|
-
preserveState: config.preserveState ?? true,
|
|
61
|
-
onReload: config.onReload ?? (() => {}),
|
|
62
|
-
onError: config.onError ?? (error => console.error('Hot reload error:', error)),
|
|
63
|
-
verbose: config.verbose ?? false,
|
|
64
|
-
...config,
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
this.initializeState()
|
|
68
|
-
this.setupWatchers()
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Initialize or restore hot reload state
|
|
73
|
-
*/
|
|
74
|
-
private initializeState(): void {
|
|
75
|
-
if (globalThis.__HOT_RELOAD_STATE__) {
|
|
76
|
-
// Restore existing state
|
|
77
|
-
this.state = globalThis.__HOT_RELOAD_STATE__
|
|
78
|
-
|
|
79
|
-
// Ensure numeric values are valid
|
|
80
|
-
if (typeof this.state.reloadCount !== 'number' || Number.isNaN(this.state.reloadCount)) {
|
|
81
|
-
this.state.reloadCount = 0
|
|
82
|
-
}
|
|
83
|
-
if (typeof this.state.lastReload !== 'number' || Number.isNaN(this.state.lastReload)) {
|
|
84
|
-
this.state.lastReload = Date.now()
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
this.state.reloadCount++
|
|
88
|
-
this.state.lastReload = Date.now()
|
|
89
|
-
|
|
90
|
-
// Ensure all required properties exist
|
|
91
|
-
if (!this.state.changedFiles) {
|
|
92
|
-
this.state.changedFiles = []
|
|
93
|
-
}
|
|
94
|
-
if (!this.state.watchers) {
|
|
95
|
-
this.state.watchers = new Map()
|
|
96
|
-
}
|
|
97
|
-
if (!this.state.preservedState) {
|
|
98
|
-
this.state.preservedState = {}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (this.config.verbose) {
|
|
102
|
-
console.log(`🔥 Hot reload #${this.state.reloadCount}`)
|
|
103
|
-
if (this.state.changedFiles.length > 0) {
|
|
104
|
-
console.log('📝 Changed files:', this.state.changedFiles)
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
// Initialize new state
|
|
110
|
-
this.state = {
|
|
111
|
-
reloadCount: 0,
|
|
112
|
-
lastReload: Date.now(),
|
|
113
|
-
changedFiles: [],
|
|
114
|
-
preservedState: globalThis.__HOT_RELOAD_PRESERVE__ || {},
|
|
115
|
-
watchers: new Map(),
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
globalThis.__HOT_RELOAD_STATE__ = this.state
|
|
119
|
-
globalThis.__HOT_RELOAD_PRESERVE__ = this.state.preservedState
|
|
120
|
-
|
|
121
|
-
if (this.config.verbose) {
|
|
122
|
-
console.log('🔥 Hot reload initialized')
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Setup file watchers
|
|
129
|
-
*/
|
|
130
|
-
private setupWatchers(): void {
|
|
131
|
-
if (!this.config.enabled)
|
|
132
|
-
return
|
|
133
|
-
|
|
134
|
-
// Ensure state is initialized
|
|
135
|
-
if (!this.state || !this.state.watchers) {
|
|
136
|
-
this.initializeState()
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Clear existing watchers
|
|
140
|
-
this.state.watchers.forEach((watcher) => {
|
|
141
|
-
try {
|
|
142
|
-
watcher.close()
|
|
143
|
-
}
|
|
144
|
-
catch {
|
|
145
|
-
// Ignore errors when closing watchers
|
|
146
|
-
}
|
|
147
|
-
})
|
|
148
|
-
this.state.watchers.clear()
|
|
149
|
-
|
|
150
|
-
// Setup new watchers
|
|
151
|
-
for (const watchPath of this.config.watchPaths) {
|
|
152
|
-
try {
|
|
153
|
-
const resolvedPath = resolve(watchPath)
|
|
154
|
-
const watcher = watch(resolvedPath, { recursive: true }, (eventType, filename) => {
|
|
155
|
-
if (filename) {
|
|
156
|
-
this.handleFileChange(eventType, join(resolvedPath, filename))
|
|
157
|
-
}
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
this.state.watchers.set(watchPath, watcher)
|
|
161
|
-
|
|
162
|
-
if (this.config.verbose) {
|
|
163
|
-
console.log(`👀 Watching: ${resolvedPath}`)
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
catch (err) {
|
|
167
|
-
this.config.onError(err as Error)
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Handle file change event
|
|
174
|
-
*/
|
|
175
|
-
private handleFileChange(eventType: string, filePath: string): void {
|
|
176
|
-
if (this.isReloading)
|
|
177
|
-
return
|
|
178
|
-
|
|
179
|
-
// Check if file should be ignored
|
|
180
|
-
if (this.shouldIgnoreFile(filePath))
|
|
181
|
-
return
|
|
182
|
-
|
|
183
|
-
// Check if file extension is watched
|
|
184
|
-
if (!this.shouldWatchFile(filePath))
|
|
185
|
-
return
|
|
186
|
-
|
|
187
|
-
if (this.config.verbose) {
|
|
188
|
-
console.log(`📁 File ${eventType}: ${filePath}`)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Add to changed files
|
|
192
|
-
if (!this.state.changedFiles.includes(filePath)) {
|
|
193
|
-
this.state.changedFiles.push(filePath)
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Debounce reload
|
|
197
|
-
if (this.debounceTimer) {
|
|
198
|
-
clearTimeout(this.debounceTimer)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
this.debounceTimer = setTimeout(() => {
|
|
202
|
-
this.triggerReload()
|
|
203
|
-
}, this.config.debounceMs)
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Check if file should be ignored
|
|
208
|
-
*/
|
|
209
|
-
private shouldIgnoreFile(filePath: string): boolean {
|
|
210
|
-
return this.config.ignorePaths.some(ignorePath =>
|
|
211
|
-
filePath.includes(ignorePath),
|
|
212
|
-
)
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Check if file should be watched
|
|
217
|
-
*/
|
|
218
|
-
private shouldWatchFile(filePath: string): boolean {
|
|
219
|
-
if (this.config.extensions.length === 0)
|
|
220
|
-
return true
|
|
221
|
-
|
|
222
|
-
return this.config.extensions.some(ext =>
|
|
223
|
-
filePath.endsWith(ext),
|
|
224
|
-
)
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Trigger hot reload
|
|
229
|
-
*/
|
|
230
|
-
private triggerReload(): void {
|
|
231
|
-
if (this.isReloading)
|
|
232
|
-
return
|
|
233
|
-
|
|
234
|
-
this.isReloading = true
|
|
235
|
-
|
|
236
|
-
try {
|
|
237
|
-
// Call reload callback
|
|
238
|
-
this.config.onReload(this.state.changedFiles)
|
|
239
|
-
|
|
240
|
-
// Update state
|
|
241
|
-
this.state.lastReload = Date.now()
|
|
242
|
-
|
|
243
|
-
if (this.config.verbose) {
|
|
244
|
-
console.log(`🔄 Hot reload triggered for ${this.state.changedFiles.length} files`)
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Clear changed files
|
|
248
|
-
this.state.changedFiles = []
|
|
249
|
-
}
|
|
250
|
-
catch (error) {
|
|
251
|
-
this.config.onError(error as Error)
|
|
252
|
-
}
|
|
253
|
-
finally {
|
|
254
|
-
this.isReloading = false
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Preserve state across reloads
|
|
260
|
-
*/
|
|
261
|
-
preserveState<T>(key: string, value: T): void {
|
|
262
|
-
if (this.config.preserveState) {
|
|
263
|
-
this.state.preservedState[key] = value
|
|
264
|
-
globalThis.__HOT_RELOAD_PRESERVE__[key] = value
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Restore preserved state
|
|
270
|
-
*/
|
|
271
|
-
restoreState<T>(key: string, defaultValue?: T): T | undefined {
|
|
272
|
-
if (this.config.preserveState && key in this.state.preservedState) {
|
|
273
|
-
return this.state.preservedState[key] as T
|
|
274
|
-
}
|
|
275
|
-
return defaultValue
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* Clear preserved state
|
|
280
|
-
*/
|
|
281
|
-
clearState(key?: string): void {
|
|
282
|
-
if (key) {
|
|
283
|
-
delete this.state.preservedState[key]
|
|
284
|
-
delete globalThis.__HOT_RELOAD_PRESERVE__[key]
|
|
285
|
-
}
|
|
286
|
-
else {
|
|
287
|
-
this.state.preservedState = {}
|
|
288
|
-
globalThis.__HOT_RELOAD_PRESERVE__ = {}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Get hot reload statistics
|
|
294
|
-
*/
|
|
295
|
-
getStats(): {
|
|
296
|
-
reloadCount: number
|
|
297
|
-
lastReload: number
|
|
298
|
-
uptime: number
|
|
299
|
-
watchedPaths: string[]
|
|
300
|
-
preservedKeys: string[]
|
|
301
|
-
} {
|
|
302
|
-
return {
|
|
303
|
-
reloadCount: this.state.reloadCount,
|
|
304
|
-
lastReload: this.state.lastReload,
|
|
305
|
-
uptime: Date.now() - this.state.lastReload,
|
|
306
|
-
watchedPaths: Array.from(this.state.watchers.keys()),
|
|
307
|
-
preservedKeys: Object.keys(this.state.preservedState),
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Stop hot reload
|
|
313
|
-
*/
|
|
314
|
-
stop(): void {
|
|
315
|
-
// Clear debounce timer
|
|
316
|
-
if (this.debounceTimer) {
|
|
317
|
-
clearTimeout(this.debounceTimer)
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// Close all watchers
|
|
321
|
-
this.state.watchers.forEach((watcher) => {
|
|
322
|
-
try {
|
|
323
|
-
watcher.close()
|
|
324
|
-
}
|
|
325
|
-
catch {
|
|
326
|
-
// Ignore errors when closing watchers
|
|
327
|
-
}
|
|
328
|
-
})
|
|
329
|
-
this.state.watchers.clear()
|
|
330
|
-
|
|
331
|
-
if (this.config.verbose) {
|
|
332
|
-
console.log('🛑 Hot reload stopped')
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* Hot reload middleware for preserving server state
|
|
339
|
-
*/
|
|
340
|
-
export function createHotReloadMiddleware(hotReload: HotReloadManager) {
|
|
341
|
-
return async (request: Request, next: () => Promise<Response>): Promise<Response> => {
|
|
342
|
-
// Add hot reload info to response headers in development
|
|
343
|
-
const response = await next()
|
|
344
|
-
|
|
345
|
-
if (hotReload.getStats().reloadCount > 0) {
|
|
346
|
-
const newHeaders = new Headers(response.headers)
|
|
347
|
-
newHeaders.set('X-Hot-Reload-Count', hotReload.getStats().reloadCount.toString())
|
|
348
|
-
newHeaders.set('X-Hot-Reload-Last', new Date(hotReload.getStats().lastReload).toISOString())
|
|
349
|
-
|
|
350
|
-
return new Response(response.body, {
|
|
351
|
-
status: response.status,
|
|
352
|
-
statusText: response.statusText,
|
|
353
|
-
headers: newHeaders,
|
|
354
|
-
})
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
return response
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* Hot reload utilities
|
|
363
|
-
*/
|
|
364
|
-
export const HotReloadUtils = {
|
|
365
|
-
/**
|
|
366
|
-
* Check if running in hot reload mode
|
|
367
|
-
*/
|
|
368
|
-
isHotReloadEnabled: (): boolean => {
|
|
369
|
-
return !!(globalThis.__HOT_RELOAD_STATE__
|
|
370
|
-
&& typeof globalThis.__HOT_RELOAD_STATE__.reloadCount === 'number'
|
|
371
|
-
&& !Number.isNaN(globalThis.__HOT_RELOAD_STATE__.reloadCount))
|
|
372
|
-
},
|
|
373
|
-
|
|
374
|
-
/**
|
|
375
|
-
* Get current reload count
|
|
376
|
-
*/
|
|
377
|
-
getReloadCount: (): number => {
|
|
378
|
-
return globalThis.__HOT_RELOAD_STATE__?.reloadCount || 0
|
|
379
|
-
},
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* Create hot-reloadable module cache
|
|
383
|
-
*/
|
|
384
|
-
createModuleCache: <T>() => {
|
|
385
|
-
const cache = new Map<string, T>()
|
|
386
|
-
|
|
387
|
-
return {
|
|
388
|
-
get: (key: string): T | undefined => cache.get(key),
|
|
389
|
-
set: (key: string, value: T): void => {
|
|
390
|
-
cache.set(key, value)
|
|
391
|
-
},
|
|
392
|
-
clear: (): void => cache.clear(),
|
|
393
|
-
delete: (key: string): boolean => cache.delete(key),
|
|
394
|
-
has: (key: string): boolean => cache.has(key),
|
|
395
|
-
size: (): number => cache.size,
|
|
396
|
-
}
|
|
397
|
-
},
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* Create hot-reloadable configuration
|
|
401
|
-
*/
|
|
402
|
-
createHotConfig: <T>(initialConfig: T, configPath?: string): {
|
|
403
|
-
get: () => T
|
|
404
|
-
reload: () => Promise<T>
|
|
405
|
-
onChange: (callback: (config: T) => void) => void
|
|
406
|
-
} => {
|
|
407
|
-
let currentConfig = initialConfig
|
|
408
|
-
const changeCallbacks: Array<(config: T) => void> = []
|
|
409
|
-
|
|
410
|
-
const reloadConfig = async (): Promise<T> => {
|
|
411
|
-
if (configPath) {
|
|
412
|
-
try {
|
|
413
|
-
// Clear require cache for config file
|
|
414
|
-
// Note: Dynamic config reloading would require proper import handling
|
|
415
|
-
const newConfig = {}
|
|
416
|
-
currentConfig = { ...currentConfig, ...newConfig }
|
|
417
|
-
}
|
|
418
|
-
catch (err) {
|
|
419
|
-
console.error('Failed to reload config:', err)
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// Always notify change callbacks on reload
|
|
424
|
-
changeCallbacks.forEach(callback => callback(currentConfig))
|
|
425
|
-
return currentConfig
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
return {
|
|
429
|
-
get: () => currentConfig,
|
|
430
|
-
reload: reloadConfig,
|
|
431
|
-
onChange: (callback: (config: T) => void) => {
|
|
432
|
-
changeCallbacks.push(callback)
|
|
433
|
-
},
|
|
434
|
-
}
|
|
435
|
-
},
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
/**
|
|
439
|
-
* Hot reload helpers for common patterns
|
|
440
|
-
*/
|
|
441
|
-
export const HotReloadHelpers = {
|
|
442
|
-
/**
|
|
443
|
-
* Create hot-reloadable route handlers
|
|
444
|
-
*/
|
|
445
|
-
createHotHandler: (handlerPath: string) => {
|
|
446
|
-
return async (request: Request): Promise<Response> => {
|
|
447
|
-
try {
|
|
448
|
-
// Clear module cache in hot reload mode
|
|
449
|
-
delete require.cache[require.resolve(handlerPath)]
|
|
450
|
-
|
|
451
|
-
// Load the handler dynamically
|
|
452
|
-
const handlerModule = await import(handlerPath)
|
|
453
|
-
const handler = handlerModule.default || handlerModule
|
|
454
|
-
|
|
455
|
-
if (typeof handler === 'function') {
|
|
456
|
-
return await handler(request)
|
|
457
|
-
}
|
|
458
|
-
else {
|
|
459
|
-
return new Response('Handler not available', { status: 501 })
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
catch (error) {
|
|
463
|
-
console.error('Hot handler error:', error)
|
|
464
|
-
return new Response('Handler Error', { status: 500 })
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
},
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* Create hot-reloadable middleware
|
|
471
|
-
*/
|
|
472
|
-
createHotMiddleware: (middlewarePath: string) => {
|
|
473
|
-
return async (request: Request, next: () => Promise<Response>): Promise<Response> => {
|
|
474
|
-
try {
|
|
475
|
-
// Clear module cache in hot reload mode
|
|
476
|
-
delete require.cache[require.resolve(middlewarePath)]
|
|
477
|
-
|
|
478
|
-
// Load the middleware dynamically
|
|
479
|
-
const middlewareModule = await import(middlewarePath)
|
|
480
|
-
const middleware = middlewareModule.default || middlewareModule
|
|
481
|
-
|
|
482
|
-
if (typeof middleware === 'function') {
|
|
483
|
-
return await middleware(request, next)
|
|
484
|
-
}
|
|
485
|
-
else {
|
|
486
|
-
// Fallback: add hot reload header and continue
|
|
487
|
-
const response = await next()
|
|
488
|
-
response.headers.set('X-Hot-Middleware', 'true')
|
|
489
|
-
return response
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
catch (error) {
|
|
493
|
-
console.error('Hot middleware error:', error)
|
|
494
|
-
const response = await next()
|
|
495
|
-
response.headers.set('X-Hot-Middleware', 'true')
|
|
496
|
-
return response
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
},
|
|
500
|
-
|
|
501
|
-
/**
|
|
502
|
-
* Create development server with hot reload
|
|
503
|
-
*/
|
|
504
|
-
createDevelopmentServer: (config: {
|
|
505
|
-
port?: number
|
|
506
|
-
hostname?: string
|
|
507
|
-
hotReload?: HotReloadConfig
|
|
508
|
-
onReload?: () => void
|
|
509
|
-
} = {}) => {
|
|
510
|
-
const hotReload = new HotReloadManager({
|
|
511
|
-
...config.hotReload,
|
|
512
|
-
onReload: (changedFiles) => {
|
|
513
|
-
console.log(`🔥 Hot reload: ${changedFiles.length} files changed`)
|
|
514
|
-
config.onReload?.()
|
|
515
|
-
config.hotReload?.onReload?.(changedFiles)
|
|
516
|
-
},
|
|
517
|
-
})
|
|
518
|
-
|
|
519
|
-
// Preserve server instance across reloads
|
|
520
|
-
const serverKey = 'development_server'
|
|
521
|
-
let server = hotReload.restoreState<any>(serverKey)
|
|
522
|
-
|
|
523
|
-
if (!server) {
|
|
524
|
-
const port = config.port ?? 3000
|
|
525
|
-
server = Bun.serve({
|
|
526
|
-
port: port === 0 ? undefined : port, // Use random port if 0
|
|
527
|
-
hostname: config.hostname || 'localhost',
|
|
528
|
-
|
|
529
|
-
fetch: async (request) => {
|
|
530
|
-
// Add hot reload middleware
|
|
531
|
-
const hotReloadMiddleware = createHotReloadMiddleware(hotReload)
|
|
532
|
-
|
|
533
|
-
return await hotReloadMiddleware(request, async () => {
|
|
534
|
-
return new Response('Hot Reload Development Server', {
|
|
535
|
-
headers: { 'Content-Type': 'text/plain' },
|
|
536
|
-
})
|
|
537
|
-
})
|
|
538
|
-
},
|
|
539
|
-
})
|
|
540
|
-
|
|
541
|
-
hotReload.preserveState(serverKey, server)
|
|
542
|
-
console.log(`🚀 Development server started on http://${config.hostname || 'localhost'}:${config.port || 3000}`)
|
|
543
|
-
}
|
|
544
|
-
else {
|
|
545
|
-
console.log(`🔄 Development server reloaded`)
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
return {
|
|
549
|
-
server: server as ReturnType<typeof Bun.serve>,
|
|
550
|
-
hotReload: hotReload as HotReloadManager,
|
|
551
|
-
stop: (): void => {
|
|
552
|
-
hotReload.stop()
|
|
553
|
-
server.stop()
|
|
554
|
-
},
|
|
555
|
-
}
|
|
556
|
-
},
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
/**
|
|
560
|
-
* Hot reload decorators for classes and methods
|
|
561
|
-
*/
|
|
562
|
-
export const HotReloadDecorators = {
|
|
563
|
-
/**
|
|
564
|
-
* Class decorator for hot-reloadable classes
|
|
565
|
-
*/
|
|
566
|
-
hotReloadable: <T extends new (...args: any[]) => any>(constructor: T): T => {
|
|
567
|
-
const className = constructor.name
|
|
568
|
-
|
|
569
|
-
return class extends constructor {
|
|
570
|
-
constructor(...args: any[]) {
|
|
571
|
-
super(...args)
|
|
572
|
-
|
|
573
|
-
// Preserve instance state if hot reloading
|
|
574
|
-
if (HotReloadUtils.isHotReloadEnabled()) {
|
|
575
|
-
const stateKey = `class_${className}_${Date.now()}`
|
|
576
|
-
const preserved = globalThis.__HOT_RELOAD_PRESERVE__?.[stateKey]
|
|
577
|
-
|
|
578
|
-
if (preserved) {
|
|
579
|
-
Object.assign(this, preserved)
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
// Save state on next tick
|
|
583
|
-
setTimeout(() => {
|
|
584
|
-
if (globalThis.__HOT_RELOAD_PRESERVE__) {
|
|
585
|
-
globalThis.__HOT_RELOAD_PRESERVE__[stateKey] = { ...this }
|
|
586
|
-
}
|
|
587
|
-
}, 0)
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
} as T
|
|
591
|
-
},
|
|
592
|
-
|
|
593
|
-
/**
|
|
594
|
-
* Method decorator for hot-reloadable methods
|
|
595
|
-
*/
|
|
596
|
-
hotMethod: (target: any, propertyKey: string, descriptor: PropertyDescriptor): void => {
|
|
597
|
-
const originalMethod = descriptor.value
|
|
598
|
-
|
|
599
|
-
descriptor.value = function (...args: any[]) {
|
|
600
|
-
try {
|
|
601
|
-
return originalMethod.apply(this, args)
|
|
602
|
-
}
|
|
603
|
-
catch (err) {
|
|
604
|
-
console.error(`Hot method error in ${propertyKey}:`, err)
|
|
605
|
-
throw err
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
},
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
/**
|
|
612
|
-
* Global hot reload instance
|
|
613
|
-
*/
|
|
614
|
-
let globalHotReload: HotReloadManager | null = null
|
|
615
|
-
|
|
616
|
-
/**
|
|
617
|
-
* Initialize global hot reload
|
|
618
|
-
*/
|
|
619
|
-
export function initializeHotReload(config?: HotReloadConfig): HotReloadManager {
|
|
620
|
-
if (!globalHotReload) {
|
|
621
|
-
globalHotReload = new HotReloadManager(config)
|
|
622
|
-
}
|
|
623
|
-
return globalHotReload
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
/**
|
|
627
|
-
* Get global hot reload instance
|
|
628
|
-
*/
|
|
629
|
-
export function getHotReload(): HotReloadManager | null {
|
|
630
|
-
return globalHotReload
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
/**
|
|
634
|
-
* Hot reload factory functions
|
|
635
|
-
*/
|
|
636
|
-
export const HotReloadFactory = {
|
|
637
|
-
/**
|
|
638
|
-
* Create development hot reload
|
|
639
|
-
*/
|
|
640
|
-
createDevelopment: (): HotReloadManager => {
|
|
641
|
-
return new HotReloadManager({
|
|
642
|
-
enabled: true,
|
|
643
|
-
watchPaths: ['.'],
|
|
644
|
-
ignorePaths: ['node_modules', '.git', 'dist', 'build', '.next', '.nuxt'],
|
|
645
|
-
extensions: ['.ts', '.js', '.tsx', '.jsx', '.json', '.env'],
|
|
646
|
-
debounceMs: 100,
|
|
647
|
-
preserveState: true,
|
|
648
|
-
verbose: true,
|
|
649
|
-
})
|
|
650
|
-
},
|
|
651
|
-
|
|
652
|
-
/**
|
|
653
|
-
* Create production hot reload (disabled)
|
|
654
|
-
*/
|
|
655
|
-
createProduction: (): HotReloadManager => {
|
|
656
|
-
return new HotReloadManager({
|
|
657
|
-
enabled: false,
|
|
658
|
-
preserveState: false,
|
|
659
|
-
verbose: false,
|
|
660
|
-
})
|
|
661
|
-
},
|
|
662
|
-
|
|
663
|
-
/**
|
|
664
|
-
* Create testing hot reload
|
|
665
|
-
*/
|
|
666
|
-
createTesting: (): HotReloadManager => {
|
|
667
|
-
return new HotReloadManager({
|
|
668
|
-
enabled: false,
|
|
669
|
-
preserveState: true,
|
|
670
|
-
verbose: false,
|
|
671
|
-
})
|
|
672
|
-
},
|
|
673
|
-
}
|