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.
- package/README.md +296 -313
- package/dist/cors.d.ts +28 -0
- package/dist/cors.d.ts.map +1 -0
- package/dist/cors.js +121 -0
- package/dist/decorators/exception.decorators.d.ts +1 -0
- package/dist/decorators/exception.decorators.d.ts.map +1 -1
- package/dist/decorators/exception.decorators.js +20 -3
- package/dist/decorators/guard.decorators.d.ts.map +1 -1
- package/dist/decorators/guard.decorators.js +11 -5
- package/dist/decorators/http.decorators.d.ts +8 -3
- package/dist/decorators/http.decorators.d.ts.map +1 -1
- package/dist/decorators/http.decorators.js +9 -2
- package/dist/decorators/interceptor.advanced.d.ts +9 -9
- package/dist/decorators/interceptor.advanced.d.ts.map +1 -1
- package/dist/decorators/interceptor.advanced.js +7 -7
- package/dist/decorators/interceptor.decorators.d.ts +9 -7
- package/dist/decorators/interceptor.decorators.d.ts.map +1 -1
- package/dist/decorators/interceptor.decorators.js +29 -18
- package/dist/decorators/param.decorators.d.ts +2 -2
- package/dist/decorators/param.decorators.js +1 -1
- package/dist/decorators/pipe.decorators.d.ts +2 -2
- package/dist/decorators/pipe.decorators.js +2 -2
- package/dist/factory.d.ts +29 -1
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +155 -180
- package/dist/global-prefix.d.ts +49 -0
- package/dist/global-prefix.d.ts.map +1 -0
- package/dist/global-prefix.js +155 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/interfaces/interceptor.interface.d.ts +15 -0
- package/dist/interfaces/interceptor.interface.d.ts.map +1 -0
- package/dist/interfaces/interceptor.interface.js +1 -0
- package/dist/optimized-handler.d.ts +31 -0
- package/dist/optimized-handler.d.ts.map +1 -0
- package/dist/optimized-handler.js +180 -0
- package/dist/pipes/validation.pipe.d.ts +10 -10
- package/dist/pipes/validation.pipe.js +4 -4
- package/dist/ultra-optimized-handler.d.ts +51 -0
- package/dist/ultra-optimized-handler.d.ts.map +1 -0
- package/dist/ultra-optimized-handler.js +302 -0
- package/package.json +10 -8
package/dist/cors.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Elysia } from "elysia";
|
|
2
|
+
/**
|
|
3
|
+
* CORS Configuration Module for WynkJS Framework
|
|
4
|
+
* Separated from factory.ts for better maintainability
|
|
5
|
+
*/
|
|
6
|
+
export interface CorsOptions {
|
|
7
|
+
origin?: string | string[] | RegExp | ((origin: string) => boolean | Promise<boolean>);
|
|
8
|
+
methods?: string | string[];
|
|
9
|
+
allowedHeaders?: string | string[];
|
|
10
|
+
exposedHeaders?: string | string[];
|
|
11
|
+
credentials?: boolean;
|
|
12
|
+
maxAge?: number;
|
|
13
|
+
preflight?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Setup CORS for Elysia application
|
|
17
|
+
* @param app - Elysia instance
|
|
18
|
+
* @param corsOptions - CORS configuration (true for defaults, or custom config)
|
|
19
|
+
* @throws Error if @elysiajs/cors is not installed
|
|
20
|
+
*/
|
|
21
|
+
export declare function setupCors(app: Elysia, corsOptions: boolean | CorsOptions): void;
|
|
22
|
+
/**
|
|
23
|
+
* Validate CORS configuration
|
|
24
|
+
* @param corsOptions - CORS configuration to validate
|
|
25
|
+
* @returns true if valid, throws error if invalid
|
|
26
|
+
*/
|
|
27
|
+
export declare function validateCorsOptions(corsOptions: boolean | CorsOptions): boolean;
|
|
28
|
+
//# sourceMappingURL=cors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../core/cors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC;;;GAGG;AAEH,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EACH,MAAM,GACN,MAAM,EAAE,GACR,MAAM,GACN,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IACrD,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,OAAO,GAAG,WAAW,GACjC,IAAI,CA2EN;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,OAAO,GAAG,WAAW,GACjC,OAAO,CA2DT"}
|
package/dist/cors.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setup CORS for Elysia application
|
|
3
|
+
* @param app - Elysia instance
|
|
4
|
+
* @param corsOptions - CORS configuration (true for defaults, or custom config)
|
|
5
|
+
* @throws Error if @elysiajs/cors is not installed
|
|
6
|
+
*/
|
|
7
|
+
export function setupCors(app, corsOptions) {
|
|
8
|
+
try {
|
|
9
|
+
// Try to import @elysiajs/cors
|
|
10
|
+
const { cors } = require("@elysiajs/cors");
|
|
11
|
+
if (corsOptions === true) {
|
|
12
|
+
// Simple CORS - allow all origins
|
|
13
|
+
app.use(cors());
|
|
14
|
+
console.log("✅ CORS enabled (all origins allowed)");
|
|
15
|
+
}
|
|
16
|
+
else if (typeof corsOptions === "object") {
|
|
17
|
+
// Advanced CORS configuration
|
|
18
|
+
const config = {};
|
|
19
|
+
// Handle origin option (supports function, string, array, RegExp)
|
|
20
|
+
if (typeof corsOptions.origin === "function") {
|
|
21
|
+
// Convert function to Elysia's format
|
|
22
|
+
const originFn = corsOptions.origin;
|
|
23
|
+
config.origin = async (request) => {
|
|
24
|
+
const origin = request.headers.get("origin") || "";
|
|
25
|
+
const allowed = await originFn(origin);
|
|
26
|
+
return allowed ? origin : false;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
else if (corsOptions.origin) {
|
|
30
|
+
config.origin = corsOptions.origin;
|
|
31
|
+
}
|
|
32
|
+
// Methods
|
|
33
|
+
if (corsOptions.methods) {
|
|
34
|
+
config.methods = Array.isArray(corsOptions.methods)
|
|
35
|
+
? corsOptions.methods.join(",")
|
|
36
|
+
: corsOptions.methods;
|
|
37
|
+
}
|
|
38
|
+
// Allowed headers
|
|
39
|
+
if (corsOptions.allowedHeaders) {
|
|
40
|
+
config.allowedHeaders = Array.isArray(corsOptions.allowedHeaders)
|
|
41
|
+
? corsOptions.allowedHeaders.join(",")
|
|
42
|
+
: corsOptions.allowedHeaders;
|
|
43
|
+
}
|
|
44
|
+
// Exposed headers
|
|
45
|
+
if (corsOptions.exposedHeaders) {
|
|
46
|
+
config.exposedHeaders = Array.isArray(corsOptions.exposedHeaders)
|
|
47
|
+
? corsOptions.exposedHeaders.join(",")
|
|
48
|
+
: corsOptions.exposedHeaders;
|
|
49
|
+
}
|
|
50
|
+
// Credentials
|
|
51
|
+
if (corsOptions.credentials !== undefined) {
|
|
52
|
+
config.credentials = corsOptions.credentials;
|
|
53
|
+
}
|
|
54
|
+
// Max age
|
|
55
|
+
if (corsOptions.maxAge !== undefined) {
|
|
56
|
+
config.maxAge = corsOptions.maxAge;
|
|
57
|
+
}
|
|
58
|
+
// Preflight
|
|
59
|
+
if (corsOptions.preflight !== undefined) {
|
|
60
|
+
config.preflight = corsOptions.preflight;
|
|
61
|
+
}
|
|
62
|
+
app.use(cors(config));
|
|
63
|
+
console.log("✅ CORS enabled with custom configuration");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
console.error("❌ Failed to enable CORS: @elysiajs/cors package not found");
|
|
68
|
+
console.error(" Install it with: bun add @elysiajs/cors");
|
|
69
|
+
console.error(" Or remove cors option from ApplicationOptions to skip CORS setup");
|
|
70
|
+
throw new Error("CORS configuration failed: @elysiajs/cors package is required");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Validate CORS configuration
|
|
75
|
+
* @param corsOptions - CORS configuration to validate
|
|
76
|
+
* @returns true if valid, throws error if invalid
|
|
77
|
+
*/
|
|
78
|
+
export function validateCorsOptions(corsOptions) {
|
|
79
|
+
if (typeof corsOptions === "boolean") {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
if (typeof corsOptions === "object") {
|
|
83
|
+
// Validate origin
|
|
84
|
+
if (corsOptions.origin !== undefined) {
|
|
85
|
+
const validOriginTypes = [
|
|
86
|
+
"string",
|
|
87
|
+
"function",
|
|
88
|
+
"object", // array or RegExp
|
|
89
|
+
];
|
|
90
|
+
const originType = typeof corsOptions.origin;
|
|
91
|
+
if (!validOriginTypes.includes(originType)) {
|
|
92
|
+
throw new Error(`Invalid CORS origin type: ${originType}. Must be string, array, RegExp, or function.`);
|
|
93
|
+
}
|
|
94
|
+
// Validate array of strings
|
|
95
|
+
if (Array.isArray(corsOptions.origin)) {
|
|
96
|
+
if (!corsOptions.origin.every((o) => typeof o === "string")) {
|
|
97
|
+
throw new Error("CORS origin array must contain only strings (URLs)");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Validate methods
|
|
102
|
+
if (corsOptions.methods !== undefined) {
|
|
103
|
+
if (typeof corsOptions.methods !== "string" &&
|
|
104
|
+
!Array.isArray(corsOptions.methods)) {
|
|
105
|
+
throw new Error("CORS methods must be string or array of strings");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Validate maxAge
|
|
109
|
+
if (corsOptions.maxAge !== undefined &&
|
|
110
|
+
typeof corsOptions.maxAge !== "number") {
|
|
111
|
+
throw new Error("CORS maxAge must be a number");
|
|
112
|
+
}
|
|
113
|
+
// Validate credentials
|
|
114
|
+
if (corsOptions.credentials !== undefined &&
|
|
115
|
+
typeof corsOptions.credentials !== "boolean") {
|
|
116
|
+
throw new Error("CORS credentials must be a boolean");
|
|
117
|
+
}
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
throw new Error("CORS options must be boolean or CorsOptions object");
|
|
121
|
+
}
|
|
@@ -42,6 +42,7 @@ export declare class HttpException extends Error {
|
|
|
42
42
|
readonly statusCode: number;
|
|
43
43
|
readonly error?: string | undefined;
|
|
44
44
|
constructor(message: string, statusCode: number, error?: string | undefined);
|
|
45
|
+
get status(): number;
|
|
45
46
|
getStatus(): number;
|
|
46
47
|
getResponse(): any;
|
|
47
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exception.decorators.d.ts","sourceRoot":"","sources":["../../core/decorators/exception.decorators.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD;;;GAGG;AAEH;;GAEG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC,GAAG,GAAG;IAC1C,KAAK,CAAC,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,gBAAgB,GAAG,GAAG,CAAC;CACrD;AAED;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CAAC,GAAG,UAAU,EAAE,GAAG,EAAE,GAAG,cAAc,CAK1D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CACxB,GAAG,OAAO,EAAE,CAAC,QAAQ,GAAG,mBAAmB,CAAC,EAAE,GAC7C,eAAe,GAAG,cAAc,CAwBlC;AAED;;GAEG;AAEH,qBAAa,aAAc,SAAQ,KAAK;aAEpB,OAAO,EAAE,MAAM;aACf,UAAU,EAAE,MAAM;aAClB,KAAK,CAAC,EAAE,MAAM;gBAFd,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,MAAM,YAAA;IAMhC,SAAS,IAAI,MAAM;IAInB,WAAW,IAAI,GAAG;CAOnB;AAED,qBAAa,mBAAoB,SAAQ,aAAa;gBACxC,OAAO,GAAE,MAAsB;CAG5C;AAED,qBAAa,qBAAsB,SAAQ,aAAa;gBAC1C,OAAO,GAAE,MAAuB;CAG7C;AAED,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,OAAO,GAAE,MAAoB;CAG1C;AAED,qBAAa,iBAAkB,SAAQ,aAAa;gBACtC,OAAO,GAAE,MAAoB;CAG1C;AAED,qBAAa,yBAA0B,SAAQ,aAAa;gBAC9C,OAAO,GAAE,MAA6B;CAGnD;AAED,qBAAa,sBAAuB,SAAQ,aAAa;gBAC3C,OAAO,GAAE,MAAyB;CAG/C;AAED,qBAAa,uBAAwB,SAAQ,aAAa;gBAC5C,OAAO,GAAE,MAA0B;CAGhD;AAED,qBAAa,iBAAkB,SAAQ,aAAa;gBACtC,OAAO,GAAE,MAAmB;CAGzC;AAED,qBAAa,sBAAuB,SAAQ,aAAa;gBAC3C,OAAO,GAAE,MAAkC;CAGxD;AAED,qBAAa,aAAc,SAAQ,aAAa;gBAClC,OAAO,GAAE,MAAe;CAGrC;AAED,qBAAa,wBAAyB,SAAQ,aAAa;gBAC7C,OAAO,GAAE,MAA4B;CAGlD;AAED,qBAAa,6BAA8B,SAAQ,aAAa;gBAClD,OAAO,GAAE,MAAiC;CAGvD;AAED,qBAAa,4BAA6B,SAAQ,aAAa;gBACjD,OAAO,GAAE,MAA+B;CAGrD;AAED,qBAAa,4BAA6B,SAAQ,aAAa;gBACjD,OAAO,GAAE,MAAgC;CAGtD;AAED,qBAAa,uBAAwB,SAAQ,aAAa;gBAC5C,OAAO,GAAE,MAA0B;CAGhD;AAED,qBAAa,mBAAoB,SAAQ,aAAa;gBACxC,OAAO,GAAE,MAAsB;CAG5C;AAED,qBAAa,2BAA4B,SAAQ,aAAa;gBAChD,OAAO,GAAE,MAA8B;CAGpD;AAED,qBAAa,uBAAwB,SAAQ,aAAa;gBAC5C,OAAO,GAAE,MAA0B;CAGhD;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,CAAC,QAAQ,GAAG,mBAAmB,CAAC,EAAE,EAC3C,SAAS,EAAE,GAAG,EACd,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"exception.decorators.d.ts","sourceRoot":"","sources":["../../core/decorators/exception.decorators.ts"],"names":[],"mappings":"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"}
|
|
@@ -63,6 +63,9 @@ export class HttpException extends Error {
|
|
|
63
63
|
this.error = error;
|
|
64
64
|
this.name = "HttpException";
|
|
65
65
|
}
|
|
66
|
+
get status() {
|
|
67
|
+
return this.statusCode;
|
|
68
|
+
}
|
|
66
69
|
getStatus() {
|
|
67
70
|
return this.statusCode;
|
|
68
71
|
}
|
|
@@ -179,13 +182,27 @@ export async function executeExceptionFilters(filters, exception, context) {
|
|
|
179
182
|
// Check if filter handles this exception type
|
|
180
183
|
const catchTypes = Reflect.getMetadata("catch:exceptions", filterInstance.constructor);
|
|
181
184
|
if (!catchTypes || catchTypes.length === 0) {
|
|
182
|
-
// Catches all exceptions
|
|
183
|
-
|
|
185
|
+
// Catches all exceptions - try it
|
|
186
|
+
try {
|
|
187
|
+
return await filterInstance.catch(exception, context);
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
// Filter didn't handle it, try next filter
|
|
191
|
+
exception = err;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
184
194
|
}
|
|
185
195
|
// Check if exception matches any of the catch types
|
|
186
196
|
for (const catchType of catchTypes) {
|
|
187
197
|
if (exception instanceof catchType) {
|
|
188
|
-
|
|
198
|
+
try {
|
|
199
|
+
return await filterInstance.catch(exception, context);
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
// Filter didn't handle it, try next filter
|
|
203
|
+
exception = err;
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
189
206
|
}
|
|
190
207
|
}
|
|
191
208
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guard.decorators.d.ts","sourceRoot":"","sources":["../../core/decorators/guard.decorators.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B;;;GAGG;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC;IACzB,WAAW,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC;IAC1B,UAAU,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC;IACzB,UAAU,IAAI,QAAQ,CAAC;IACvB,QAAQ,IAAI,GAAG,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACpE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CACvB,GAAG,MAAM,EAAE,CAAC,QAAQ,GAAG,WAAW,CAAC,EAAE,GACpC,eAAe,GAAG,cAAc,CAwBlC;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,QAAQ,EACjB,eAAe,EAAE,GAAG,GACnB,gBAAgB,CAQlB;
|
|
1
|
+
{"version":3,"file":"guard.decorators.d.ts","sourceRoot":"","sources":["../../core/decorators/guard.decorators.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B;;;GAGG;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC;IACzB,WAAW,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC;IAC1B,UAAU,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC;IACzB,UAAU,IAAI,QAAQ,CAAC;IACvB,QAAQ,IAAI,GAAG,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACpE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CACvB,GAAG,MAAM,EAAE,CAAC,QAAQ,GAAG,WAAW,CAAC,EAAE,GACpC,eAAe,GAAG,cAAc,CAwBlC;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,QAAQ,EACjB,eAAe,EAAE,GAAG,GACnB,gBAAgB,CAQlB;AAOD;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,CAAC,QAAQ,GAAG,WAAW,CAAC,EAAE,EAClC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,OAAO,CAAC,CA8BlB"}
|
|
@@ -39,6 +39,10 @@ export function createExecutionContext(ctx, handler, controllerClass) {
|
|
|
39
39
|
getClass: () => controllerClass,
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Guard instance cache for singleton pattern
|
|
44
|
+
*/
|
|
45
|
+
const guardInstanceCache = new Map();
|
|
42
46
|
/**
|
|
43
47
|
* Helper function to execute guards
|
|
44
48
|
*/
|
|
@@ -46,14 +50,16 @@ export async function executeGuards(guards, context) {
|
|
|
46
50
|
for (const guard of guards) {
|
|
47
51
|
let result;
|
|
48
52
|
if (typeof guard === "function") {
|
|
49
|
-
// Guard is a class,
|
|
50
|
-
|
|
51
|
-
if (guardInstance
|
|
52
|
-
|
|
53
|
+
// Guard is a class, get or create singleton instance
|
|
54
|
+
let guardInstance = guardInstanceCache.get(guard);
|
|
55
|
+
if (!guardInstance) {
|
|
56
|
+
guardInstance = new guard();
|
|
57
|
+
guardInstanceCache.set(guard, guardInstance);
|
|
53
58
|
}
|
|
54
|
-
|
|
59
|
+
if (!guardInstance.canActivate) {
|
|
55
60
|
throw new Error(`Guard ${guard.name} must implement CanActivate interface`);
|
|
56
61
|
}
|
|
62
|
+
result = await guardInstance.canActivate(context);
|
|
57
63
|
}
|
|
58
64
|
else {
|
|
59
65
|
// Guard is already an instance
|
|
@@ -2,7 +2,7 @@ import "reflect-metadata";
|
|
|
2
2
|
/**
|
|
3
3
|
* HTTP Method Decorators for WynkJS Framework
|
|
4
4
|
* RESTful route handlers with TypeScript decorators
|
|
5
|
-
* Optimized for
|
|
5
|
+
* Optimized for WynkJS's performance on Bun runtime
|
|
6
6
|
*/
|
|
7
7
|
export interface RouteOptions {
|
|
8
8
|
path?: string;
|
|
@@ -14,12 +14,17 @@ export interface RouteOptions {
|
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* Controller decorator - Defines a controller with a base path
|
|
17
|
-
* @param
|
|
17
|
+
* @param pathOrOptions Base path string or options object with path
|
|
18
18
|
* @example
|
|
19
19
|
* @Controller('/users')
|
|
20
20
|
* export class UserController {}
|
|
21
|
+
*
|
|
22
|
+
* @Controller({ path: '/users' })
|
|
23
|
+
* export class UserController {}
|
|
21
24
|
*/
|
|
22
|
-
export declare function Controller(
|
|
25
|
+
export declare function Controller(pathOrOptions?: string | {
|
|
26
|
+
path?: string;
|
|
27
|
+
}): ClassDecorator;
|
|
23
28
|
/**
|
|
24
29
|
* HTTP GET decorator
|
|
25
30
|
* @param pathOrOptions Route path or options with DTO
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.decorators.d.ts","sourceRoot":"","sources":["../../core/decorators/http.decorators.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B;;;;GAIG;AAEH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,QAAQ,CAAC,EAAE,GAAG,CAAC;CAChB;AAED
|
|
1
|
+
{"version":3,"file":"http.decorators.d.ts","sourceRoot":"","sources":["../../core/decorators/http.decorators.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B;;;;GAIG;AAEH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,QAAQ,CAAC,EAAE,GAAG,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CACxB,aAAa,CAAC,EAAE,MAAM,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACzC,cAAc,CAWhB;AAED;;;;;;;;;GASG;AACH,wBAAgB,GAAG,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,eAAe,CAM1E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,IAAI,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,eAAe,CAM3E;AAED;;;;;;;;;GASG;AACH,wBAAgB,GAAG,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,eAAe,CAM1E;AAED;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,eAAe,CAM5E;AAED;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,eAAe,CAM7E;AAED;;;GAGG;AACH,wBAAgB,OAAO,CACrB,aAAa,CAAC,EAAE,MAAM,GAAG,YAAY,GACpC,eAAe,CAMjB;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,eAAe,CAM3E;AAmDD;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAStD;AAED;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,CAYnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CACtB,GAAG,EAAE,MAAM,EACX,UAAU,GAAE,MAAY,GACvB,eAAe,CAcjB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,GAAG,CAAC,GAAG,WAAW,EAAE,GAAG,EAAE,GAAG,cAAc,GAAG,eAAe,CAuB3E"}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
2
|
/**
|
|
3
3
|
* Controller decorator - Defines a controller with a base path
|
|
4
|
-
* @param
|
|
4
|
+
* @param pathOrOptions Base path string or options object with path
|
|
5
5
|
* @example
|
|
6
6
|
* @Controller('/users')
|
|
7
7
|
* export class UserController {}
|
|
8
|
+
*
|
|
9
|
+
* @Controller({ path: '/users' })
|
|
10
|
+
* export class UserController {}
|
|
8
11
|
*/
|
|
9
|
-
export function Controller(
|
|
12
|
+
export function Controller(pathOrOptions) {
|
|
10
13
|
return (target) => {
|
|
14
|
+
// Handle both string and object formats
|
|
15
|
+
const path = typeof pathOrOptions === "string"
|
|
16
|
+
? pathOrOptions
|
|
17
|
+
: pathOrOptions?.path || "";
|
|
11
18
|
Reflect.defineMetadata("basePath", path, target);
|
|
12
19
|
Reflect.defineMetadata("routes", [], target);
|
|
13
20
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
|
-
import { WynkInterceptor
|
|
3
|
-
import {
|
|
2
|
+
import { WynkInterceptor } from "./interceptor.decorators";
|
|
3
|
+
import { InterceptorContext } from "../interfaces/interceptor.interface";
|
|
4
4
|
/**
|
|
5
5
|
* Advanced Interceptors for WynkJS Framework
|
|
6
6
|
* Additional interceptors for common use cases
|
|
@@ -13,7 +13,7 @@ import { ExecutionContext } from "./guard.decorators";
|
|
|
13
13
|
* export class ApiController {}
|
|
14
14
|
*/
|
|
15
15
|
export declare class ResponseInterceptor implements WynkInterceptor {
|
|
16
|
-
intercept(context:
|
|
16
|
+
intercept(context: InterceptorContext, next: () => Promise<any>): Promise<any>;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* Error Handling Interceptor - Catches and transforms errors
|
|
@@ -23,7 +23,7 @@ export declare class ResponseInterceptor implements WynkInterceptor {
|
|
|
23
23
|
* async getData() {}
|
|
24
24
|
*/
|
|
25
25
|
export declare class ErrorHandlingInterceptor implements WynkInterceptor {
|
|
26
|
-
intercept(context:
|
|
26
|
+
intercept(context: InterceptorContext, next: () => Promise<any>): Promise<any>;
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
29
|
* Compression Interceptor - Simulates response compression metadata
|
|
@@ -35,7 +35,7 @@ export declare class ErrorHandlingInterceptor implements WynkInterceptor {
|
|
|
35
35
|
export declare class CompressionInterceptor implements WynkInterceptor {
|
|
36
36
|
private threshold;
|
|
37
37
|
constructor(threshold?: number);
|
|
38
|
-
intercept(context:
|
|
38
|
+
intercept(context: InterceptorContext, next: () => Promise<any>): Promise<any>;
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
41
|
* Rate Limit Interceptor - Basic rate limiting
|
|
@@ -49,7 +49,7 @@ export declare class RateLimitInterceptor implements WynkInterceptor {
|
|
|
49
49
|
private windowMs;
|
|
50
50
|
private requests;
|
|
51
51
|
constructor(maxRequests?: number, windowMs?: number);
|
|
52
|
-
intercept(context:
|
|
52
|
+
intercept(context: InterceptorContext, next: () => Promise<any>): Promise<any>;
|
|
53
53
|
}
|
|
54
54
|
/**
|
|
55
55
|
* CORS Interceptor - Add CORS headers to responses
|
|
@@ -65,7 +65,7 @@ export declare class CorsInterceptor implements WynkInterceptor {
|
|
|
65
65
|
methods?: string[];
|
|
66
66
|
credentials?: boolean;
|
|
67
67
|
});
|
|
68
|
-
intercept(context:
|
|
68
|
+
intercept(context: InterceptorContext, next: () => Promise<any>): Promise<any>;
|
|
69
69
|
}
|
|
70
70
|
/**
|
|
71
71
|
* Sanitize Interceptor - Sanitizes response data
|
|
@@ -77,7 +77,7 @@ export declare class CorsInterceptor implements WynkInterceptor {
|
|
|
77
77
|
export declare class SanitizeInterceptor implements WynkInterceptor {
|
|
78
78
|
private fieldsToRemove;
|
|
79
79
|
constructor(fieldsToRemove?: string[]);
|
|
80
|
-
intercept(context:
|
|
80
|
+
intercept(context: InterceptorContext, next: () => Promise<any>): Promise<any>;
|
|
81
81
|
private sanitize;
|
|
82
82
|
}
|
|
83
83
|
/**
|
|
@@ -88,6 +88,6 @@ export declare class SanitizeInterceptor implements WynkInterceptor {
|
|
|
88
88
|
* async getUsers(@Query('page') page: number, @Query('limit') limit: number) {}
|
|
89
89
|
*/
|
|
90
90
|
export declare class PaginationInterceptor implements WynkInterceptor {
|
|
91
|
-
intercept(context:
|
|
91
|
+
intercept(context: InterceptorContext, next: () => Promise<any>): Promise<any>;
|
|
92
92
|
}
|
|
93
93
|
//# sourceMappingURL=interceptor.advanced.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interceptor.advanced.d.ts","sourceRoot":"","sources":["../../core/decorators/interceptor.advanced.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"interceptor.advanced.d.ts","sourceRoot":"","sources":["../../core/decorators/interceptor.advanced.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAEzE;;;GAGG;AAEH;;;;;;GAMG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IACnD,SAAS,CACb,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,GAAG,CAAC;CAsChB;AAED;;;;;;GAMG;AACH,qBAAa,wBAAyB,YAAW,eAAe;IACxD,SAAS,CACb,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,GAAG,CAAC;CAoBhB;AAED;;;;;;GAMG;AACH,qBAAa,sBAAuB,YAAW,eAAe;IAChD,OAAO,CAAC,SAAS;gBAAT,SAAS,GAAE,MAAa;IAEtC,SAAS,CACb,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,GAAG,CAAC;CAahB;AAED;;;;;;GAMG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IAIxD,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,QAAQ;IAJlB,OAAO,CAAC,QAAQ,CAAoC;gBAG1C,WAAW,GAAE,MAAY,EACzB,QAAQ,GAAE,MAAc;IAG5B,SAAS,CACb,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,GAAG,CAAC;CA0BhB;AAED;;;;;;GAMG;AACH,qBAAa,eAAgB,YAAW,eAAe;IAEnD,OAAO,CAAC,OAAO;gBAAP,OAAO,GAAE;QACf,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,WAAW,CAAC,EAAE,OAAO,CAAC;KAClB;IAGF,SAAS,CACb,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,GAAG,CAAC;CA8BhB;AAED;;;;;;GAMG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IACzD,OAAO,CAAC,cAAc,CAAW;gBAErB,cAAc,GAAE,MAAM,EAAoC;IAIhE,SAAS,CACb,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,GAAG,CAAC;IAKf,OAAO,CAAC,QAAQ;CAmBjB;AAED;;;;;;GAMG;AACH,qBAAa,qBAAsB,YAAW,eAAe;IACrD,SAAS,CACb,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,GAAG,CAAC;CA2BhB"}
|
|
@@ -15,7 +15,7 @@ export class ResponseInterceptor {
|
|
|
15
15
|
const request = context.getRequest();
|
|
16
16
|
const startTime = Date.now();
|
|
17
17
|
try {
|
|
18
|
-
const data = await next
|
|
18
|
+
const data = await next();
|
|
19
19
|
const duration = Date.now() - startTime;
|
|
20
20
|
return {
|
|
21
21
|
success: true,
|
|
@@ -58,7 +58,7 @@ export class ResponseInterceptor {
|
|
|
58
58
|
export class ErrorHandlingInterceptor {
|
|
59
59
|
async intercept(context, next) {
|
|
60
60
|
try {
|
|
61
|
-
return await next
|
|
61
|
+
return await next();
|
|
62
62
|
}
|
|
63
63
|
catch (error) {
|
|
64
64
|
console.error(`❌ Error in ${context.getRequest().method} ${context.getRequest().url}:`, error);
|
|
@@ -85,7 +85,7 @@ export class CompressionInterceptor {
|
|
|
85
85
|
this.threshold = threshold;
|
|
86
86
|
}
|
|
87
87
|
async intercept(context, next) {
|
|
88
|
-
const data = await next
|
|
88
|
+
const data = await next();
|
|
89
89
|
const dataSize = JSON.stringify(data).length;
|
|
90
90
|
if (dataSize > this.threshold) {
|
|
91
91
|
// In a real implementation, you'd compress the data here
|
|
@@ -128,7 +128,7 @@ export class RateLimitInterceptor {
|
|
|
128
128
|
// Add current request
|
|
129
129
|
history.push(now);
|
|
130
130
|
this.requests.set(clientIp, history);
|
|
131
|
-
return next
|
|
131
|
+
return next();
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
/**
|
|
@@ -162,7 +162,7 @@ export class CorsInterceptor {
|
|
|
162
162
|
response.headers.set("Access-Control-Allow-Credentials", "true");
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
|
-
return next
|
|
165
|
+
return next();
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
/**
|
|
@@ -178,7 +178,7 @@ export class SanitizeInterceptor {
|
|
|
178
178
|
this.fieldsToRemove = fieldsToRemove;
|
|
179
179
|
}
|
|
180
180
|
async intercept(context, next) {
|
|
181
|
-
const data = await next
|
|
181
|
+
const data = await next();
|
|
182
182
|
return this.sanitize(data);
|
|
183
183
|
}
|
|
184
184
|
sanitize(data) {
|
|
@@ -210,7 +210,7 @@ export class PaginationInterceptor {
|
|
|
210
210
|
const url = new URL(request.url, `http://${request.headers?.get?.("host")}`);
|
|
211
211
|
const page = parseInt(url.searchParams.get("page") || "1");
|
|
212
212
|
const limit = parseInt(url.searchParams.get("limit") || "10");
|
|
213
|
-
const data = await next
|
|
213
|
+
const data = await next();
|
|
214
214
|
// If data is an array, add pagination
|
|
215
215
|
if (Array.isArray(data)) {
|
|
216
216
|
return {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
|
-
import {
|
|
2
|
+
import { InterceptorContext } from "../interfaces/interceptor.interface";
|
|
3
|
+
type ExecutionContext = InterceptorContext;
|
|
3
4
|
/**
|
|
4
5
|
* Interceptor Decorators and Interfaces for WynkJS Framework
|
|
5
6
|
* Interceptors for request/response transformation
|
|
@@ -14,7 +15,7 @@ export interface CallHandler<T = any> {
|
|
|
14
15
|
* WynkInterceptor interface - All interceptors must implement this
|
|
15
16
|
*/
|
|
16
17
|
export interface WynkInterceptor {
|
|
17
|
-
intercept(context: ExecutionContext, next:
|
|
18
|
+
intercept(context: ExecutionContext, next: () => Promise<any>): Promise<any>;
|
|
18
19
|
}
|
|
19
20
|
/**
|
|
20
21
|
* @UseInterceptors decorator - Apply interceptors to routes or controllers
|
|
@@ -32,7 +33,7 @@ export declare function UseInterceptors(...interceptors: (Function | WynkInterce
|
|
|
32
33
|
/**
|
|
33
34
|
* Helper function to execute interceptors
|
|
34
35
|
*/
|
|
35
|
-
export declare function executeInterceptors(interceptors: (Function | WynkInterceptor)[], context:
|
|
36
|
+
export declare function executeInterceptors(interceptors: (Function | WynkInterceptor)[], context: InterceptorContext, handler: () => Promise<any>): Promise<any>;
|
|
36
37
|
/**
|
|
37
38
|
* Common interceptor utilities
|
|
38
39
|
*/
|
|
@@ -50,7 +51,7 @@ export declare function executeInterceptors(interceptors: (Function | WynkInterc
|
|
|
50
51
|
export declare class TransformInterceptor implements WynkInterceptor {
|
|
51
52
|
private transformFn?;
|
|
52
53
|
constructor(transformFn?: ((data: any) => any) | undefined);
|
|
53
|
-
intercept(context:
|
|
54
|
+
intercept(context: InterceptorContext, next: () => Promise<any>): Promise<any>;
|
|
54
55
|
}
|
|
55
56
|
/**
|
|
56
57
|
* Timeout interceptor - Adds timeout to requests
|
|
@@ -63,7 +64,7 @@ export declare class TransformInterceptor implements WynkInterceptor {
|
|
|
63
64
|
export declare class TimeoutInterceptor implements WynkInterceptor {
|
|
64
65
|
private timeout;
|
|
65
66
|
constructor(timeout?: number);
|
|
66
|
-
intercept(context:
|
|
67
|
+
intercept(context: InterceptorContext, next: () => Promise<any>): Promise<any>;
|
|
67
68
|
}
|
|
68
69
|
/**
|
|
69
70
|
* Cache interceptor - Caches responses
|
|
@@ -76,7 +77,7 @@ export declare class CacheInterceptor implements WynkInterceptor {
|
|
|
76
77
|
private cache;
|
|
77
78
|
private ttl;
|
|
78
79
|
constructor(ttl?: number);
|
|
79
|
-
intercept(context:
|
|
80
|
+
intercept(context: InterceptorContext, next: () => Promise<any>): Promise<any>;
|
|
80
81
|
}
|
|
81
82
|
/**
|
|
82
83
|
* Logging interceptor - Logs requests and responses
|
|
@@ -86,6 +87,7 @@ export declare class CacheInterceptor implements WynkInterceptor {
|
|
|
86
87
|
* export class AppController {}
|
|
87
88
|
*/
|
|
88
89
|
export declare class LoggingInterceptor implements WynkInterceptor {
|
|
89
|
-
intercept(context:
|
|
90
|
+
intercept(context: InterceptorContext, next: () => Promise<any>): Promise<any>;
|
|
90
91
|
}
|
|
92
|
+
export {};
|
|
91
93
|
//# sourceMappingURL=interceptor.decorators.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interceptor.decorators.d.ts","sourceRoot":"","sources":["../../core/decorators/interceptor.decorators.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"interceptor.decorators.d.ts","sourceRoot":"","sources":["../../core/decorators/interceptor.decorators.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAIzE,KAAK,gBAAgB,GAAG,kBAAkB,CAAC;AAK3C;;;GAGG;AAEH;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,GAAG;IAClC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CAC9E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,GAAG,YAAY,EAAE,CAAC,QAAQ,GAAG,eAAe,CAAC,EAAE,GAC9C,eAAe,GAAG,cAAc,CA4BlC;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,CAAC,QAAQ,GAAG,eAAe,CAAC,EAAE,EAC5C,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GAC1B,OAAO,CAAC,GAAG,CAAC,CAyCd;AAED;;GAEG;AAEH;;;;;;;;;;GAUG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IAC9C,OAAO,CAAC,WAAW,CAAC;gBAAZ,WAAW,CAAC,GAAE,CAAC,IAAI,EAAE,GAAG,KAAK,GAAG,aAAA;IAE9C,SAAS,CACb,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,GAAG,CAAC;CAahB;AAED;;;;;;;GAOG;AACH,qBAAa,kBAAmB,YAAW,eAAe;IAC5C,OAAO,CAAC,OAAO;gBAAP,OAAO,GAAE,MAAa;IAEpC,SAAS,CACb,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,GAAG,CAAC;CAQhB;AAED;;;;;;GAMG;AACH,qBAAa,gBAAiB,YAAW,eAAe;IACtD,OAAO,CAAC,KAAK,CAAuD;IACpE,OAAO,CAAC,GAAG,CAAS;gBAER,GAAG,GAAE,MAAc;IAIzB,SAAS,CACb,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,GAAG,CAAC;CAgBhB;AAED;;;;;;GAMG;AACH,qBAAa,kBAAmB,YAAW,eAAe;IAClD,SAAS,CACb,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,GAAG,CAAC;CAqBhB"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
|
+
import { container } from "tsyringe";
|
|
3
|
+
// Store singleton interceptor instances
|
|
4
|
+
const interceptorInstances = new Map();
|
|
2
5
|
/**
|
|
3
6
|
* @UseInterceptors decorator - Apply interceptors to routes or controllers
|
|
4
7
|
* @param interceptors Interceptor classes to apply
|
|
@@ -31,17 +34,27 @@ export function UseInterceptors(...interceptors) {
|
|
|
31
34
|
* Helper function to execute interceptors
|
|
32
35
|
*/
|
|
33
36
|
export async function executeInterceptors(interceptors, context, handler) {
|
|
34
|
-
// Build interceptor chain
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
// Apply interceptors in
|
|
39
|
-
|
|
37
|
+
// Build interceptor chain
|
|
38
|
+
// First interceptor in array is innermost (transforms first, closest to handler)
|
|
39
|
+
// Last interceptor in array is outermost (transforms last, farthest from handler)
|
|
40
|
+
let next = handler;
|
|
41
|
+
// Apply interceptors in FORWARD order
|
|
42
|
+
// First wraps handler, second wraps first, etc.
|
|
43
|
+
for (let i = 0; i < interceptors.length; i++) {
|
|
40
44
|
const interceptor = interceptors[i];
|
|
41
|
-
const currentNext = next;
|
|
45
|
+
const currentNext = next; // Capture current next in closure
|
|
42
46
|
let interceptorInstance;
|
|
43
47
|
if (typeof interceptor === "function") {
|
|
44
|
-
|
|
48
|
+
// Always use singleton pattern - cache all interceptor instances by class
|
|
49
|
+
if (!interceptorInstances.has(interceptor)) {
|
|
50
|
+
try {
|
|
51
|
+
interceptorInstances.set(interceptor, container.resolve(interceptor));
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
interceptorInstances.set(interceptor, new interceptor());
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
interceptorInstance = interceptorInstances.get(interceptor);
|
|
45
58
|
}
|
|
46
59
|
else {
|
|
47
60
|
interceptorInstance = interceptor;
|
|
@@ -49,14 +62,12 @@ export async function executeInterceptors(interceptors, context, handler) {
|
|
|
49
62
|
if (!interceptorInstance.intercept) {
|
|
50
63
|
throw new Error(`Interceptor must implement WynkInterceptor interface`);
|
|
51
64
|
}
|
|
52
|
-
//
|
|
53
|
-
next = {
|
|
54
|
-
|
|
55
|
-
return interceptorInstance.intercept(context, currentNext);
|
|
56
|
-
},
|
|
65
|
+
// Wrap in a function that calls the interceptor
|
|
66
|
+
next = async () => {
|
|
67
|
+
return interceptorInstance.intercept(context, currentNext);
|
|
57
68
|
};
|
|
58
69
|
}
|
|
59
|
-
return next
|
|
70
|
+
return next();
|
|
60
71
|
}
|
|
61
72
|
/**
|
|
62
73
|
* Common interceptor utilities
|
|
@@ -78,7 +89,7 @@ export class TransformInterceptor {
|
|
|
78
89
|
this.transformFn = transformFn;
|
|
79
90
|
}
|
|
80
91
|
async intercept(context, next) {
|
|
81
|
-
const data = await next
|
|
92
|
+
const data = await next();
|
|
82
93
|
if (this.transformFn) {
|
|
83
94
|
return this.transformFn(data);
|
|
84
95
|
}
|
|
@@ -104,7 +115,7 @@ export class TimeoutInterceptor {
|
|
|
104
115
|
}
|
|
105
116
|
async intercept(context, next) {
|
|
106
117
|
return Promise.race([
|
|
107
|
-
next
|
|
118
|
+
next(),
|
|
108
119
|
new Promise((_, reject) => setTimeout(() => reject(new Error("Request timeout")), this.timeout)),
|
|
109
120
|
]);
|
|
110
121
|
}
|
|
@@ -131,7 +142,7 @@ export class CacheInterceptor {
|
|
|
131
142
|
return cached.data;
|
|
132
143
|
}
|
|
133
144
|
// Execute handler and cache result
|
|
134
|
-
const data = await next
|
|
145
|
+
const data = await next();
|
|
135
146
|
this.cache.set(cacheKey, { data, timestamp: Date.now() });
|
|
136
147
|
return data;
|
|
137
148
|
}
|
|
@@ -149,7 +160,7 @@ export class LoggingInterceptor {
|
|
|
149
160
|
const startTime = Date.now();
|
|
150
161
|
console.log(`📥 ${request.method} ${request.url} - Started`);
|
|
151
162
|
try {
|
|
152
|
-
const data = await next
|
|
163
|
+
const data = await next();
|
|
153
164
|
const duration = Date.now() - startTime;
|
|
154
165
|
console.log(`📤 ${request.method} ${request.url} - Completed in ${duration}ms`);
|
|
155
166
|
return data;
|