wynkjs 1.0.4 → 1.0.6

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.
Files changed (43) hide show
  1. package/README.md +296 -313
  2. package/dist/cors.d.ts +28 -0
  3. package/dist/cors.d.ts.map +1 -0
  4. package/dist/cors.js +121 -0
  5. package/dist/decorators/exception.decorators.d.ts +1 -0
  6. package/dist/decorators/exception.decorators.d.ts.map +1 -1
  7. package/dist/decorators/exception.decorators.js +20 -3
  8. package/dist/decorators/guard.decorators.d.ts.map +1 -1
  9. package/dist/decorators/guard.decorators.js +11 -5
  10. package/dist/decorators/http.decorators.d.ts +8 -3
  11. package/dist/decorators/http.decorators.d.ts.map +1 -1
  12. package/dist/decorators/http.decorators.js +9 -2
  13. package/dist/decorators/interceptor.advanced.d.ts +9 -9
  14. package/dist/decorators/interceptor.advanced.d.ts.map +1 -1
  15. package/dist/decorators/interceptor.advanced.js +7 -7
  16. package/dist/decorators/interceptor.decorators.d.ts +9 -7
  17. package/dist/decorators/interceptor.decorators.d.ts.map +1 -1
  18. package/dist/decorators/interceptor.decorators.js +29 -18
  19. package/dist/decorators/param.decorators.d.ts +2 -2
  20. package/dist/decorators/param.decorators.js +1 -1
  21. package/dist/decorators/pipe.decorators.d.ts +2 -2
  22. package/dist/decorators/pipe.decorators.js +2 -2
  23. package/dist/factory.d.ts +29 -1
  24. package/dist/factory.d.ts.map +1 -1
  25. package/dist/factory.js +155 -180
  26. package/dist/global-prefix.d.ts +49 -0
  27. package/dist/global-prefix.d.ts.map +1 -0
  28. package/dist/global-prefix.js +155 -0
  29. package/dist/index.d.ts +4 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +2 -0
  32. package/dist/interfaces/interceptor.interface.d.ts +15 -0
  33. package/dist/interfaces/interceptor.interface.d.ts.map +1 -0
  34. package/dist/interfaces/interceptor.interface.js +1 -0
  35. package/dist/optimized-handler.d.ts +31 -0
  36. package/dist/optimized-handler.d.ts.map +1 -0
  37. package/dist/optimized-handler.js +180 -0
  38. package/dist/pipes/validation.pipe.d.ts +10 -10
  39. package/dist/pipes/validation.pipe.js +4 -4
  40. package/dist/ultra-optimized-handler.d.ts +51 -0
  41. package/dist/ultra-optimized-handler.d.ts.map +1 -0
  42. package/dist/ultra-optimized-handler.js +302 -0
  43. package/package.json +10 -8
@@ -1,6 +1,6 @@
1
1
  import "reflect-metadata";
2
2
  /**
3
- * Parameter Decorators for ElysiaJS Framework
3
+ * Parameter Decorators for WynkJS Framework
4
4
  * Extract data from request context
5
5
  */
6
6
  export type ParamType = "body" | "param" | "query" | "headers" | "request" | "response" | "context" | "user" | "file" | "files";
@@ -80,7 +80,7 @@ export declare function Res(): ParameterDecorator;
80
80
  */
81
81
  export declare const Response: typeof Res;
82
82
  /**
83
- * @Context decorator - Injects full Elysia context
83
+ * @Context decorator - Injects full WynkJS context
84
84
  * @example
85
85
  * @Get()
86
86
  * getData(@Context() ctx: any) {}
@@ -98,7 +98,7 @@ export function Res() {
98
98
  */
99
99
  export const Response = Res;
100
100
  /**
101
- * @Context decorator - Injects full Elysia context
101
+ * @Context decorator - Injects full WynkJS context
102
102
  * @example
103
103
  * @Get()
104
104
  * getData(@Context() ctx: any) {}
@@ -66,12 +66,12 @@ export declare class ValidationPipe implements WynkPipeTransform {
66
66
  });
67
67
  transform(value: any, metadata: ArgumentMetadata): Promise<any>;
68
68
  /**
69
- * Format Elysia validation error
69
+ * Format WynkJS validation error
70
70
  * Called by ValidationExceptionFilter
71
71
  */
