wynkjs 1.0.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/LICENSE +21 -0
- package/README.md +522 -0
- package/dist/database.d.ts +36 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +162 -0
- package/dist/decorators/database.decorators.d.ts +55 -0
- package/dist/decorators/database.decorators.d.ts.map +1 -0
- package/dist/decorators/database.decorators.js +131 -0
- package/dist/decorators/exception.advanced.d.ts +160 -0
- package/dist/decorators/exception.advanced.d.ts.map +1 -0
- package/dist/decorators/exception.advanced.js +232 -0
- package/dist/decorators/exception.decorators.d.ts +121 -0
- package/dist/decorators/exception.decorators.d.ts.map +1 -0
- package/dist/decorators/exception.decorators.js +242 -0
- package/dist/decorators/guard.decorators.d.ts +43 -0
- package/dist/decorators/guard.decorators.d.ts.map +1 -0
- package/dist/decorators/guard.decorators.js +67 -0
- package/dist/decorators/http.decorators.d.ts +130 -0
- package/dist/decorators/http.decorators.d.ts.map +1 -0
- package/dist/decorators/http.decorators.js +209 -0
- package/dist/decorators/interceptor.advanced.d.ts +93 -0
- package/dist/decorators/interceptor.advanced.d.ts.map +1 -0
- package/dist/decorators/interceptor.advanced.js +228 -0
- package/dist/decorators/interceptor.decorators.d.ts +91 -0
- package/dist/decorators/interceptor.decorators.d.ts.map +1 -0
- package/dist/decorators/interceptor.decorators.js +163 -0
- package/dist/decorators/param.decorators.d.ts +144 -0
- package/dist/decorators/param.decorators.d.ts.map +1 -0
- package/dist/decorators/param.decorators.js +205 -0
- package/dist/decorators/pipe.advanced.d.ts +125 -0
- package/dist/decorators/pipe.advanced.d.ts.map +1 -0
- package/dist/decorators/pipe.advanced.js +263 -0
- package/dist/decorators/pipe.decorators.d.ts +226 -0
- package/dist/decorators/pipe.decorators.d.ts.map +1 -0
- package/dist/decorators/pipe.decorators.js +420 -0
- package/dist/dto.d.ts +83 -0
- package/dist/dto.d.ts.map +1 -0
- package/dist/dto.js +88 -0
- package/dist/factory.d.ts +76 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +410 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/pipes/validation.pipe.d.ts +91 -0
- package/dist/pipes/validation.pipe.d.ts.map +1 -0
- package/dist/pipes/validation.pipe.js +163 -0
- package/package.json +68 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
/**
|
|
3
|
+
* Advanced Interceptors for WynkJS Framework
|
|
4
|
+
* Additional interceptors for common use cases
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Response Interceptor - Wraps all responses in a standard format
|
|
8
|
+
* @example
|
|
9
|
+
* @UseInterceptors(ResponseInterceptor)
|
|
10
|
+
* @Controller('/api')
|
|
11
|
+
* export class ApiController {}
|
|
12
|
+
*/
|
|
13
|
+
export class ResponseInterceptor {
|
|
14
|
+
async intercept(context, next) {
|
|
15
|
+
const request = context.getRequest();
|
|
16
|
+
const startTime = Date.now();
|
|
17
|
+
try {
|
|
18
|
+
const data = await next.handle();
|
|
19
|
+
const duration = Date.now() - startTime;
|
|
20
|
+
return {
|
|
21
|
+
success: true,
|
|
22
|
+
statusCode: 200,
|
|
23
|
+
data,
|
|
24
|
+
meta: {
|
|
25
|
+
timestamp: new Date().toISOString(),
|
|
26
|
+
duration: `${duration}ms`,
|
|
27
|
+
path: request.url,
|
|
28
|
+
method: request.method,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
const duration = Date.now() - startTime;
|
|
34
|
+
return {
|
|
35
|
+
success: false,
|
|
36
|
+
statusCode: error.statusCode || 500,
|
|
37
|
+
error: {
|
|
38
|
+
message: error.message,
|
|
39
|
+
code: error.code,
|
|
40
|
+
},
|
|
41
|
+
meta: {
|
|
42
|
+
timestamp: new Date().toISOString(),
|
|
43
|
+
duration: `${duration}ms`,
|
|
44
|
+
path: request.url,
|
|
45
|
+
method: request.method,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Error Handling Interceptor - Catches and transforms errors
|
|
53
|
+
* @example
|
|
54
|
+
* @UseInterceptors(ErrorHandlingInterceptor)
|
|
55
|
+
* @Get()
|
|
56
|
+
* async getData() {}
|
|
57
|
+
*/
|
|
58
|
+
export class ErrorHandlingInterceptor {
|
|
59
|
+
async intercept(context, next) {
|
|
60
|
+
try {
|
|
61
|
+
return await next.handle();
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
console.error(`❌ Error in ${context.getRequest().method} ${context.getRequest().url}:`, error);
|
|
65
|
+
// Transform error to a consistent format
|
|
66
|
+
throw {
|
|
67
|
+
statusCode: error.statusCode || 500,
|
|
68
|
+
message: error.message || "Internal server error",
|
|
69
|
+
error: error.name || "Error",
|
|
70
|
+
timestamp: new Date().toISOString(),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Compression Interceptor - Simulates response compression metadata
|
|
77
|
+
* @example
|
|
78
|
+
* @UseInterceptors(CompressionInterceptor)
|
|
79
|
+
* @Get()
|
|
80
|
+
* async getLargeData() {}
|
|
81
|
+
*/
|
|
82
|
+
export class CompressionInterceptor {
|
|
83
|
+
threshold;
|
|
84
|
+
constructor(threshold = 1024) {
|
|
85
|
+
this.threshold = threshold;
|
|
86
|
+
}
|
|
87
|
+
async intercept(context, next) {
|
|
88
|
+
const data = await next.handle();
|
|
89
|
+
const dataSize = JSON.stringify(data).length;
|
|
90
|
+
if (dataSize > this.threshold) {
|
|
91
|
+
// In a real implementation, you'd compress the data here
|
|
92
|
+
console.log(`📦 Response size: ${dataSize} bytes (compression recommended)`);
|
|
93
|
+
}
|
|
94
|
+
return data;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Rate Limit Interceptor - Basic rate limiting
|
|
99
|
+
* @example
|
|
100
|
+
* @UseInterceptors(new RateLimitInterceptor(100, 60000))
|
|
101
|
+
* @Post()
|
|
102
|
+
* async create() {}
|
|
103
|
+
*/
|
|
104
|
+
export class RateLimitInterceptor {
|
|
105
|
+
maxRequests;
|
|
106
|
+
windowMs;
|
|
107
|
+
requests = new Map();
|
|
108
|
+
constructor(maxRequests = 100, windowMs = 60000) {
|
|
109
|
+
this.maxRequests = maxRequests;
|
|
110
|
+
this.windowMs = windowMs;
|
|
111
|
+
}
|
|
112
|
+
async intercept(context, next) {
|
|
113
|
+
const request = context.getRequest();
|
|
114
|
+
const clientIp = request.headers?.get?.("x-forwarded-for") || "unknown";
|
|
115
|
+
const now = Date.now();
|
|
116
|
+
// Get or create request history for this IP
|
|
117
|
+
let history = this.requests.get(clientIp) || [];
|
|
118
|
+
// Filter out old requests outside the window
|
|
119
|
+
history = history.filter((timestamp) => now - timestamp < this.windowMs);
|
|
120
|
+
// Check if rate limit exceeded
|
|
121
|
+
if (history.length >= this.maxRequests) {
|
|
122
|
+
throw {
|
|
123
|
+
statusCode: 429,
|
|
124
|
+
message: "Too many requests",
|
|
125
|
+
error: "Rate limit exceeded",
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// Add current request
|
|
129
|
+
history.push(now);
|
|
130
|
+
this.requests.set(clientIp, history);
|
|
131
|
+
return next.handle();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* CORS Interceptor - Add CORS headers to responses
|
|
136
|
+
* @example
|
|
137
|
+
* @UseInterceptors(CorsInterceptor)
|
|
138
|
+
* @Controller('/api')
|
|
139
|
+
* export class ApiController {}
|
|
140
|
+
*/
|
|
141
|
+
export class CorsInterceptor {
|
|
142
|
+
options;
|
|
143
|
+
constructor(options = {}) {
|
|
144
|
+
this.options = options;
|
|
145
|
+
}
|
|
146
|
+
async intercept(context, next) {
|
|
147
|
+
const response = context.getResponse();
|
|
148
|
+
const origin = this.options.origin || "*";
|
|
149
|
+
const methods = this.options.methods || [
|
|
150
|
+
"GET",
|
|
151
|
+
"POST",
|
|
152
|
+
"PUT",
|
|
153
|
+
"DELETE",
|
|
154
|
+
"PATCH",
|
|
155
|
+
];
|
|
156
|
+
// Set CORS headers
|
|
157
|
+
if (response.headers) {
|
|
158
|
+
response.headers.set("Access-Control-Allow-Origin", Array.isArray(origin) ? origin[0] : origin);
|
|
159
|
+
response.headers.set("Access-Control-Allow-Methods", methods.join(", "));
|
|
160
|
+
response.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
161
|
+
if (this.options.credentials) {
|
|
162
|
+
response.headers.set("Access-Control-Allow-Credentials", "true");
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return next.handle();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Sanitize Interceptor - Sanitizes response data
|
|
170
|
+
* @example
|
|
171
|
+
* @UseInterceptors(SanitizeInterceptor)
|
|
172
|
+
* @Get('/users')
|
|
173
|
+
* async getUsers() {}
|
|
174
|
+
*/
|
|
175
|
+
export class SanitizeInterceptor {
|
|
176
|
+
fieldsToRemove;
|
|
177
|
+
constructor(fieldsToRemove = ["password", "secret", "token"]) {
|
|
178
|
+
this.fieldsToRemove = fieldsToRemove;
|
|
179
|
+
}
|
|
180
|
+
async intercept(context, next) {
|
|
181
|
+
const data = await next.handle();
|
|
182
|
+
return this.sanitize(data);
|
|
183
|
+
}
|
|
184
|
+
sanitize(data) {
|
|
185
|
+
if (Array.isArray(data)) {
|
|
186
|
+
return data.map((item) => this.sanitize(item));
|
|
187
|
+
}
|
|
188
|
+
if (data && typeof data === "object") {
|
|
189
|
+
const sanitized = {};
|
|
190
|
+
for (const key in data) {
|
|
191
|
+
if (!this.fieldsToRemove.includes(key)) {
|
|
192
|
+
sanitized[key] = this.sanitize(data[key]);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return sanitized;
|
|
196
|
+
}
|
|
197
|
+
return data;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Pagination Interceptor - Adds pagination metadata
|
|
202
|
+
* @example
|
|
203
|
+
* @UseInterceptors(PaginationInterceptor)
|
|
204
|
+
* @Get('/users')
|
|
205
|
+
* async getUsers(@Query('page') page: number, @Query('limit') limit: number) {}
|
|
206
|
+
*/
|
|
207
|
+
export class PaginationInterceptor {
|
|
208
|
+
async intercept(context, next) {
|
|
209
|
+
const request = context.getRequest();
|
|
210
|
+
const url = new URL(request.url, `http://${request.headers?.get?.("host")}`);
|
|
211
|
+
const page = parseInt(url.searchParams.get("page") || "1");
|
|
212
|
+
const limit = parseInt(url.searchParams.get("limit") || "10");
|
|
213
|
+
const data = await next.handle();
|
|
214
|
+
// If data is an array, add pagination
|
|
215
|
+
if (Array.isArray(data)) {
|
|
216
|
+
return {
|
|
217
|
+
items: data,
|
|
218
|
+
pagination: {
|
|
219
|
+
page,
|
|
220
|
+
limit,
|
|
221
|
+
total: data.length,
|
|
222
|
+
hasMore: data.length >= limit,
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
return data;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { ExecutionContext } from "./guard.decorators";
|
|
3
|
+
/**
|
|
4
|
+
* Interceptor Decorators and Interfaces for WynkJS Framework
|
|
5
|
+
* Interceptors for request/response transformation
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Call handler interface for interceptors
|
|
9
|
+
*/
|
|
10
|
+
export interface CallHandler<T = any> {
|
|
11
|
+
handle(): Promise<T>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* WynkInterceptor interface - All interceptors must implement this
|
|
15
|
+
*/
|
|
16
|
+
export interface WynkInterceptor {
|
|
17
|
+
intercept(context: ExecutionContext, next: CallHandler): Promise<any>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* @UseInterceptors decorator - Apply interceptors to routes or controllers
|
|
21
|
+
* @param interceptors Interceptor classes to apply
|
|
22
|
+
* @example
|
|
23
|
+
* @UseInterceptors(LoggingInterceptor, TransformInterceptor)
|
|
24
|
+
* @Controller('/users')
|
|
25
|
+
* export class UserController {}
|
|
26
|
+
*
|
|
27
|
+
* @Get()
|
|
28
|
+
* @UseInterceptors(CacheInterceptor)
|
|
29
|
+
* findAll() {}
|
|
30
|
+
*/
|
|
31
|
+
export declare function UseInterceptors(...interceptors: (Function | WynkInterceptor)[]): MethodDecorator & ClassDecorator;
|
|
32
|
+
/**
|
|
33
|
+
* Helper function to execute interceptors
|
|
34
|
+
*/
|
|
35
|
+
export declare function executeInterceptors(interceptors: (Function | WynkInterceptor)[], context: ExecutionContext, handler: () => Promise<any>): Promise<any>;
|
|
36
|
+
/**
|
|
37
|
+
* Common interceptor utilities
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Transform interceptor decorator - Wraps response in a specific structure
|
|
41
|
+
* @param transformFn Transformation function
|
|
42
|
+
* @example
|
|
43
|
+
* @UseInterceptors(TransformInterceptor)
|
|
44
|
+
* @Get()
|
|
45
|
+
* async getData() {
|
|
46
|
+
* return { data: 'value' };
|
|
47
|
+
* }
|
|
48
|
+
* // Response: { data: { data: 'value' }, statusCode: 200 }
|
|
49
|
+
*/
|
|
50
|
+
export declare class TransformInterceptor implements WynkInterceptor {
|
|
51
|
+
private transformFn?;
|
|
52
|
+
constructor(transformFn?: ((data: any) => any) | undefined);
|
|
53
|
+
intercept(context: ExecutionContext, next: CallHandler): Promise<any>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Timeout interceptor - Adds timeout to requests
|
|
57
|
+
* @param timeout Timeout in milliseconds
|
|
58
|
+
* @example
|
|
59
|
+
* @UseInterceptors(new TimeoutInterceptor(5000))
|
|
60
|
+
* @Get()
|
|
61
|
+
* async getData() {}
|
|
62
|
+
*/
|
|
63
|
+
export declare class TimeoutInterceptor implements WynkInterceptor {
|
|
64
|
+
private timeout;
|
|
65
|
+
constructor(timeout?: number);
|
|
66
|
+
intercept(context: ExecutionContext, next: CallHandler): Promise<any>;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Cache interceptor - Caches responses
|
|
70
|
+
* @example
|
|
71
|
+
* @UseInterceptors(CacheInterceptor)
|
|
72
|
+
* @Get()
|
|
73
|
+
* async getData() {}
|
|
74
|
+
*/
|
|
75
|
+
export declare class CacheInterceptor implements WynkInterceptor {
|
|
76
|
+
private cache;
|
|
77
|
+
private ttl;
|
|
78
|
+
constructor(ttl?: number);
|
|
79
|
+
intercept(context: ExecutionContext, next: CallHandler): Promise<any>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Logging interceptor - Logs requests and responses
|
|
83
|
+
* @example
|
|
84
|
+
* @UseInterceptors(LoggingInterceptor)
|
|
85
|
+
* @Controller()
|
|
86
|
+
* export class AppController {}
|
|
87
|
+
*/
|
|
88
|
+
export declare class LoggingInterceptor implements WynkInterceptor {
|
|
89
|
+
intercept(context: ExecutionContext, next: CallHandler): Promise<any>;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=interceptor.decorators.d.ts.map
|
|
@@ -0,0 +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,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD;;;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,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CACvE;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,gBAAgB,EACzB,OAAO,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GAC1B,OAAO,CAAC,GAAG,CAAC,CA+Bd;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,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC;CAa5E;AAED;;;;;;;GAOG;AACH,qBAAa,kBAAmB,YAAW,eAAe;IAC5C,OAAO,CAAC,OAAO;gBAAP,OAAO,GAAE,MAAa;IAEpC,SAAS,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC;CAQ5E;AAED;;;;;;GAMG;AACH,qBAAa,gBAAiB,YAAW,eAAe;IACtD,OAAO,CAAC,KAAK,CAAuD;IACpE,OAAO,CAAC,GAAG,CAAS;gBAER,GAAG,GAAE,MAAc;IAIzB,SAAS,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC;CAgB5E;AAED;;;;;;GAMG;AACH,qBAAa,kBAAmB,YAAW,eAAe;IAClD,SAAS,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC;CAqB5E"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
/**
|
|
3
|
+
* @UseInterceptors decorator - Apply interceptors to routes or controllers
|
|
4
|
+
* @param interceptors Interceptor classes to apply
|
|
5
|
+
* @example
|
|
6
|
+
* @UseInterceptors(LoggingInterceptor, TransformInterceptor)
|
|
7
|
+
* @Controller('/users')
|
|
8
|
+
* export class UserController {}
|
|
9
|
+
*
|
|
10
|
+
* @Get()
|
|
11
|
+
* @UseInterceptors(CacheInterceptor)
|
|
12
|
+
* findAll() {}
|
|
13
|
+
*/
|
|
14
|
+
export function UseInterceptors(...interceptors) {
|
|
15
|
+
return (target, propertyKey, descriptor) => {
|
|
16
|
+
if (propertyKey && descriptor) {
|
|
17
|
+
// Method decorator
|
|
18
|
+
const existing = Reflect.getMetadata("interceptors", target, propertyKey) || [];
|
|
19
|
+
Reflect.defineMetadata("interceptors", [...existing, ...interceptors], target, propertyKey);
|
|
20
|
+
return descriptor;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
// Class decorator
|
|
24
|
+
const existing = Reflect.getMetadata("interceptors", target) || [];
|
|
25
|
+
Reflect.defineMetadata("interceptors", [...existing, ...interceptors], target);
|
|
26
|
+
return target;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Helper function to execute interceptors
|
|
32
|
+
*/
|
|
33
|
+
export async function executeInterceptors(interceptors, context, handler) {
|
|
34
|
+
// Build interceptor chain from last to first
|
|
35
|
+
let next = {
|
|
36
|
+
handle: async () => handler(),
|
|
37
|
+
};
|
|
38
|
+
// Apply interceptors in reverse order
|
|
39
|
+
for (let i = interceptors.length - 1; i >= 0; i--) {
|
|
40
|
+
const interceptor = interceptors[i];
|
|
41
|
+
const currentNext = next;
|
|
42
|
+
let interceptorInstance;
|
|
43
|
+
if (typeof interceptor === "function") {
|
|
44
|
+
interceptorInstance = new interceptor();
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
interceptorInstance = interceptor;
|
|
48
|
+
}
|
|
49
|
+
if (!interceptorInstance.intercept) {
|
|
50
|
+
throw new Error(`Interceptor must implement WynkInterceptor interface`);
|
|
51
|
+
}
|
|
52
|
+
// Create new call handler that wraps the previous one
|
|
53
|
+
next = {
|
|
54
|
+
handle: async () => {
|
|
55
|
+
return interceptorInstance.intercept(context, currentNext);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return next.handle();
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Common interceptor utilities
|
|
63
|
+
*/
|
|
64
|
+
/**
|
|
65
|
+
* Transform interceptor decorator - Wraps response in a specific structure
|
|
66
|
+
* @param transformFn Transformation function
|
|
67
|
+
* @example
|
|
68
|
+
* @UseInterceptors(TransformInterceptor)
|
|
69
|
+
* @Get()
|
|
70
|
+
* async getData() {
|
|
71
|
+
* return { data: 'value' };
|
|
72
|
+
* }
|
|
73
|
+
* // Response: { data: { data: 'value' }, statusCode: 200 }
|
|
74
|
+
*/
|
|
75
|
+
export class TransformInterceptor {
|
|
76
|
+
transformFn;
|
|
77
|
+
constructor(transformFn) {
|
|
78
|
+
this.transformFn = transformFn;
|
|
79
|
+
}
|
|
80
|
+
async intercept(context, next) {
|
|
81
|
+
const data = await next.handle();
|
|
82
|
+
if (this.transformFn) {
|
|
83
|
+
return this.transformFn(data);
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
data,
|
|
87
|
+
statusCode: context.getResponse().status || 200,
|
|
88
|
+
timestamp: new Date().toISOString(),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Timeout interceptor - Adds timeout to requests
|
|
94
|
+
* @param timeout Timeout in milliseconds
|
|
95
|
+
* @example
|
|
96
|
+
* @UseInterceptors(new TimeoutInterceptor(5000))
|
|
97
|
+
* @Get()
|
|
98
|
+
* async getData() {}
|
|
99
|
+
*/
|
|
100
|
+
export class TimeoutInterceptor {
|
|
101
|
+
timeout;
|
|
102
|
+
constructor(timeout = 5000) {
|
|
103
|
+
this.timeout = timeout;
|
|
104
|
+
}
|
|
105
|
+
async intercept(context, next) {
|
|
106
|
+
return Promise.race([
|
|
107
|
+
next.handle(),
|
|
108
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("Request timeout")), this.timeout)),
|
|
109
|
+
]);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Cache interceptor - Caches responses
|
|
114
|
+
* @example
|
|
115
|
+
* @UseInterceptors(CacheInterceptor)
|
|
116
|
+
* @Get()
|
|
117
|
+
* async getData() {}
|
|
118
|
+
*/
|
|
119
|
+
export class CacheInterceptor {
|
|
120
|
+
cache = new Map();
|
|
121
|
+
ttl;
|
|
122
|
+
constructor(ttl = 60000) {
|
|
123
|
+
this.ttl = ttl;
|
|
124
|
+
}
|
|
125
|
+
async intercept(context, next) {
|
|
126
|
+
const request = context.getRequest();
|
|
127
|
+
const cacheKey = `${request.method}:${request.url}`;
|
|
128
|
+
// Check cache
|
|
129
|
+
const cached = this.cache.get(cacheKey);
|
|
130
|
+
if (cached && Date.now() - cached.timestamp < this.ttl) {
|
|
131
|
+
return cached.data;
|
|
132
|
+
}
|
|
133
|
+
// Execute handler and cache result
|
|
134
|
+
const data = await next.handle();
|
|
135
|
+
this.cache.set(cacheKey, { data, timestamp: Date.now() });
|
|
136
|
+
return data;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Logging interceptor - Logs requests and responses
|
|
141
|
+
* @example
|
|
142
|
+
* @UseInterceptors(LoggingInterceptor)
|
|
143
|
+
* @Controller()
|
|
144
|
+
* export class AppController {}
|
|
145
|
+
*/
|
|
146
|
+
export class LoggingInterceptor {
|
|
147
|
+
async intercept(context, next) {
|
|
148
|
+
const request = context.getRequest();
|
|
149
|
+
const startTime = Date.now();
|
|
150
|
+
console.log(`📥 ${request.method} ${request.url} - Started`);
|
|
151
|
+
try {
|
|
152
|
+
const data = await next.handle();
|
|
153
|
+
const duration = Date.now() - startTime;
|
|
154
|
+
console.log(`📤 ${request.method} ${request.url} - Completed in ${duration}ms`);
|
|
155
|
+
return data;
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
const duration = Date.now() - startTime;
|
|
159
|
+
console.log(`❌ ${request.method} ${request.url} - Failed in ${duration}ms`);
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
/**
|
|
3
|
+
* Parameter Decorators for ElysiaJS Framework
|
|
4
|
+
* Extract data from request context
|
|
5
|
+
*/
|
|
6
|
+
export type ParamType = "body" | "param" | "query" | "headers" | "request" | "response" | "context" | "user" | "file" | "files";
|
|
7
|
+
export interface ParamMetadata {
|
|
8
|
+
index: number;
|
|
9
|
+
type: ParamType;
|
|
10
|
+
data?: string;
|
|
11
|
+
pipes?: any[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* @Body decorator - Extracts request body
|
|
15
|
+
* @param property Optional property name to extract from body
|
|
16
|
+
* @param pipes Optional validation/transformation pipes
|
|
17
|
+
* @example
|
|
18
|
+
* @Post()
|
|
19
|
+
* create(@Body() dto: CreateDto) {}
|
|
20
|
+
*
|
|
21
|
+
* @Post()
|
|
22
|
+
* update(@Body('name') name: string) {}
|
|
23
|
+
*/
|
|
24
|
+
export declare function Body(property?: string, ...pipes: any[]): ParameterDecorator;
|
|
25
|
+
/**
|
|
26
|
+
* @Param decorator - Extracts route parameters
|
|
27
|
+
* @param property Optional parameter name
|
|
28
|
+
* @param pipes Optional validation/transformation pipes
|
|
29
|
+
* @example
|
|
30
|
+
* @Get('/:id')
|
|
31
|
+
* findOne(@Param('id') id: string) {}
|
|
32
|
+
*
|
|
33
|
+
* @Get('/:id')
|
|
34
|
+
* findOne(@Param() params: any) {}
|
|
35
|
+
*/
|
|
36
|
+
export declare function Param(property?: string, ...pipes: any[]): ParameterDecorator;
|
|
37
|
+
/**
|
|
38
|
+
* @Query decorator - Extracts query parameters
|
|
39
|
+
* @param property Optional query parameter name
|
|
40
|
+
* @param pipes Optional validation/transformation pipes
|
|
41
|
+
* @example
|
|
42
|
+
* @Get()
|
|
43
|
+
* findAll(@Query('page') page: number) {}
|
|
44
|
+
*
|
|
45
|
+
* @Get()
|
|
46
|
+
* findAll(@Query() query: QueryDto) {}
|
|
47
|
+
*/
|
|
48
|
+
export declare function Query(property?: string, ...pipes: any[]): ParameterDecorator;
|
|
49
|
+
/**
|
|
50
|
+
* @Headers decorator - Extracts request headers
|
|
51
|
+
* @param property Optional header name
|
|
52
|
+
* @example
|
|
53
|
+
* @Get()
|
|
54
|
+
* getData(@Headers('authorization') auth: string) {}
|
|
55
|
+
*
|
|
56
|
+
* @Get()
|
|
57
|
+
* getData(@Headers() headers: any) {}
|
|
58
|
+
*/
|
|
59
|
+
export declare function Headers(property?: string): ParameterDecorator;
|
|
60
|
+
/**
|
|
61
|
+
* @Req decorator - Injects full request object
|
|
62
|
+
* @example
|
|
63
|
+
* @Get()
|
|
64
|
+
* getData(@Req() request: Request) {}
|
|
65
|
+
*/
|
|
66
|
+
export declare function Req(): ParameterDecorator;
|
|
67
|
+
/**
|
|
68
|
+
* @Request decorator - Alias for @Req
|
|
69
|
+
*/
|
|
70
|
+
export declare const Request: typeof Req;
|
|
71
|
+
/**
|
|
72
|
+
* @Res decorator - Injects response object
|
|
73
|
+
* @example
|
|
74
|
+
* @Get()
|
|
75
|
+
* getData(@Res() response: Response) {}
|
|
76
|
+
*/
|
|
77
|
+
export declare function Res(): ParameterDecorator;
|
|
78
|
+
/**
|
|
79
|
+
* @Response decorator - Alias for @Res
|
|
80
|
+
*/
|
|
81
|
+
export declare const Response: typeof Res;
|
|
82
|
+
/**
|
|
83
|
+
* @Context decorator - Injects full Elysia context
|
|
84
|
+
* @example
|
|
85
|
+
* @Get()
|
|
86
|
+
* getData(@Context() ctx: any) {}
|
|
87
|
+
*/
|
|
88
|
+
export declare function Context(): ParameterDecorator;
|
|
89
|
+
/**
|
|
90
|
+
* @User decorator - Extracts user from context (after authentication)
|
|
91
|
+
* @param property Optional user property to extract
|
|
92
|
+
* @example
|
|
93
|
+
* @Get('/profile')
|
|
94
|
+
* @UseGuards(AuthGuard)
|
|
95
|
+
* getProfile(@User() user: UserEntity) {}
|
|
96
|
+
*
|
|
97
|
+
* @Get('/profile')
|
|
98
|
+
* getProfile(@User('id') userId: string) {}
|
|
99
|
+
*/
|
|
100
|
+
export declare function User(property?: string): ParameterDecorator;
|
|
101
|
+
/**
|
|
102
|
+
* @UploadedFile decorator - Extracts uploaded file
|
|
103
|
+
* @example
|
|
104
|
+
* @Post('/upload')
|
|
105
|
+
* uploadFile(@UploadedFile() file: File) {}
|
|
106
|
+
*/
|
|
107
|
+
export declare function UploadedFile(): ParameterDecorator;
|
|
108
|
+
/**
|
|
109
|
+
* @UploadedFiles decorator - Extracts multiple uploaded files
|
|
110
|
+
* @example
|
|
111
|
+
* @Post('/upload-multiple')
|
|
112
|
+
* uploadFiles(@UploadedFiles() files: File[]) {}
|
|
113
|
+
*/
|
|
114
|
+
export declare function UploadedFiles(): ParameterDecorator;
|
|
115
|
+
/**
|
|
116
|
+
* @Ip decorator - Extracts client IP address
|
|
117
|
+
* @example
|
|
118
|
+
* @Get()
|
|
119
|
+
* getData(@Ip() ip: string) {}
|
|
120
|
+
*/
|
|
121
|
+
export declare function Ip(): ParameterDecorator;
|
|
122
|
+
/**
|
|
123
|
+
* @Session decorator - Extracts session data
|
|
124
|
+
* @param property Optional session property name
|
|
125
|
+
* @example
|
|
126
|
+
* @Get()
|
|
127
|
+
* getData(@Session() session: any) {}
|
|
128
|
+
*
|
|
129
|
+
* @Get()
|
|
130
|
+
* getData(@Session('userId') userId: string) {}
|
|
131
|
+
*/
|
|
132
|
+
export declare function Session(property?: string): ParameterDecorator;
|
|
133
|
+
/**
|
|
134
|
+
* @HostParam decorator - Extracts subdomain parameters
|
|
135
|
+
* @param property Host parameter name
|
|
136
|
+
* @example
|
|
137
|
+
* @Controller({ host: ':account.example.com' })
|
|
138
|
+
* export class AccountController {
|
|
139
|
+
* @Get()
|
|
140
|
+
* getData(@HostParam('account') account: string) {}
|
|
141
|
+
* }
|
|
142
|
+
*/
|
|
143
|
+
export declare function HostParam(property: string): ParameterDecorator;
|
|
144
|
+
//# sourceMappingURL=param.decorators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"param.decorators.d.ts","sourceRoot":"","sources":["../../core/decorators/param.decorators.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B;;;GAGG;AAEH,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,OAAO,GACP,OAAO,GACP,SAAS,GACT,SAAS,GACT,UAAU,GACV,SAAS,GACT,MAAM,GACN,MAAM,GACN,OAAO,CAAC;AAEZ,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;CACf;AA2BD;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,GAAG,EAAE,GAAG,kBAAkB,CAE3E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,GAAG,EAAE,GAAG,kBAAkB,CAE5E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,GAAG,EAAE,GAAG,kBAAkB,CAE5E;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAE7D;AAED;;;;;GAKG;AACH,wBAAgB,GAAG,IAAI,kBAAkB,CAExC;AAED;;GAEG;AACH,eAAO,MAAM,OAAO,YAAM,CAAC;AAE3B;;;;;GAKG;AACH,wBAAgB,GAAG,IAAI,kBAAkB,CAExC;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ,YAAM,CAAC;AAE5B;;;;;GAKG;AACH,wBAAgB,OAAO,IAAI,kBAAkB,CAE5C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAE1D;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,kBAAkB,CAEjD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,kBAAkB,CAElD;AAED;;;;;GAKG;AACH,wBAAgB,EAAE,IAAI,kBAAkB,CAmBvC;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAmB7D;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAmB9D"}
|