@buenojs/bueno 0.8.0
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/.env.example +109 -0
- package/.github/workflows/ci.yml +31 -0
- package/LICENSE +21 -0
- package/README.md +892 -0
- package/architecture.md +652 -0
- package/bun.lock +70 -0
- package/dist/cli/index.js +3233 -0
- package/dist/index.js +9014 -0
- package/package.json +77 -0
- package/src/cache/index.ts +795 -0
- package/src/cli/ARCHITECTURE.md +837 -0
- package/src/cli/bin.ts +10 -0
- package/src/cli/commands/build.ts +425 -0
- package/src/cli/commands/dev.ts +248 -0
- package/src/cli/commands/generate.ts +541 -0
- package/src/cli/commands/help.ts +55 -0
- package/src/cli/commands/index.ts +112 -0
- package/src/cli/commands/migration.ts +355 -0
- package/src/cli/commands/new.ts +804 -0
- package/src/cli/commands/start.ts +208 -0
- package/src/cli/core/args.ts +283 -0
- package/src/cli/core/console.ts +349 -0
- package/src/cli/core/index.ts +60 -0
- package/src/cli/core/prompt.ts +424 -0
- package/src/cli/core/spinner.ts +265 -0
- package/src/cli/index.ts +135 -0
- package/src/cli/templates/deploy.ts +295 -0
- package/src/cli/templates/docker.ts +307 -0
- package/src/cli/templates/index.ts +24 -0
- package/src/cli/utils/fs.ts +428 -0
- package/src/cli/utils/index.ts +8 -0
- package/src/cli/utils/strings.ts +197 -0
- package/src/config/env.ts +408 -0
- package/src/config/index.ts +506 -0
- package/src/config/loader.ts +329 -0
- package/src/config/merge.ts +285 -0
- package/src/config/types.ts +320 -0
- package/src/config/validation.ts +441 -0
- package/src/container/forward-ref.ts +143 -0
- package/src/container/index.ts +386 -0
- package/src/context/index.ts +360 -0
- package/src/database/index.ts +1142 -0
- package/src/database/migrations/index.ts +371 -0
- package/src/database/schema/index.ts +619 -0
- package/src/frontend/api-routes.ts +640 -0
- package/src/frontend/bundler.ts +643 -0
- package/src/frontend/console-client.ts +419 -0
- package/src/frontend/console-stream.ts +587 -0
- package/src/frontend/dev-server.ts +846 -0
- package/src/frontend/file-router.ts +611 -0
- package/src/frontend/frameworks/index.ts +106 -0
- package/src/frontend/frameworks/react.ts +85 -0
- package/src/frontend/frameworks/solid.ts +104 -0
- package/src/frontend/frameworks/svelte.ts +110 -0
- package/src/frontend/frameworks/vue.ts +92 -0
- package/src/frontend/hmr-client.ts +663 -0
- package/src/frontend/hmr.ts +728 -0
- package/src/frontend/index.ts +342 -0
- package/src/frontend/islands.ts +552 -0
- package/src/frontend/isr.ts +555 -0
- package/src/frontend/layout.ts +475 -0
- package/src/frontend/ssr/react.ts +446 -0
- package/src/frontend/ssr/solid.ts +523 -0
- package/src/frontend/ssr/svelte.ts +546 -0
- package/src/frontend/ssr/vue.ts +504 -0
- package/src/frontend/ssr.ts +699 -0
- package/src/frontend/types.ts +2274 -0
- package/src/health/index.ts +604 -0
- package/src/index.ts +410 -0
- package/src/lock/index.ts +587 -0
- package/src/logger/index.ts +444 -0
- package/src/logger/transports/index.ts +969 -0
- package/src/metrics/index.ts +494 -0
- package/src/middleware/built-in.ts +360 -0
- package/src/middleware/index.ts +94 -0
- package/src/modules/filters.ts +458 -0
- package/src/modules/guards.ts +405 -0
- package/src/modules/index.ts +1256 -0
- package/src/modules/interceptors.ts +574 -0
- package/src/modules/lazy.ts +418 -0
- package/src/modules/lifecycle.ts +478 -0
- package/src/modules/metadata.ts +90 -0
- package/src/modules/pipes.ts +626 -0
- package/src/router/index.ts +339 -0
- package/src/router/linear.ts +371 -0
- package/src/router/regex.ts +292 -0
- package/src/router/tree.ts +562 -0
- package/src/rpc/index.ts +1263 -0
- package/src/security/index.ts +436 -0
- package/src/ssg/index.ts +631 -0
- package/src/storage/index.ts +456 -0
- package/src/telemetry/index.ts +1097 -0
- package/src/testing/index.ts +1586 -0
- package/src/types/index.ts +236 -0
- package/src/types/optional-deps.d.ts +219 -0
- package/src/validation/index.ts +276 -0
- package/src/websocket/index.ts +1004 -0
- package/tests/integration/cli.test.ts +1016 -0
- package/tests/integration/fullstack.test.ts +234 -0
- package/tests/unit/cache.test.ts +174 -0
- package/tests/unit/cli-commands.test.ts +892 -0
- package/tests/unit/cli.test.ts +1258 -0
- package/tests/unit/container.test.ts +279 -0
- package/tests/unit/context.test.ts +221 -0
- package/tests/unit/database.test.ts +183 -0
- package/tests/unit/linear-router.test.ts +280 -0
- package/tests/unit/lock.test.ts +336 -0
- package/tests/unit/middleware.test.ts +184 -0
- package/tests/unit/modules.test.ts +142 -0
- package/tests/unit/pubsub.test.ts +257 -0
- package/tests/unit/regex-router.test.ts +265 -0
- package/tests/unit/router.test.ts +373 -0
- package/tests/unit/rpc.test.ts +1248 -0
- package/tests/unit/security.test.ts +174 -0
- package/tests/unit/telemetry.test.ts +371 -0
- package/tests/unit/test-cache.test.ts +110 -0
- package/tests/unit/test-database.test.ts +282 -0
- package/tests/unit/tree-router.test.ts +325 -0
- package/tests/unit/validation.test.ts +794 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lifecycle Hooks System
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive lifecycle management for the Bueno framework module system.
|
|
5
|
+
* Provides hooks for module initialization, application bootstrap, and shutdown.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Context } from "../context";
|
|
9
|
+
|
|
10
|
+
// ============= Application Lifecycle Hooks =============
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Hook called when a module is initialized.
|
|
14
|
+
* Called after the module's providers are registered.
|
|
15
|
+
*/
|
|
16
|
+
export interface OnModuleInit {
|
|
17
|
+
onModuleInit(): void | Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Hook called when the application has fully bootstrapped.
|
|
22
|
+
* Called after all controllers are registered.
|
|
23
|
+
*/
|
|
24
|
+
export interface OnApplicationBootstrap {
|
|
25
|
+
onApplicationBootstrap(): void | Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Hook called when a module is being destroyed.
|
|
30
|
+
* Called during the shutdown process.
|
|
31
|
+
*/
|
|
32
|
+
export interface OnModuleDestroy {
|
|
33
|
+
onModuleDestroy(): void | Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Hook called before the application shuts down.
|
|
38
|
+
* Called when a shutdown signal is received (SIGTERM, SIGINT).
|
|
39
|
+
*/
|
|
40
|
+
export interface BeforeApplicationShutdown {
|
|
41
|
+
beforeApplicationShutdown(signal?: string): void | Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Hook called when the application is shutting down.
|
|
46
|
+
* Called at the end of the shutdown process.
|
|
47
|
+
*/
|
|
48
|
+
export interface OnApplicationShutdown {
|
|
49
|
+
onApplicationShutdown(signal?: string): void | Promise<void>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ============= Request Lifecycle Hooks =============
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Hook called before a request is handled.
|
|
56
|
+
*/
|
|
57
|
+
export interface OnBeforeRequest {
|
|
58
|
+
onBeforeRequest(context: Context): void | Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Hook called after a request is handled.
|
|
63
|
+
*/
|
|
64
|
+
export interface OnAfterRequest {
|
|
65
|
+
onAfterRequest(context: Context, response: Response): void | Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Hook called when a request throws an error.
|
|
70
|
+
*/
|
|
71
|
+
export interface OnRequestError {
|
|
72
|
+
onRequestError(context: Context, error: Error): void | Promise<void>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ============= Type Guards =============
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Check if an instance implements OnModuleInit
|
|
79
|
+
*/
|
|
80
|
+
export function isOnModuleInit(instance: unknown): instance is OnModuleInit {
|
|
81
|
+
return (
|
|
82
|
+
typeof instance === "object" &&
|
|
83
|
+
instance !== null &&
|
|
84
|
+
"onModuleInit" in instance &&
|
|
85
|
+
typeof (instance as OnModuleInit).onModuleInit === "function"
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Check if an instance implements OnApplicationBootstrap
|
|
91
|
+
*/
|
|
92
|
+
export function isOnApplicationBootstrap(
|
|
93
|
+
instance: unknown,
|
|
94
|
+
): instance is OnApplicationBootstrap {
|
|
95
|
+
return (
|
|
96
|
+
typeof instance === "object" &&
|
|
97
|
+
instance !== null &&
|
|
98
|
+
"onApplicationBootstrap" in instance &&
|
|
99
|
+
typeof (instance as OnApplicationBootstrap).onApplicationBootstrap ===
|
|
100
|
+
"function"
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Check if an instance implements OnModuleDestroy
|
|
106
|
+
*/
|
|
107
|
+
export function isOnModuleDestroy(instance: unknown): instance is OnModuleDestroy {
|
|
108
|
+
return (
|
|
109
|
+
typeof instance === "object" &&
|
|
110
|
+
instance !== null &&
|
|
111
|
+
"onModuleDestroy" in instance &&
|
|
112
|
+
typeof (instance as OnModuleDestroy).onModuleDestroy === "function"
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Check if an instance implements BeforeApplicationShutdown
|
|
118
|
+
*/
|
|
119
|
+
export function isBeforeApplicationShutdown(
|
|
120
|
+
instance: unknown,
|
|
121
|
+
): instance is BeforeApplicationShutdown {
|
|
122
|
+
return (
|
|
123
|
+
typeof instance === "object" &&
|
|
124
|
+
instance !== null &&
|
|
125
|
+
"beforeApplicationShutdown" in instance &&
|
|
126
|
+
typeof (instance as BeforeApplicationShutdown)
|
|
127
|
+
.beforeApplicationShutdown === "function"
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Check if an instance implements OnApplicationShutdown
|
|
133
|
+
*/
|
|
134
|
+
export function isOnApplicationShutdown(
|
|
135
|
+
instance: unknown,
|
|
136
|
+
): instance is OnApplicationShutdown {
|
|
137
|
+
return (
|
|
138
|
+
typeof instance === "object" &&
|
|
139
|
+
instance !== null &&
|
|
140
|
+
"onApplicationShutdown" in instance &&
|
|
141
|
+
typeof (instance as OnApplicationShutdown).onApplicationShutdown ===
|
|
142
|
+
"function"
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Check if an instance implements OnBeforeRequest
|
|
148
|
+
*/
|
|
149
|
+
export function isOnBeforeRequest(instance: unknown): instance is OnBeforeRequest {
|
|
150
|
+
return (
|
|
151
|
+
typeof instance === "object" &&
|
|
152
|
+
instance !== null &&
|
|
153
|
+
"onBeforeRequest" in instance &&
|
|
154
|
+
typeof (instance as OnBeforeRequest).onBeforeRequest === "function"
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Check if an instance implements OnAfterRequest
|
|
160
|
+
*/
|
|
161
|
+
export function isOnAfterRequest(instance: unknown): instance is OnAfterRequest {
|
|
162
|
+
return (
|
|
163
|
+
typeof instance === "object" &&
|
|
164
|
+
instance !== null &&
|
|
165
|
+
"onAfterRequest" in instance &&
|
|
166
|
+
typeof (instance as OnAfterRequest).onAfterRequest === "function"
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Check if an instance implements OnRequestError
|
|
172
|
+
*/
|
|
173
|
+
export function isOnRequestError(instance: unknown): instance is OnRequestError {
|
|
174
|
+
return (
|
|
175
|
+
typeof instance === "object" &&
|
|
176
|
+
instance !== null &&
|
|
177
|
+
"onRequestError" in instance &&
|
|
178
|
+
typeof (instance as OnRequestError).onRequestError === "function"
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ============= Lifecycle Hook Manager =============
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Manager for lifecycle hooks.
|
|
186
|
+
* Handles registration and execution of lifecycle hooks in the correct order.
|
|
187
|
+
*/
|
|
188
|
+
export class LifecycleHookManager {
|
|
189
|
+
private instancesWithModuleInit: OnModuleInit[] = [];
|
|
190
|
+
private instancesWithBootstrap: OnApplicationBootstrap[] = [];
|
|
191
|
+
private instancesWithModuleDestroy: OnModuleDestroy[] = [];
|
|
192
|
+
private instancesWithBeforeShutdown: BeforeApplicationShutdown[] = [];
|
|
193
|
+
private instancesWithShutdown: OnApplicationShutdown[] = [];
|
|
194
|
+
private instancesWithBeforeRequest: OnBeforeRequest[] = [];
|
|
195
|
+
private instancesWithAfterRequest: OnAfterRequest[] = [];
|
|
196
|
+
private instancesWithRequestError: OnRequestError[] = [];
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Register an instance with lifecycle hooks.
|
|
200
|
+
* The instance will be checked for all lifecycle hook interfaces.
|
|
201
|
+
*/
|
|
202
|
+
registerInstance(instance: unknown): void {
|
|
203
|
+
if (isOnModuleInit(instance)) {
|
|
204
|
+
this.instancesWithModuleInit.push(instance);
|
|
205
|
+
}
|
|
206
|
+
if (isOnApplicationBootstrap(instance)) {
|
|
207
|
+
this.instancesWithBootstrap.push(instance);
|
|
208
|
+
}
|
|
209
|
+
if (isOnModuleDestroy(instance)) {
|
|
210
|
+
this.instancesWithModuleDestroy.push(instance);
|
|
211
|
+
}
|
|
212
|
+
if (isBeforeApplicationShutdown(instance)) {
|
|
213
|
+
this.instancesWithBeforeShutdown.push(instance);
|
|
214
|
+
}
|
|
215
|
+
if (isOnApplicationShutdown(instance)) {
|
|
216
|
+
this.instancesWithShutdown.push(instance);
|
|
217
|
+
}
|
|
218
|
+
if (isOnBeforeRequest(instance)) {
|
|
219
|
+
this.instancesWithBeforeRequest.push(instance);
|
|
220
|
+
}
|
|
221
|
+
if (isOnAfterRequest(instance)) {
|
|
222
|
+
this.instancesWithAfterRequest.push(instance);
|
|
223
|
+
}
|
|
224
|
+
if (isOnRequestError(instance)) {
|
|
225
|
+
this.instancesWithRequestError.push(instance);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Register multiple instances with lifecycle hooks.
|
|
231
|
+
*/
|
|
232
|
+
registerInstances(instances: unknown[]): void {
|
|
233
|
+
for (const instance of instances) {
|
|
234
|
+
this.registerInstance(instance);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ============= Application Lifecycle Execution =============
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Execute onModuleInit hooks for all registered instances.
|
|
242
|
+
* Called after providers are registered.
|
|
243
|
+
*/
|
|
244
|
+
async executeOnModuleInit(): Promise<void> {
|
|
245
|
+
for (const instance of this.instancesWithModuleInit) {
|
|
246
|
+
await instance.onModuleInit();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Execute onApplicationBootstrap hooks for all registered instances.
|
|
252
|
+
* Called after controllers are registered.
|
|
253
|
+
*/
|
|
254
|
+
async executeOnApplicationBootstrap(): Promise<void> {
|
|
255
|
+
for (const instance of this.instancesWithBootstrap) {
|
|
256
|
+
await instance.onApplicationBootstrap();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Execute beforeApplicationShutdown hooks for all registered instances.
|
|
262
|
+
* Called when a shutdown signal is received.
|
|
263
|
+
*/
|
|
264
|
+
async executeBeforeApplicationShutdown(signal?: string): Promise<void> {
|
|
265
|
+
for (const instance of this.instancesWithBeforeShutdown) {
|
|
266
|
+
await instance.beforeApplicationShutdown(signal);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Execute onModuleDestroy hooks for all registered instances.
|
|
272
|
+
* Called during the shutdown process.
|
|
273
|
+
*/
|
|
274
|
+
async executeOnModuleDestroy(): Promise<void> {
|
|
275
|
+
for (const instance of this.instancesWithModuleDestroy) {
|
|
276
|
+
await instance.onModuleDestroy();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Execute onApplicationShutdown hooks for all registered instances.
|
|
282
|
+
* Called at the end of the shutdown process.
|
|
283
|
+
*/
|
|
284
|
+
async executeOnApplicationShutdown(signal?: string): Promise<void> {
|
|
285
|
+
for (const instance of this.instancesWithShutdown) {
|
|
286
|
+
await instance.onApplicationShutdown(signal);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ============= Request Lifecycle Execution =============
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Execute onBeforeRequest hooks for all registered instances.
|
|
294
|
+
*/
|
|
295
|
+
async executeOnBeforeRequest(context: Context): Promise<void> {
|
|
296
|
+
for (const instance of this.instancesWithBeforeRequest) {
|
|
297
|
+
await instance.onBeforeRequest(context);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Execute onAfterRequest hooks for all registered instances.
|
|
303
|
+
*/
|
|
304
|
+
async executeOnAfterRequest(
|
|
305
|
+
context: Context,
|
|
306
|
+
response: Response,
|
|
307
|
+
): Promise<void> {
|
|
308
|
+
for (const instance of this.instancesWithAfterRequest) {
|
|
309
|
+
await instance.onAfterRequest(context, response);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Execute onRequestError hooks for all registered instances.
|
|
315
|
+
*/
|
|
316
|
+
async executeOnRequestError(context: Context, error: Error): Promise<void> {
|
|
317
|
+
for (const instance of this.instancesWithRequestError) {
|
|
318
|
+
await instance.onRequestError(context, error);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// ============= Utility Methods =============
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Check if there are any registered instances with lifecycle hooks.
|
|
326
|
+
*/
|
|
327
|
+
hasRegisteredHooks(): boolean {
|
|
328
|
+
return (
|
|
329
|
+
this.instancesWithModuleInit.length > 0 ||
|
|
330
|
+
this.instancesWithBootstrap.length > 0 ||
|
|
331
|
+
this.instancesWithModuleDestroy.length > 0 ||
|
|
332
|
+
this.instancesWithBeforeShutdown.length > 0 ||
|
|
333
|
+
this.instancesWithShutdown.length > 0 ||
|
|
334
|
+
this.instancesWithBeforeRequest.length > 0 ||
|
|
335
|
+
this.instancesWithAfterRequest.length > 0 ||
|
|
336
|
+
this.instancesWithRequestError.length > 0
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Get count of registered instances for each hook type.
|
|
342
|
+
*/
|
|
343
|
+
getHookCounts(): {
|
|
344
|
+
onModuleInit: number;
|
|
345
|
+
onApplicationBootstrap: number;
|
|
346
|
+
onModuleDestroy: number;
|
|
347
|
+
beforeApplicationShutdown: number;
|
|
348
|
+
onApplicationShutdown: number;
|
|
349
|
+
onBeforeRequest: number;
|
|
350
|
+
onAfterRequest: number;
|
|
351
|
+
onRequestError: number;
|
|
352
|
+
} {
|
|
353
|
+
return {
|
|
354
|
+
onModuleInit: this.instancesWithModuleInit.length,
|
|
355
|
+
onApplicationBootstrap: this.instancesWithBootstrap.length,
|
|
356
|
+
onModuleDestroy: this.instancesWithModuleDestroy.length,
|
|
357
|
+
beforeApplicationShutdown: this.instancesWithBeforeShutdown.length,
|
|
358
|
+
onApplicationShutdown: this.instancesWithShutdown.length,
|
|
359
|
+
onBeforeRequest: this.instancesWithBeforeRequest.length,
|
|
360
|
+
onAfterRequest: this.instancesWithAfterRequest.length,
|
|
361
|
+
onRequestError: this.instancesWithRequestError.length,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Clear all registered instances.
|
|
367
|
+
* Useful for testing or when resetting the application.
|
|
368
|
+
*/
|
|
369
|
+
clear(): void {
|
|
370
|
+
this.instancesWithModuleInit = [];
|
|
371
|
+
this.instancesWithBootstrap = [];
|
|
372
|
+
this.instancesWithModuleDestroy = [];
|
|
373
|
+
this.instancesWithBeforeShutdown = [];
|
|
374
|
+
this.instancesWithShutdown = [];
|
|
375
|
+
this.instancesWithBeforeRequest = [];
|
|
376
|
+
this.instancesWithAfterRequest = [];
|
|
377
|
+
this.instancesWithRequestError = [];
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// ============= Shutdown Signal Handler =============
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Handler for graceful shutdown signals.
|
|
385
|
+
*/
|
|
386
|
+
export class ShutdownSignalHandler {
|
|
387
|
+
private isShuttingDown = false;
|
|
388
|
+
private signalListeners: Array<(signal: string) => Promise<void>> = [];
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Register a listener for shutdown signals.
|
|
392
|
+
*/
|
|
393
|
+
onSignal(listener: (signal: string) => Promise<void>): void {
|
|
394
|
+
this.signalListeners.push(listener);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Remove a listener for shutdown signals.
|
|
399
|
+
*/
|
|
400
|
+
offSignal(listener: (signal: string) => Promise<void>): void {
|
|
401
|
+
const index = this.signalListeners.indexOf(listener);
|
|
402
|
+
if (index > -1) {
|
|
403
|
+
this.signalListeners.splice(index, 1);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Start listening for shutdown signals (SIGTERM, SIGINT).
|
|
409
|
+
*/
|
|
410
|
+
startListening(): void {
|
|
411
|
+
process.on("SIGTERM", () => this.handleSignal("SIGTERM"));
|
|
412
|
+
process.on("SIGINT", () => this.handleSignal("SIGINT"));
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Stop listening for shutdown signals.
|
|
417
|
+
*/
|
|
418
|
+
stopListening(): void {
|
|
419
|
+
process.off("SIGTERM", () => this.handleSignal("SIGTERM"));
|
|
420
|
+
process.off("SIGINT", () => this.handleSignal("SIGINT"));
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Handle a shutdown signal.
|
|
425
|
+
*/
|
|
426
|
+
private async handleSignal(signal: string): Promise<void> {
|
|
427
|
+
if (this.isShuttingDown) {
|
|
428
|
+
console.log(`Already shutting down, ignoring ${signal}`);
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
this.isShuttingDown = true;
|
|
433
|
+
console.log(`\nReceived ${signal}, starting graceful shutdown...`);
|
|
434
|
+
|
|
435
|
+
for (const listener of this.signalListeners) {
|
|
436
|
+
try {
|
|
437
|
+
await listener(signal);
|
|
438
|
+
} catch (error) {
|
|
439
|
+
console.error("Error during shutdown:", error);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Exit with success code
|
|
444
|
+
process.exit(0);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Check if the application is shutting down.
|
|
449
|
+
*/
|
|
450
|
+
isShuttingDownNow(): boolean {
|
|
451
|
+
return this.isShuttingDown;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// ============= Combined Lifecycle Interfaces =============
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Combined interface for all application lifecycle hooks.
|
|
459
|
+
*/
|
|
460
|
+
export interface ApplicationLifecycle
|
|
461
|
+
extends OnModuleInit,
|
|
462
|
+
OnApplicationBootstrap,
|
|
463
|
+
OnModuleDestroy,
|
|
464
|
+
BeforeApplicationShutdown,
|
|
465
|
+
OnApplicationShutdown {}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Combined interface for all request lifecycle hooks.
|
|
469
|
+
*/
|
|
470
|
+
export interface RequestLifecycle
|
|
471
|
+
extends OnBeforeRequest,
|
|
472
|
+
OnAfterRequest,
|
|
473
|
+
OnRequestError {}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Combined interface for all lifecycle hooks.
|
|
477
|
+
*/
|
|
478
|
+
export interface FullLifecycle extends ApplicationLifecycle, RequestLifecycle {}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata Storage
|
|
3
|
+
*
|
|
4
|
+
* Isolated metadata storage and decorators to avoid circular dependencies.
|
|
5
|
+
* This module has no dependencies on other module files.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Token, Provider } from "../container";
|
|
9
|
+
|
|
10
|
+
// Type alias for class constructors
|
|
11
|
+
type Constructor = new (...args: unknown[]) => unknown;
|
|
12
|
+
|
|
13
|
+
// ============= Types =============
|
|
14
|
+
|
|
15
|
+
export interface ModuleMetadata {
|
|
16
|
+
imports?: Constructor[];
|
|
17
|
+
providers?: Provider[];
|
|
18
|
+
controllers?: Constructor[];
|
|
19
|
+
exports?: Token[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// ============= Metadata Storage =============
|
|
23
|
+
|
|
24
|
+
// Simple metadata storage without Reflect.metadata
|
|
25
|
+
const metadataStore = new WeakMap<Constructor, Map<string, unknown>>();
|
|
26
|
+
|
|
27
|
+
export function setMetadata(target: Constructor, key: string, value: unknown): void {
|
|
28
|
+
if (!metadataStore.has(target)) {
|
|
29
|
+
metadataStore.set(target, new Map());
|
|
30
|
+
}
|
|
31
|
+
metadataStore.get(target)?.set(key, value);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getMetadata<T>(target: Constructor, key: string): T | undefined {
|
|
35
|
+
return metadataStore.get(target)?.get(key) as T | undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Prototype metadata for method decorators
|
|
39
|
+
const prototypeMetadataStore = new WeakMap<object, Map<string, unknown>>();
|
|
40
|
+
|
|
41
|
+
export function setPrototypeMetadata(
|
|
42
|
+
target: object,
|
|
43
|
+
key: string,
|
|
44
|
+
value: unknown,
|
|
45
|
+
): void {
|
|
46
|
+
if (!prototypeMetadataStore.has(target)) {
|
|
47
|
+
prototypeMetadataStore.set(target, new Map());
|
|
48
|
+
}
|
|
49
|
+
prototypeMetadataStore.get(target)?.set(key, value);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function getPrototypeMetadata<T>(target: object, key: string): T | undefined {
|
|
53
|
+
return prototypeMetadataStore.get(target)?.get(key) as T | undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ============= Decorators =============
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Mark a class as injectable
|
|
60
|
+
*/
|
|
61
|
+
export function Injectable(): ClassDecorator {
|
|
62
|
+
return <TFunction extends Function>(target: TFunction): TFunction => {
|
|
63
|
+
setMetadata(target as unknown as Constructor, "injectable", true);
|
|
64
|
+
return target;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Mark a class as a controller with a base path
|
|
70
|
+
*/
|
|
71
|
+
export function Controller(path = ""): ClassDecorator {
|
|
72
|
+
return <TFunction extends Function>(target: TFunction): TFunction => {
|
|
73
|
+
setMetadata(target as unknown as Constructor, "controller", true);
|
|
74
|
+
setMetadata(target as unknown as Constructor, "path", path);
|
|
75
|
+
return target;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Define a module with metadata
|
|
81
|
+
*/
|
|
82
|
+
export function Module(metadata: ModuleMetadata): ClassDecorator {
|
|
83
|
+
return <TFunction extends Function>(target: TFunction): TFunction => {
|
|
84
|
+
setMetadata(target as unknown as Constructor, "module", metadata);
|
|
85
|
+
return target;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Export the Constructor type for use in other modules
|
|
90
|
+
export type { Constructor };
|