72
72
  formatError(exception: any): any;
73
73
  /**
74
- * Parse validation error from Elysia exception
74
+ * Parse validation error from WynkJS exception
75
75
  */
76
76
  private parseValidationError;
77
77
  /**
@@ -92,7 +92,7 @@ export class ValidationPipe {
92
92
  return value;
93
93
  }
94
94
  /**
95
- * Format Elysia validation error
95
+ * Format WynkJS validation error
96
96
  * Called by ValidationExceptionFilter
97
97
  */
98
98
  formatError(exception) {
@@ -105,7 +105,7 @@ export class ValidationPipe {
105
105
  return this.defaultFormatError(validationError);
106
106
  }
107
107
  /**
108
- * Parse validation error from Elysia exception
108
+ * Parse validation error from WynkJS exception
109
109
  */
110
110
  parseValidationError(exception) {
111
111
  let validationData;
package/dist/factory.d.ts CHANGED
@@ -1,31 +1,43 @@
1
1
  import { Elysia } from "elysia";
2
2
  import "reflect-metadata";
3
3
  import { ErrorFormatter } from "./decorators/formatter.decorators";
4
+ import { CorsOptions } from "./cors";
4
5
  /**
5
6
  * Application Factory for WynkJS Framework
6
7
  * Creates and configures Elysia app with all decorators support
7
8
  */
8
9
  export interface ApplicationOptions {
9
- cors?: boolean | any;
10
+ cors?: boolean | CorsOptions;
10
11
  globalPrefix?: string;
11
12
  logger?: boolean;
12
13
  validationErrorFormatter?: ErrorFormatter;
14
+ providers?: any[];
13
15
  }
14
16
  export declare class WynkFramework {
15
17
  private app;
16
18
  private controllers;
19
+ private providers;
17
20
  private globalGuards;
18
21
  private globalInterceptors;
19
22
  private globalPipes;
20
23
  private globalFilters;
21
24
  private validationFormatter?;
25
+ private shutdownHandlersRegistered;
26
+ private globalPrefix?;
27
+ private isBuilt;
22
28
  constructor(options?: ApplicationOptions);
23
29
  /**
24
30
  * Static convenience creator to align with documentation examples
25
31
  */
26
32
  static create(options?: ApplicationOptions & {
27
33
  controllers?: any[];
34
+ providers?: any[];
28
35
  }): WynkFramework;
36
+ /**
37
+ * Register providers with the application
38
+ * Providers are singleton services that are initialized when the app starts
39
+ */
40
+ registerProviders(...providers: any[]): this;
29
41
  /**
30
42
  * Register controllers with the application
31
43
  */
@@ -46,10 +58,20 @@ export declare class WynkFramework {
46
58
  * Register global exception filters
47
59
  */
48
60
  useGlobalFilters(...filters: any[]): this;
61
+ /**
62
+ * Initialize all registered providers
63
+ * Providers with onModuleInit() method will be called
64
+ */
65
+ private initializeProviders;
49
66
  /**
50
67
  * Build the application - register all routes
51
68
  */
52
69
  build(): Promise<Elysia>;
70
+ /**
71
+ * Cleanup all providers when app shuts down
72
+ * Providers with onModuleDestroy() method will be called
73
+ */
74
+ private destroyProviders;
53
75
  /**
54
76
  * Start listening on a port
55
77
  */
@@ -58,6 +80,11 @@ export declare class WynkFramework {
58
80
  * Get the underlying Elysia instance
59
81
  */
60
82
  getApp(): Elysia;
83
+ /**
84
+ * Handle an HTTP request
85
+ * Automatically builds the app if not already built
86
+ */
87
+ handle(request: Request): Promise<Response>;
61
88
  /**
62
89
  * Register a single controller
63
90
  */
@@ -73,6 +100,7 @@ export declare function createApp(options?: ApplicationOptions): WynkFramework;
73
100
  export declare class WynkFactory {
74
101
  static create(options?: ApplicationOptions & {
75
102
  controllers?: any[];
103
+ providers?: any[];
76
104
  }): WynkFramework;
77
105
  }
78
106
  export { WynkFramework as ElysiaFramework };
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../core/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,kBAAkB,CAAC;AAc1B,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAGnE;;;GAGG;AAEH,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,OAAO,GAAG,GAAG,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wBAAwB,CAAC,EAAE,cAAc,CAAC;CAC3C;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,mBAAmB,CAAC,CAAiB;gBAEjC,OAAO,GAAE,kBAAuB;IAgL5C;;OAEG;IACH,MAAM,CAAC,MAAM,CACX,OAAO,GAAE,kBAAkB,GAAG;QAAE,WAAW,CAAC,EAAE,GAAG,EAAE,CAAA;KAAO,GACzD,aAAa;IAQhB;;OAEG;IACH,mBAAmB,CAAC,GAAG,WAAW,EAAE,GAAG,EAAE,GAAG,IAAI;IAKhD;;OAEG;IACH,eAAe,CAAC,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI;IAKvC;;OAEG;IACH,qBAAqB,CAAC,GAAG,YAAY,EAAE,GAAG,EAAE,GAAG,IAAI;IAKnD;;OAEG;IACH,cAAc,CAAC,GAAG,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI;IAKrC;;OAEG;IACH,gBAAgB,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI;IAKzC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAkD9B;;OAEG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzC;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;OAEG;YACW,kBAAkB;CAuWjC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,kBAAuB,GAAG,aAAa,CAEzE;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,MAAM,CAAC,MAAM,CACX,OAAO,GAAE,kBAAkB,GAAG;QAAE,WAAW,CAAC,EAAE,GAAG,EAAE,CAAA;KAAO,GACzD,aAAa;CASjB;AAGD,OAAO,EAAE,aAAa,IAAI,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../core/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,kBAAkB,CAAC;AAc1B,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAEnE,OAAO,EAAE,WAAW,EAAa,MAAM,QAAQ,CAAC;AAOhD;;;GAGG;AAEH,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wBAAwB,CAAC,EAAE,cAAc,CAAC;IAC1C,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC;CACnB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,mBAAmB,CAAC,CAAiB;IAC7C,OAAO,CAAC,0BAA0B,CAAS;IAC3C,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,GAAE,kBAAuB;IA2L5C;;OAEG;IACH,MAAM,CAAC,MAAM,CACX,OAAO,GAAE,kBAAkB,GAAG;QAC5B,WAAW,CAAC,EAAE,GAAG,EAAE,CAAC;QACpB,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC;KACd,GACL,aAAa;IAahB;;;OAGG;IACH,iBAAiB,CAAC,GAAG,SAAS,EAAE,GAAG,EAAE,GAAG,IAAI;IAK5C;;OAEG;IACH,mBAAmB,CAAC,GAAG,WAAW,EAAE,GAAG,EAAE,GAAG,IAAI;IAKhD;;OAEG;IACH,eAAe,CAAC,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI;IAKvC;;OAEG;IACH,qBAAqB,CAAC,GAAG,YAAY,EAAE,GAAG,EAAE,GAAG,IAAI;IAKnD;;OAEG;IACH,cAAc,CAAC,GAAG,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI;IAKrC;;OAEG;IACH,gBAAgB,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI;IAKzC;;;OAGG;YACW,mBAAmB;IAkCjC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAwD9B;;;OAGG;YACW,gBAAgB;IA0B9B;;OAEG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkCzC;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;;OAGG;IACG,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAOjD;;OAEG;YACW,kBAAkB;CAwLjC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,kBAAuB,GAAG,aAAa,CAEzE;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,MAAM,CAAC,MAAM,CACX,OAAO,GAAE,kBAAkB,GAAG;QAC5B,WAAW,CAAC,EAAE,GAAG,EAAE,CAAC;QACpB,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC;KACd,GACL,aAAa;CAYjB;AAGD,OAAO,EAAE,aAAa,IAAI,eAAe,EAAE,CAAC"}
package/dist/factory.js CHANGED
@@ -2,22 +2,38 @@ import { Elysia } from "elysia";
2
2
  import "reflect-metadata";
3
3
  import { container } from "tsyringe";
4
4
  import { Value } from "@sinclair/typebox/value";
5
- import { createExecutionContext, executeGuards, } from "./decorators/guard.decorators";
6
- import { executeInterceptors } from "./decorators/interceptor.decorators";
7
- import { executePipes } from "./decorators/pipe.decorators";
8
- import { executeExceptionFilters, HttpException, } from "./decorators/exception.decorators";
5
+ import { executeExceptionFilters, } from "./decorators/exception.decorators";
9
6
  import { schemaRegistry } from "./schema-registry";
7
+ import { setupCors } from "./cors";
8
+ import { normalizePrefixPath } from "./global-prefix";
9
+ import { buildUltraOptimizedHandler, buildMiddlewareChain, } from "./ultra-optimized-handler";
10
10
  export class WynkFramework {
11
11
  app;
12
12
  controllers = [];
13
+ providers = []; // Store registered providers
13
14
  globalGuards = [];
14
15
  globalInterceptors = [];
15
16
  globalPipes = [];
16
17
  globalFilters = [];
17
18
  validationFormatter;
19
+ shutdownHandlersRegistered = false; // Prevent duplicate signal handlers
20
+ globalPrefix; // Store global prefix for route registration
21
+ isBuilt = false; // Track if build() has been called
18
22
  constructor(options = {}) {
19
23
  this.app = new Elysia();
20
24
  this.validationFormatter = options.validationErrorFormatter;
25
+ // Store global prefix for later use
26
+ if (options.globalPrefix) {
27
+ this.globalPrefix = normalizePrefixPath(options.globalPrefix);
28
+ }
29
+ // Register providers if provided
30
+ if (options.providers && options.providers.length > 0) {
31
+ this.providers.push(...options.providers);
32
+ }
33
+ // Apply CORS configuration
34
+ if (options.cors) {
35
+ setupCors(this.app, options.cors);
36
+ }
21
37
  // Configure Elysia's error handling for validation errors
22
38
  this.app.onError(({ code, error, set, request }) => {
23
39
  // Handle ValidationError from Elysia
@@ -137,13 +153,10 @@ export class WynkFramework {
137
153
  error: err.name || "Error",
138
154
  };
139
155
  });
140
- // Apply CORS if enabled
141
- if (options.cors) {
142
- // CORS configuration would go here
143
- }
144
156
  // Apply global prefix if specified
145
157
  if (options.globalPrefix) {
146
- // Global prefix handling
158
+ // Global prefix is handled during route registration
159
+ console.log(`✅ Global prefix configured: ${this.globalPrefix}`);
147
160
  }
148
161
  return this;
149
162
  }
@@ -152,11 +165,21 @@ export class WynkFramework {
152
165
  */
153
166
  static create(options = {}) {
154
167
  const app = new WynkFramework(options);
168
+ // Don't re-register providers/controllers if they were already added in constructor
169
+ // The constructor already handles options.providers
155
170
  if (options.controllers && options.controllers.length) {
156
171
  app.registerControllers(...options.controllers);
157
172
  }
158
173
  return app;
159
174
  }
175
+ /**
176
+ * Register providers with the application
177
+ * Providers are singleton services that are initialized when the app starts
178
+ */
179
+ registerProviders(...providers) {
180
+ this.providers.push(...providers);
181
+ return this;
182
+ }
160
183
  /**
161
184
  * Register controllers with the application
162
185
  */
@@ -192,10 +215,42 @@ export class WynkFramework {
192
215
  this.globalFilters.push(...filters);
193
216
  return this;
194
217
  }
218
+ /**
219
+ * Initialize all registered providers
220
+ * Providers with onModuleInit() method will be called
221
+ */
222
+ async initializeProviders() {
223
+ console.log(`🔧 Initializing ${this.providers.length} providers...`);
224
+ for (const ProviderClass of this.providers) {
225
+ try {
226
+ console.log(` ⚙️ Initializing provider: ${ProviderClass.name}`);
227
+ // Resolve provider instance from DI container
228
+ const instance = container.resolve(ProviderClass);
229
+ // Check if provider has onModuleInit lifecycle hook
230
+ if (typeof instance.onModuleInit === "function") {
231
+ await instance.onModuleInit();
232
+ console.log(` ✅ ${ProviderClass.name} initialized successfully`);
233
+ }
234
+ else {
235
+ // Just register in container for injection
236
+ console.log(` ✅ ${ProviderClass.name} registered in container`);
237
+ }
238
+ }
239
+ catch (error) {
240
+ console.error(` ❌ Failed to initialize provider ${ProviderClass.name}:`, error);
241
+ throw new Error(`Provider initialization failed for ${ProviderClass.name}: ${error.message}`);
242
+ }
243
+ }
244
+ console.log(`✅ All providers initialized successfully\n`);
245
+ }
195
246
  /**
196
247
  * Build the application - register all routes
197
248
  */
198
249
  async build() {
250
+ // Initialize providers first (database connections, etc.)
251
+ if (this.providers.length > 0) {
252
+ await this.initializeProviders();
253
+ }
199
254
  // Register global error handler if filters exist
200
255
  if (this.globalFilters.length > 0) {
201
256
  this.app.onError(async ({ error, set, request }) => {
@@ -234,8 +289,33 @@ export class WynkFramework {
234
289
  for (const ControllerClass of this.controllers) {
235
290
  await this.registerController(ControllerClass);
236
291
  }
292
+ this.isBuilt = true;
237
293
  return this.app;
238
294
  }
295
+ /**
296
+ * Cleanup all providers when app shuts down
297
+ * Providers with onModuleDestroy() method will be called
298
+ */
299
+ async destroyProviders() {
300
+ console.log(`\n🔧 Cleaning up ${this.providers.length} providers...`);
301
+ for (const ProviderClass of this.providers) {
302
+ try {
303
+ // Resolve provider instance from DI container
304
+ const instance = container.resolve(ProviderClass);
305
+ // Check if provider has onModuleDestroy lifecycle hook
306
+ if (typeof instance.onModuleDestroy === "function") {
307
+ console.log(` 🧹 Destroying provider: ${ProviderClass.name}`);
308
+ await instance.onModuleDestroy();
309
+ console.log(` ✅ ${ProviderClass.name} destroyed successfully`);
310
+ }
311
+ }
312
+ catch (error) {
313
+ console.error(` ❌ Failed to destroy provider ${ProviderClass.name}:`, error);
314
+ // Continue cleanup even if one provider fails
315
+ }
316
+ }
317
+ console.log(`✅ All providers cleaned up\n`);
318
+ }
239
319
  /**
240
320
  * Start listening on a port
241
321
  */
@@ -243,6 +323,29 @@ export class WynkFramework {
243
323
  await this.build();
244
324
  this.app.listen(port);
245
325
  console.log(`🚀 Application is running on http://localhost:${port}`);
326
+ // Register signal handlers only once to prevent memory leaks
327
+ if (!this.shutdownHandlersRegistered) {
328
+ this.shutdownHandlersRegistered = true;
329
+ // Setup graceful shutdown handlers
330
+ const gracefulShutdown = async (signal) => {
331
+ console.log(`\n📡 Received ${signal}, shutting down gracefully...`);
332
+ try {
333
+ // Cleanup providers (close database connections, etc.)
334
+ await this.destroyProviders();
335
+ // Stop the Elysia server
336
+ await this.app.stop();
337
+ console.log("👋 Application shut down successfully");
338
+ process.exit(0);
339
+ }
340
+ catch (error) {
341
+ console.error("❌ Error during shutdown:", error);
342
+ process.exit(1);
343
+ }
344
+ };
345
+ // Register signal handlers (only once)
346
+ process.once("SIGTERM", () => gracefulShutdown("SIGTERM"));
347
+ process.once("SIGINT", () => gracefulShutdown("SIGINT"));
348
+ }
246
349
  }
247
350
  /**
248
351
  * Get the underlying Elysia instance
@@ -250,6 +353,16 @@ export class WynkFramework {
250
353
  getApp() {
251
354
  return this.app;
252
355
  }
356
+ /**
357
+ * Handle an HTTP request
358
+ * Automatically builds the app if not already built
359
+ */
360
+ async handle(request) {
361
+ if (!this.isBuilt) {
362
+ await this.build();
363
+ }
364
+ return this.app.handle(request);
365
+ }
253
366
  /**
254
367
  * Register a single controller
255
368
  */
@@ -273,7 +386,11 @@ export class WynkFramework {
273
386
  // Get @Use() middleware (simple pattern like user's working code)
274
387
  const controllerUses = Reflect.getMetadata("uses", ControllerClass) || [];
275
388
  for (const route of routes) {
276
- const fullPath = basePath + route.path;
389
+ // Apply global prefix to route path
390
+ let fullPath = basePath + route.path;
391
+ if (this.globalPrefix) {
392
+ fullPath = this.globalPrefix + fullPath;
393
+ }
277
394
  const method = route.method.toLowerCase();
278
395
  const methodName = route.methodName;
279
396
  // Get method-specific metadata
@@ -284,19 +401,24 @@ export class WynkFramework {
284
401
  // Get @Use() middleware for this method
285
402
  const methodUses = Reflect.getMetadata("uses", instance, methodName) || [];
286
403
  const params = Reflect.getMetadata("params", instance, methodName) || [];
404
+ // Sort params once during registration, not on every request
405
+ if (params.length > 0) {
406
+ params.sort((a, b) => a.index - b.index);
407
+ }
287
408
  const httpCode = Reflect.getMetadata("route:httpCode", instance, methodName);
288
409
  const headers = Reflect.getMetadata("route:headers", instance, methodName);
289
410
  const redirect = Reflect.getMetadata("route:redirect", instance, methodName);
290
- // Combine guards, interceptors, pipes, filters (global -> controller -> method)
411
+ // Combine guards, interceptors, pipes, filters
412
+ // Order: method -> controller -> global (method is innermost/closest to handler)
291
413
  const allGuards = [
292
414
  ...this.globalGuards,
293
415
  ...controllerGuards,
294
416
  ...methodGuards,
295
417
  ];
296
418
  const allInterceptors = [
297
- ...this.globalInterceptors,
298
- ...controllerInterceptors,
299
419
  ...methodInterceptors,
420
+ ...controllerInterceptors,
421
+ ...this.globalInterceptors,
300
422
  ];
301
423
  const allPipes = [
302
424
  ...this.globalPipes,
@@ -314,178 +436,29 @@ export class WynkFramework {
314
436
  if (bodySchema && !routeOptions.body) {
315
437
  routeOptions.body = bodySchema;
316
438
  }
317
- // Create route handler
318
- const handler = async (ctx) => {
319
- try {
320
- // Create execution context
321
- const executionContext = createExecutionContext(ctx, instance[methodName], ControllerClass);
322
- // Execute guards
323
- if (allGuards.length > 0) {
324
- const canActivate = await executeGuards(allGuards, executionContext);
325
- if (!canActivate) {
326
- throw new HttpException("Forbidden", 403, "Access denied");
327
- }
328
- }
329
- // Prepare handler with parameters and pipes
330
- const executeHandler = async () => {
331
- // Build arguments for the controller method
332
- const args = [];
333
- if (params.length === 0) {
334
- // No parameter decorators, pass full context
335
- args.push(ctx);
336
- }
337
- else {
338
- // Sort params by index
339
- params.sort((a, b) => a.index - b.index);
340
- for (const param of params) {
341
- let value;
342
- // Extract value based on type
343
- switch (param.type) {
344
- case "body":
345
- value = param.data ? ctx.body?.[param.data] : ctx.body;
346
- break;
347
- case "param":
348
- value = param.data ? ctx.params?.[param.data] : ctx.params;
349
- break;
350
- case "query":
351
- value = param.data ? ctx.query?.[param.data] : ctx.query;
352
- break;
353
- case "headers":
354
- value = param.data
355
- ? ctx.headers?.get?.(param.data) ||
356
- ctx.request?.headers?.get?.(param.data)
357
- : ctx.headers || ctx.request?.headers;
358
- break;
359
- case "request":
360
- value = ctx.request || ctx;
361
- break;
362
- case "response":
363
- value = ctx.set || ctx.response;
364
- break;
365
- case "context":
366
- if (param.data) {
367
- // Access nested property like "session.userId"
368
- const keys = param.data.split(".");
369
- value = keys.reduce((obj, key) => obj?.[key], ctx);
370
- }
371
- else {
372
- value = ctx;
373
- }
374
- break;
375
- case "user":
376
- value = param.data ? ctx.user?.[param.data] : ctx.user;
377
- break;
378
- case "file":
379
- value = ctx.body?.file || ctx.file;
380
- break;
381
- case "files":
382
- value = ctx.body?.files || ctx.files;
383
- break;
384
- }
385
- // Apply pipes if any
386
- if (param.pipes && param.pipes.length > 0) {
387
- const metadata = {
388
- type: param.type,
389
- data: param.data,
390
- };
391
- value = await executePipes(param.pipes, value, metadata);
392
- }
393
- // Apply global/controller/method pipes
394
- if (allPipes.length > 0) {
395
- const metadata = {
396
- type: param.type,
397
- data: param.data,
398
- };
399
- value = await executePipes(allPipes, value, metadata);
400
- }
401
- args[param.index] = value;
402
- }
403
- }
404
- // Call controller method
405
- return await instance[methodName].apply(instance, args);
406
- };
407
- // Execute interceptors
408
- let result;
409
- if (allInterceptors.length > 0) {
410
- result = await executeInterceptors(allInterceptors, executionContext, executeHandler);
411
- }
412
- else {
413
- result = await executeHandler();
414
- }
415
- // Handle redirect
416
- if (redirect) {
417
- ctx.set.redirect = redirect.url;
418
- ctx.set.status = redirect.statusCode;
419
- return;
420
- }
421
- // Set custom HTTP code
422
- if (httpCode) {
423
- ctx.set.status = httpCode;
424
- }
425
- // Set custom headers
426
- if (headers) {
427
- Object.entries(headers).forEach(([key, value]) => {
428
- ctx.set.headers[key] = value;
429
- });
430
- }
431
- return result;
432
- }
433
- catch (error) {
434
- console.log("🔴 ERROR CAUGHT IN FACTORY");
435
- console.log("allFilters.length:", allFilters.length);
436
- console.log("Error:", error?.message);
437
- // Execute exception filters
438
- if (allFilters.length > 0) {
439
- console.log("✅ Executing exception filters...");
440
- const executionContext = createExecutionContext(ctx, instance[methodName], ControllerClass);
441
- try {
442
- const result = await executeExceptionFilters(allFilters, error, executionContext);
443
- if (result) {
444
- if (result.statusCode) {
445
- ctx.set.status = result.statusCode;
446
- }
447
- return result;
448
- }
449
- }
450
- catch (filterError) {
451
- // If filter doesn't handle it, continue to default error handling
452
- error = filterError;
453
- }
454
- }
455
- else {
456
- console.log("❌ No filters registered for this route");
457
- }
458
- // Default error handling
459
- if (error instanceof HttpException) {
460
- ctx.set.status = error.getStatus();
461
- return error.getResponse();
462
- }
463
- // Unknown error
464
- ctx.set.status = 500;
465
- return {
466
- statusCode: 500,
467
- message: error.message || "Internal server error",
468
- error: "Internal Server Error",
469
- };
470
- }
471
- };
439
+ // ULTRA-OPTIMIZED HANDLER - Use specialized builder
440
+ // This eliminates nested async/await and IIFEs for maximum performance
441
+ const handler = buildUltraOptimizedHandler({
442
+ instance,
443
+ methodName,
444
+ ControllerClass,
445
+ params,
446
+ allGuards,
447
+ allInterceptors,
448
+ allPipes,
449
+ allFilters,
450
+ httpCode,
451
+ headers,
452
+ redirect,
453
+ routePath: route.path,
454
+ routeMethod: method.toUpperCase(),
455
+ });
472
456
  // Wrap handler with @Use() middleware if present
473
457
  // Combine controller and method middleware
474
458
  const allUses = [...controllerUses, ...methodUses];
475
459
  let finalHandler = handler;
476
460
  if (allUses.length > 0) {
477
- console.log(`🔗 Building middleware chain for ${method} ${fullPath}:`);
478
- console.log(` Middleware count: ${allUses.length}`);
479
- allUses.forEach((m, i) => console.log(` [${i}] ${m.name || "anonymous"}`));
480
- // Build middleware chain using reduce (O(n) complexity)
481
- // Builds from right to left: handler <- middleware[n-1] <- ... <- middleware[0]
482
- // Executes left to right: middleware[0] -> ... -> middleware[n-1] -> handler
483
- finalHandler = allUses.reduceRight((next, middleware, index) => {
484
- return async (ctx) => {
485
- console.log(`▶️ Executing middleware [${index}]: ${middleware.name || "anonymous"}`);
486
- return await middleware(ctx, () => next(ctx));
487
- };
488
- }, handler);
461
+ finalHandler = buildMiddlewareChain(handler, allUses);
489
462
  }
490
463
  // Register route with Elysia
491
464
  const elysiaOptions = {};
@@ -536,6 +509,8 @@ export function createApp(options = {}) {
536
509
  export class WynkFactory {
537
510
  static create(options = {}) {
538
511
  const app = new WynkFramework(options);
512
+ // Don't re-register providers if they were already added in constructor
513
+ // The constructor already handles options.providers
539
514
  if (options.controllers) {
540
515
  app.registerControllers(...options.controllers);
541
516
  }
@@ -0,0 +1,49 @@
1
+ import { Elysia } from "elysia";
2
+ /**
3
+ * Global Prefix Module for WynkJS Framework
4
+ * Adds a prefix to all routes in the application
5
+ * Separated from factory.ts for better maintainability
6
+ */
7
+ export interface GlobalPrefixOptions {
8
+ prefix: string;
9
+ exclude?: string[];
10
+ }
11
+ /**
12
+ * Apply global prefix to all routes
13
+ * @param app - Elysia instance
14
+ * @param prefix - Prefix string (e.g., '/api', '/v1')
15
+ * @param options - Additional options like route exclusions
16
+ * @returns Modified Elysia instance
17
+ */
18
+ export declare function applyGlobalPrefix(app: Elysia, prefix: string | GlobalPrefixOptions): any;
19
+ /**
20
+ * Normalize prefix path
21
+ * - Ensures it starts with /
22
+ * - Removes trailing /
23
+ * - Validates format
24
+ * @param prefix - Raw prefix string
25
+ * @returns Normalized prefix
26
+ */
27
+ export declare function normalizePrefixPath(prefix: string): string;
28
+ /**
29
+ * Check if a route should be excluded from global prefix
30
+ * @param path - Route path
31
+ * @param excludedRoutes - List of routes to exclude
32
+ * @returns true if route should be excluded
33
+ */
34
+ export declare function isRouteExcluded(path: string, excludedRoutes: string[]): boolean;
35
+ /**
36
+ * Apply global prefix to an existing Elysia app by wrapping it
37
+ * This is useful when you want to add prefix to already configured app
38
+ * @param app - Existing Elysia instance
39
+ * @param prefix - Prefix to apply
40
+ * @returns New Elysia instance with prefix
41
+ */
42
+ export declare function wrapWithPrefix(app: Elysia, prefix: string | GlobalPrefixOptions): any;
43
+ /**
44
+ * Validate global prefix configuration
45
+ * @param prefix - Prefix configuration
46
+ * @returns true if valid, throws error if invalid
47
+ */
48
+ export declare function validateGlobalPrefix(prefix: string | GlobalPrefixOptions): boolean;
49
+ //# sourceMappingURL=global-prefix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"global-prefix.d.ts","sourceRoot":"","sources":["../core/global-prefix.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC;;;;GAIG;AAEH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GAAG,mBAAmB,GACnC,GAAG,CAkCL;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA0B1D;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAuBT;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GAAG,mBAAmB,GACnC,GAAG,CA0BL;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,GAAG,mBAAmB,GACnC,OAAO,CA2CT"}