wynkjs 1.0.7 → 1.0.9
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 +76 -0
- package/dist/common/http-status.enum.d.ts +129 -0
- package/dist/common/http-status.enum.js +135 -0
- package/dist/cors.d.ts +0 -1
- package/dist/cors.js +2 -2
- package/dist/database.d.ts +0 -1
- package/dist/decorators/database.decorators.d.ts +0 -1
- package/dist/decorators/database.decorators.js +2 -2
- package/dist/decorators/di.decorators.d.ts +13 -0
- package/dist/decorators/di.decorators.js +28 -0
- package/dist/decorators/exception.decorators.d.ts +34 -1
- package/dist/decorators/exception.decorators.js +44 -6
- package/dist/decorators/formatter.decorators.d.ts +0 -1
- package/dist/decorators/guard.decorators.d.ts +22 -3
- package/dist/decorators/guard.decorators.js +1 -0
- package/dist/decorators/http.decorators.d.ts +30 -1
- package/dist/decorators/http.decorators.js +25 -4
- package/dist/decorators/interceptor.advanced.d.ts +0 -1
- package/dist/decorators/interceptor.decorators.d.ts +40 -3
- package/dist/decorators/metadata.decorators.d.ts +71 -0
- package/dist/decorators/metadata.decorators.js +134 -0
- package/dist/decorators/param.decorators.d.ts +27 -2
- package/dist/decorators/pipe.advanced.d.ts +19 -26
- package/dist/decorators/pipe.advanced.js +84 -54
- package/dist/decorators/pipe.decorators.d.ts +76 -12
- package/dist/decorators/pipe.decorators.js +55 -8
- package/dist/dto.d.ts +0 -1
- package/dist/factory.d.ts +270 -20
- package/dist/factory.js +284 -68
- package/dist/filters/exception.filters.d.ts +0 -1
- package/dist/filters/exception.filters.js +3 -3
- package/dist/global-prefix.d.ts +2 -3
- package/dist/global-prefix.js +4 -6
- package/dist/index.d.ts +13 -1
- package/dist/index.js +13 -0
- package/dist/interfaces/interceptor.interface.d.ts +0 -1
- package/dist/interfaces/lifecycle.interface.d.ts +53 -0
- package/dist/interfaces/lifecycle.interface.js +1 -0
- package/dist/module.d.ts +53 -0
- package/dist/module.js +35 -0
- package/dist/pipes/validation.pipe.d.ts +1 -2
- package/dist/pipes/validation.pipe.js +1 -1
- package/dist/plugins/compression.d.ts +0 -1
- package/dist/plugins/compression.js +24 -9
- package/dist/request.d.ts +126 -0
- package/dist/request.js +214 -0
- package/dist/response.d.ts +128 -0
- package/dist/response.js +261 -0
- package/dist/schema-registry.d.ts +0 -1
- package/dist/testing/index.d.ts +0 -1
- package/dist/testing/test-utils.d.ts +0 -1
- package/dist/ultra-optimized-handler.d.ts +0 -1
- package/dist/ultra-optimized-handler.js +44 -4
- package/package.json +18 -6
- package/dist/cors.d.ts.map +0 -1
- package/dist/database.d.ts.map +0 -1
- package/dist/decorators/database.decorators.d.ts.map +0 -1
- package/dist/decorators/exception.advanced.d.ts +0 -457
- package/dist/decorators/exception.advanced.d.ts.map +0 -1
- package/dist/decorators/exception.advanced.js +0 -742
- package/dist/decorators/exception.decorators.d.ts.map +0 -1
- package/dist/decorators/formatter.decorators.d.ts.map +0 -1
- package/dist/decorators/guard.decorators.d.ts.map +0 -1
- package/dist/decorators/http.decorators.d.ts.map +0 -1
- package/dist/decorators/interceptor.advanced.d.ts.map +0 -1
- package/dist/decorators/interceptor.decorators.d.ts.map +0 -1
- package/dist/decorators/param.decorators.d.ts.map +0 -1
- package/dist/decorators/pipe.advanced.d.ts.map +0 -1
- package/dist/decorators/pipe.decorators.d.ts.map +0 -1
- package/dist/dto.d.ts.map +0 -1
- package/dist/factory.d.ts.map +0 -1
- package/dist/filters/exception.filters.d.ts.map +0 -1
- package/dist/global-prefix.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/interfaces/interceptor.interface.d.ts.map +0 -1
- package/dist/optimized-handler.d.ts +0 -31
- package/dist/optimized-handler.d.ts.map +0 -1
- package/dist/optimized-handler.js +0 -180
- package/dist/pipes/validation.pipe.d.ts.map +0 -1
- package/dist/plugins/compression.d.ts.map +0 -1
- package/dist/schema-registry.d.ts.map +0 -1
- package/dist/testing/index.d.ts.map +0 -1
- package/dist/testing/test-utils.d.ts.map +0 -1
- package/dist/ultra-optimized-handler.d.ts.map +0 -1
|
@@ -52,6 +52,21 @@ export function UseFilters(...filters) {
|
|
|
52
52
|
/**
|
|
53
53
|
* Built-in HTTP Exceptions
|
|
54
54
|
*/
|
|
55
|
+
/**
|
|
56
|
+
* Base HTTP exception class. All WynkJS HTTP exceptions extend this.
|
|
57
|
+
*
|
|
58
|
+
* Throw any `HttpException` subclass from a controller method — WynkJS will
|
|
59
|
+
* convert it into the appropriate HTTP response automatically.
|
|
60
|
+
*
|
|
61
|
+
* @param message - Human-readable error description sent in the response body.
|
|
62
|
+
* @param statusCode - HTTP status code (e.g. `404`, `500`).
|
|
63
|
+
* @param error - Short error category string (e.g. `'Not Found'`). Optional.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* throw new HttpException('Custom error', 418);
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
55
70
|
export class HttpException extends Error {
|
|
56
71
|
message;
|
|
57
72
|
statusCode;
|
|
@@ -77,66 +92,79 @@ export class HttpException extends Error {
|
|
|
77
92
|
};
|
|
78
93
|
}
|
|
79
94
|
}
|
|
95
|
+
/** Thrown when the request is malformed or contains invalid data (HTTP 400). */
|
|
80
96
|
export class BadRequestException extends HttpException {
|
|
81
97
|
constructor(message = "Bad Request") {
|
|
82
98
|
super(message, 400, "Bad Request");
|
|
83
99
|
}
|
|
84
100
|
}
|
|
101
|
+
/** Thrown when the request lacks valid authentication credentials (HTTP 401). */
|
|
85
102
|
export class UnauthorizedException extends HttpException {
|
|
86
103
|
constructor(message = "Unauthorized") {
|
|
87
104
|
super(message, 401, "Unauthorized");
|
|
88
105
|
}
|
|
89
106
|
}
|
|
107
|
+
/** Thrown when the authenticated user does not have permission (HTTP 403). */
|
|
90
108
|
export class ForbiddenException extends HttpException {
|
|
91
109
|
constructor(message = "Forbidden") {
|
|
92
110
|
super(message, 403, "Forbidden");
|
|
93
111
|
}
|
|
94
112
|
}
|
|
113
|
+
/** Thrown when the requested resource does not exist (HTTP 404). */
|
|
95
114
|
export class NotFoundException extends HttpException {
|
|
96
115
|
constructor(message = "Not Found") {
|
|
97
116
|
super(message, 404, "Not Found");
|
|
98
117
|
}
|
|
99
118
|
}
|
|
119
|
+
/** Thrown when the HTTP method is not supported for the endpoint (HTTP 405). */
|
|
100
120
|
export class MethodNotAllowedException extends HttpException {
|
|
101
121
|
constructor(message = "Method Not Allowed") {
|
|
102
122
|
super(message, 405, "Method Not Allowed");
|
|
103
123
|
}
|
|
104
124
|
}
|
|
125
|
+
/** Thrown when the server cannot produce a response matching the `Accept` header (HTTP 406). */
|
|
105
126
|
export class NotAcceptableException extends HttpException {
|
|
106
127
|
constructor(message = "Not Acceptable") {
|
|
107
128
|
super(message, 406, "Not Acceptable");
|
|
108
129
|
}
|
|
109
130
|
}
|
|
131
|
+
/** Thrown when the server did not receive a timely response (HTTP 408). */
|
|
110
132
|
export class RequestTimeoutException extends HttpException {
|
|
111
133
|
constructor(message = "Request Timeout") {
|
|
112
134
|
super(message, 408, "Request Timeout");
|
|
113
135
|
}
|
|
114
136
|
}
|
|
137
|
+
/** Thrown when the request conflicts with the current state of the resource (HTTP 409). */
|
|
115
138
|
export class ConflictException extends HttpException {
|
|
116
139
|
constructor(message = "Conflict") {
|
|
117
140
|
super(message, 409, "Conflict");
|
|
118
141
|
}
|
|
119
142
|
}
|
|
143
|
+
/** Thrown when a resource already exists and cannot be created again (HTTP 409). */
|
|
120
144
|
export class AlreadyExistsException extends HttpException {
|
|
121
145
|
constructor(message = "Resource Already Exists") {
|
|
122
146
|
super(message, 409, "Conflict");
|
|
123
147
|
}
|
|
124
148
|
}
|
|
149
|
+
/** Thrown when the requested resource is no longer available (HTTP 410). */
|
|
125
150
|
export class GoneException extends HttpException {
|
|
126
151
|
constructor(message = "Gone") {
|
|
127
152
|
super(message, 410, "Gone");
|
|
128
153
|
}
|
|
129
154
|
}
|
|
155
|
+
/** Thrown when the request body exceeds the server's size limit (HTTP 413). */
|
|
130
156
|
export class PayloadTooLargeException extends HttpException {
|
|
131
157
|
constructor(message = "Payload Too Large") {
|
|
132
158
|
super(message, 413, "Payload Too Large");
|
|
133
159
|
}
|
|
134
160
|
}
|
|
161
|
+
/** Thrown when the request's `Content-Type` is not supported (HTTP 415). */
|
|
135
162
|
export class UnsupportedMediaTypeException extends HttpException {
|
|
136
163
|
constructor(message = "Unsupported Media Type") {
|
|
137
164
|
super(message, 415, "Unsupported Media Type");
|
|
138
165
|
}
|
|
139
166
|
}
|
|
167
|
+
/** Thrown when the request is well-formed but cannot be processed (HTTP 422). */
|
|
140
168
|
export class UnprocessableEntityException extends HttpException {
|
|
141
169
|
constructor(message = "Unprocessable Entity") {
|
|
142
170
|
super(message, 422, "Unprocessable Entity");
|
|
@@ -167,6 +195,16 @@ export class GatewayTimeoutException extends HttpException {
|
|
|
167
195
|
super(message, 504, "Gateway Timeout");
|
|
168
196
|
}
|
|
169
197
|
}
|
|
198
|
+
export class TooManyRequestsException extends HttpException {
|
|
199
|
+
constructor(message = "Too Many Requests") {
|
|
200
|
+
super(message, 429, "Too Many Requests");
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
export class HttpVersionNotSupportedException extends HttpException {
|
|
204
|
+
constructor(message = "HTTP Version Not Supported") {
|
|
205
|
+
super(message, 505, "HTTP Version Not Supported");
|
|
206
|
+
}
|
|
207
|
+
}
|
|
170
208
|
/**
|
|
171
209
|
* Helper function to execute exception filters
|
|
172
210
|
*/
|
|
@@ -217,7 +255,7 @@ export async function executeExceptionFilters(filters, exception, context) {
|
|
|
217
255
|
*/
|
|
218
256
|
let HttpWynkExceptionFilter = class HttpWynkExceptionFilter {
|
|
219
257
|
catch(exception, context) {
|
|
220
|
-
const
|
|
258
|
+
const _response = context.getResponse();
|
|
221
259
|
const status = exception.getStatus();
|
|
222
260
|
return {
|
|
223
261
|
statusCode: status,
|
|
@@ -235,7 +273,7 @@ export { HttpWynkExceptionFilter };
|
|
|
235
273
|
*/
|
|
236
274
|
let AllExceptions = class AllExceptions {
|
|
237
275
|
catch(exception, context) {
|
|
238
|
-
const
|
|
276
|
+
const _response = context.getResponse();
|
|
239
277
|
if (exception instanceof HttpException) {
|
|
240
278
|
const status = exception.getStatus();
|
|
241
279
|
return {
|
|
@@ -276,7 +314,7 @@ export { AllExceptions };
|
|
|
276
314
|
*/
|
|
277
315
|
export class AuthenticationException {
|
|
278
316
|
catch(exception, context) {
|
|
279
|
-
const
|
|
317
|
+
const _response = context.getResponse();
|
|
280
318
|
const request = context.getRequest();
|
|
281
319
|
return {
|
|
282
320
|
statusCode: exception.statusCode,
|
|
@@ -307,7 +345,7 @@ export class AuthenticationException {
|
|
|
307
345
|
*/
|
|
308
346
|
export class AuthorizationException {
|
|
309
347
|
catch(exception, context) {
|
|
310
|
-
const
|
|
348
|
+
const _response = context.getResponse();
|
|
311
349
|
const request = context.getRequest();
|
|
312
350
|
return {
|
|
313
351
|
statusCode: exception.statusCode,
|
|
@@ -329,7 +367,7 @@ export class AuthorizationException {
|
|
|
329
367
|
*/
|
|
330
368
|
export class RateLimitException {
|
|
331
369
|
catch(exception, context) {
|
|
332
|
-
const
|
|
370
|
+
const _response = context.getResponse();
|
|
333
371
|
const request = context.getRequest();
|
|
334
372
|
// Don't catch HttpException or its subclasses
|
|
335
373
|
if (exception instanceof HttpException) {
|
|
@@ -355,7 +393,7 @@ export class RateLimitException {
|
|
|
355
393
|
*/
|
|
356
394
|
export class BusinessLogicException {
|
|
357
395
|
catch(exception, context) {
|
|
358
|
-
const
|
|
396
|
+
const _response = context.getResponse();
|
|
359
397
|
const request = context.getRequest();
|
|
360
398
|
// Don't catch HttpException or its subclasses
|
|
361
399
|
if (exception instanceof HttpException) {
|
|
@@ -4,17 +4,37 @@ import "reflect-metadata";
|
|
|
4
4
|
* Guards for route protection and authorization
|
|
5
5
|
*/
|
|
6
6
|
/**
|
|
7
|
-
* Execution context interface
|
|
7
|
+
* Execution context interface — provides typed access to the current request cycle.
|
|
8
|
+
* Passed to guards, interceptors, and exception filters.
|
|
8
9
|
*/
|
|
9
10
|
export interface ExecutionContext {
|
|
11
|
+
/** Returns the underlying request object (typed as `T`). */
|
|
10
12
|
getRequest<T = any>(): T;
|
|
13
|
+
/** Returns the underlying response/set object (typed as `T`). */
|
|
11
14
|
getResponse<T = any>(): T;
|
|
15
|
+
/** Returns the full Elysia context object (typed as `T`). */
|
|
12
16
|
getContext<T = any>(): T;
|
|
17
|
+
/** Returns the route handler function currently being invoked. */
|
|
13
18
|
getHandler(): Function;
|
|
19
|
+
/** Returns the controller class that owns the current route handler. */
|
|
14
20
|
getClass(): any;
|
|
21
|
+
/**
|
|
22
|
+
* Returns the transport type of the current request.
|
|
23
|
+
* WynkJS currently always returns `'http'`.
|
|
24
|
+
*/
|
|
25
|
+
getType(): 'http' | 'ws' | 'rpc';
|
|
15
26
|
}
|
|
16
27
|
/**
|
|
17
|
-
*
|
|
28
|
+
* Interface that all guards must implement.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* @Injectable()
|
|
32
|
+
* export class AuthGuard implements CanActivate {
|
|
33
|
+
* canActivate(context: ExecutionContext): boolean {
|
|
34
|
+
* const req = context.getRequest<Request>();
|
|
35
|
+
* return req.headers.get('authorization') !== null;
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
18
38
|
*/
|
|
19
39
|
export interface CanActivate {
|
|
20
40
|
canActivate(context: ExecutionContext): boolean | Promise<boolean>;
|
|
@@ -40,4 +60,3 @@ export declare function createExecutionContext(ctx: any, handler: Function, cont
|
|
|
40
60
|
* Helper function to execute guards
|
|
41
61
|
*/
|
|
42
62
|
export declare function executeGuards(guards: (Function | CanActivate)[], context: ExecutionContext): Promise<boolean>;
|
|
43
|
-
//# sourceMappingURL=guard.decorators.d.ts.map
|
|
@@ -4,12 +4,25 @@ import "reflect-metadata";
|
|
|
4
4
|
* RESTful route handlers with TypeScript decorators
|
|
5
5
|
* Optimized for WynkJS's performance on Bun runtime
|
|
6
6
|
*/
|
|
7
|
+
/**
|
|
8
|
+
* Options accepted by HTTP method decorators when passed as an object.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* @Post({ path: '/users', body: CreateUserDTO, query: PaginationDTO })
|
|
12
|
+
* create(@Body() dto: CreateUserType, @Query() q: PaginationQuery) {}
|
|
13
|
+
*/
|
|
7
14
|
export interface RouteOptions {
|
|
15
|
+
/** Route path (e.g. `'/'`, `'/:id'`). Defaults to `''`. */
|
|
8
16
|
path?: string;
|
|
17
|
+
/** TypeBox schema used to validate and type the request body. */
|
|
9
18
|
body?: any;
|
|
19
|
+
/** TypeBox schema used to validate route path parameters. */
|
|
10
20
|
params?: any;
|
|
21
|
+
/** TypeBox schema used to validate query string parameters. */
|
|
11
22
|
query?: any;
|
|
23
|
+
/** TypeBox schema used to validate request headers. */
|
|
12
24
|
headers?: any;
|
|
25
|
+
/** TypeBox schema describing the response shape (informational / Swagger). */
|
|
13
26
|
response?: any;
|
|
14
27
|
}
|
|
15
28
|
/**
|
|
@@ -121,6 +134,23 @@ export declare function Header(name: string, value: string): MethodDecorator;
|
|
|
121
134
|
* redirect() {}
|
|
122
135
|
*/
|
|
123
136
|
export declare function Redirect(url: string, statusCode?: number): MethodDecorator;
|
|
137
|
+
/**
|
|
138
|
+
* Server-Sent Events (SSE) decorator — registers a GET route and marks it as
|
|
139
|
+
* an SSE endpoint via metadata. Note: the caller is responsible for setting
|
|
140
|
+
* `Content-Type: text/event-stream` and streaming the response appropriately;
|
|
141
|
+
* WynkJS does not configure this automatically at this time.
|
|
142
|
+
*
|
|
143
|
+
* @param pathOrOptions Route path string or {@link RouteOptions} object.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* @Sse('/events')
|
|
148
|
+
* streamEvents() {
|
|
149
|
+
* // Set Content-Type header and return a streaming response manually
|
|
150
|
+
* }
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
export declare function Sse(pathOrOptions?: string | RouteOptions): MethodDecorator;
|
|
124
154
|
/**
|
|
125
155
|
* Use decorator - Apply middleware to controller or method
|
|
126
156
|
* Simple middleware pattern like your working code
|
|
@@ -135,4 +165,3 @@ export declare function Redirect(url: string, statusCode?: number): MethodDecora
|
|
|
135
165
|
* async findAll() {}
|
|
136
166
|
*/
|
|
137
167
|
export declare function Use(...middlewares: any[]): ClassDecorator & MethodDecorator;
|
|
138
|
-
//# sourceMappingURL=http.decorators.d.ts.map
|
|
@@ -143,13 +143,9 @@ function createRouteDecorator(method, path, options) {
|
|
|
143
143
|
methodName: propertyKey,
|
|
144
144
|
options,
|
|
145
145
|
});
|
|
146
|
-
console.log(`🔹 Storing route: ${method} ${path} on ${constructor.name}.${String(propertyKey)} (routes: ${routes.length})`);
|
|
147
146
|
Reflect.defineMetadata("routes", routes, constructor.prototype);
|
|
148
147
|
// Also store on constructor for compatibility
|
|
149
148
|
Reflect.defineMetadata("routes", routes, constructor);
|
|
150
|
-
// Verify it was stored
|
|
151
|
-
const verify = Reflect.getMetadata("routes", constructor.prototype) || [];
|
|
152
|
-
console.log(`✅ Verified ${verify.length} routes stored on ${constructor.name}.prototype`);
|
|
153
149
|
// Store method-specific metadata
|
|
154
150
|
Reflect.defineMetadata("route:method", method, target, propertyKey);
|
|
155
151
|
Reflect.defineMetadata("route:path", path, target, propertyKey);
|
|
@@ -204,6 +200,31 @@ export function Redirect(url, statusCode = 302) {
|
|
|
204
200
|
return descriptor;
|
|
205
201
|
};
|
|
206
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* Server-Sent Events (SSE) decorator — registers a GET route and marks it as
|
|
205
|
+
* an SSE endpoint via metadata. Note: the caller is responsible for setting
|
|
206
|
+
* `Content-Type: text/event-stream` and streaming the response appropriately;
|
|
207
|
+
* WynkJS does not configure this automatically at this time.
|
|
208
|
+
*
|
|
209
|
+
* @param pathOrOptions Route path string or {@link RouteOptions} object.
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```typescript
|
|
213
|
+
* @Sse('/events')
|
|
214
|
+
* streamEvents() {
|
|
215
|
+
* // Set Content-Type header and return a streaming response manually
|
|
216
|
+
* }
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
export function Sse(pathOrOptions) {
|
|
220
|
+
const path = typeof pathOrOptions === "string"
|
|
221
|
+
? pathOrOptions
|
|
222
|
+
: pathOrOptions?.path || "";
|
|
223
|
+
const options = typeof pathOrOptions === "object" && pathOrOptions !== null
|
|
224
|
+
? { ...pathOrOptions, sse: true }
|
|
225
|
+
: { sse: true };
|
|
226
|
+
return createRouteDecorator("GET", path, options);
|
|
227
|
+
}
|
|
207
228
|
/**
|
|
208
229
|
* Use decorator - Apply middleware to controller or method
|
|
209
230
|
* Simple middleware pattern like your working code
|
|
@@ -90,4 +90,3 @@ export declare class SanitizeInterceptor implements WynkInterceptor {
|
|
|
90
90
|
export declare class PaginationInterceptor implements WynkInterceptor {
|
|
91
91
|
intercept(context: InterceptorContext, next: () => Promise<any>): Promise<any>;
|
|
92
92
|
}
|
|
93
|
-
//# sourceMappingURL=interceptor.advanced.d.ts.map
|
|
@@ -6,17 +6,55 @@ type ExecutionContext = InterceptorContext;
|
|
|
6
6
|
* Interceptors for request/response transformation
|
|
7
7
|
*/
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* Provides access to the handler return value as a promise.
|
|
10
|
+
*
|
|
11
|
+
* Passed as the second argument to `WynkInterceptor.intercept()`. Call
|
|
12
|
+
* `handle()` to invoke the next interceptor in the chain or the actual route
|
|
13
|
+
* handler. You can `await` the result to inspect or transform the response.
|
|
14
|
+
*
|
|
15
|
+
* @template T - The type of value returned by the handler
|
|
10
16
|
*/
|
|
11
17
|
export interface CallHandler<T = any> {
|
|
18
|
+
/** Invoke the next interceptor or the route handler and return its result. */
|
|
12
19
|
handle(): Promise<T>;
|
|
13
20
|
}
|
|
14
21
|
/**
|
|
15
|
-
*
|
|
22
|
+
* Interface that all WynkJS interceptors must implement.
|
|
23
|
+
*
|
|
24
|
+
* Interceptors sit between the client request and the route handler. They can
|
|
25
|
+
* execute logic before AND after the handler, transform the result, catch errors,
|
|
26
|
+
* and even override the response entirely.
|
|
27
|
+
*
|
|
28
|
+
* Use `@UseInterceptors()` to apply an interceptor to a controller or route.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* import { Injectable } from "wynkjs";
|
|
33
|
+
* import { WynkInterceptor } from "wynkjs";
|
|
34
|
+
*
|
|
35
|
+
* @Injectable()
|
|
36
|
+
* export class LoggingInterceptor implements WynkInterceptor {
|
|
37
|
+
* async intercept(context: ExecutionContext, next: () => Promise<any>) {
|
|
38
|
+
* console.log("Before handler");
|
|
39
|
+
* const result = await next();
|
|
40
|
+
* console.log("After handler");
|
|
41
|
+
* return result;
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
16
45
|
*/
|
|
17
46
|
export interface WynkInterceptor {
|
|
47
|
+
/**
|
|
48
|
+
* Called for every request that passes through this interceptor.
|
|
49
|
+
*
|
|
50
|
+
* @param context - The execution context for the current request
|
|
51
|
+
* @param next - Call `next()` to invoke the next interceptor / route handler
|
|
52
|
+
* @returns The (possibly transformed) response value
|
|
53
|
+
*/
|
|
18
54
|
intercept(context: ExecutionContext, next: () => Promise<any>): Promise<any>;
|
|
19
55
|
}
|
|
56
|
+
/** NestJS-compatible generic alias for {@link WynkInterceptor}. */
|
|
57
|
+
export type NestInterceptor<T = any, R = any> = WynkInterceptor;
|
|
20
58
|
/**
|
|
21
59
|
* @UseInterceptors decorator - Apply interceptors to routes or controllers
|
|
22
60
|
* @param interceptors Interceptor classes to apply
|
|
@@ -90,4 +128,3 @@ export declare class LoggingInterceptor implements WynkInterceptor {
|
|
|
90
128
|
intercept(context: InterceptorContext, next: () => Promise<any>): Promise<any>;
|
|
91
129
|
}
|
|
92
130
|
export {};
|
|
93
|
-
//# sourceMappingURL=interceptor.decorators.d.ts.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import type { ExecutionContext } from "./guard.decorators";
|
|
3
|
+
/**
|
|
4
|
+
* Attaches custom metadata to a class or method using the reflect-metadata API.
|
|
5
|
+
* Retrieve the value at runtime via the `Reflector` class.
|
|
6
|
+
*
|
|
7
|
+
* @param metadataKey - The key under which the value is stored
|
|
8
|
+
* @param metadataValue - The value to store
|
|
9
|
+
* @returns A decorator applicable to both classes and methods
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Define a helper decorator
|
|
13
|
+
* export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
|
|
14
|
+
*
|
|
15
|
+
* // Use in controller
|
|
16
|
+
* @Roles('admin', 'editor')
|
|
17
|
+
* @Get('/secret')
|
|
18
|
+
* getSecret() {}
|
|
19
|
+
*/
|
|
20
|
+
export declare function SetMetadata<K = string, V = any>(metadataKey: K, metadataValue: V): MethodDecorator & ClassDecorator;
|
|
21
|
+
/**
|
|
22
|
+
* Reads metadata stored by `SetMetadata` across one or multiple targets.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* const reflector = new Reflector();
|
|
26
|
+
*
|
|
27
|
+
* // In a guard:
|
|
28
|
+
* const roles = reflector.getAllAndOverride<string[]>('roles', [
|
|
29
|
+
* context.getHandler(),
|
|
30
|
+
* context.getClass(),
|
|
31
|
+
* ]);
|
|
32
|
+
*/
|
|
33
|
+
export declare class Reflector {
|
|
34
|
+
get<TResult = any>(metadataKey: string, target: Function | object): TResult | undefined;
|
|
35
|
+
getAllAndOverride<TResult = any>(metadataKey: string, targets: (Function | object)[]): TResult | undefined;
|
|
36
|
+
getAllAndMerge<TResult = any>(metadataKey: string, targets: (Function | object)[]): TResult[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Composes multiple decorators into one, applying them left-to-right.
|
|
40
|
+
*
|
|
41
|
+
* @param decorators - One or more class/method/property decorators
|
|
42
|
+
* @returns A single decorator that applies all provided decorators
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* export const Auth = (...roles: string[]) => applyDecorators(
|
|
46
|
+
* SetMetadata('roles', roles),
|
|
47
|
+
* UseGuards(AuthGuard, RolesGuard),
|
|
48
|
+
* );
|
|
49
|
+
*
|
|
50
|
+
* @Get('/admin')
|
|
51
|
+
* @Auth('admin')
|
|
52
|
+
* adminOnly() {}
|
|
53
|
+
*/
|
|
54
|
+
export declare function applyDecorators(...decorators: (ClassDecorator | MethodDecorator | PropertyDecorator)[]): (target: any, key?: any, descriptor?: any) => any;
|
|
55
|
+
/**
|
|
56
|
+
* Creates a custom parameter decorator that calls `factory` to produce the
|
|
57
|
+
* injected value at request time.
|
|
58
|
+
*
|
|
59
|
+
* @param factory - Called with `(data, ctx)` where `data` is the argument passed
|
|
60
|
+
* to the decorator and `ctx` is the current `ExecutionContext`.
|
|
61
|
+
* @returns A decorator factory: `(data?) => ParameterDecorator`
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* const CurrentUser = createParamDecorator((data, ctx: ExecutionContext) => {
|
|
65
|
+
* return ctx.getRequest().user;
|
|
66
|
+
* });
|
|
67
|
+
*
|
|
68
|
+
* @Get('/profile')
|
|
69
|
+
* getProfile(@CurrentUser() user: User) {}
|
|
70
|
+
*/
|
|
71
|
+
export declare function createParamDecorator<TData = unknown>(factory: (data: TData, ctx: ExecutionContext) => any): (data?: TData) => ParameterDecorator;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
/**
|
|
3
|
+
* Attaches custom metadata to a class or method using the reflect-metadata API.
|
|
4
|
+
* Retrieve the value at runtime via the `Reflector` class.
|
|
5
|
+
*
|
|
6
|
+
* @param metadataKey - The key under which the value is stored
|
|
7
|
+
* @param metadataValue - The value to store
|
|
8
|
+
* @returns A decorator applicable to both classes and methods
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // Define a helper decorator
|
|
12
|
+
* export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
|
|
13
|
+
*
|
|
14
|
+
* // Use in controller
|
|
15
|
+
* @Roles('admin', 'editor')
|
|
16
|
+
* @Get('/secret')
|
|
17
|
+
* getSecret() {}
|
|
18
|
+
*/
|
|
19
|
+
export function SetMetadata(metadataKey, metadataValue) {
|
|
20
|
+
return (target, propertyKey, descriptor) => {
|
|
21
|
+
if (propertyKey !== undefined && descriptor !== undefined) {
|
|
22
|
+
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey);
|
|
23
|
+
return descriptor;
|
|
24
|
+
}
|
|
25
|
+
Reflect.defineMetadata(metadataKey, metadataValue, target);
|
|
26
|
+
return target;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Reads metadata stored by `SetMetadata` across one or multiple targets.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* const reflector = new Reflector();
|
|
34
|
+
*
|
|
35
|
+
* // In a guard:
|
|
36
|
+
* const roles = reflector.getAllAndOverride<string[]>('roles', [
|
|
37
|
+
* context.getHandler(),
|
|
38
|
+
* context.getClass(),
|
|
39
|
+
* ]);
|
|
40
|
+
*/
|
|
41
|
+
export class Reflector {
|
|
42
|
+
get(metadataKey, target) {
|
|
43
|
+
return Reflect.getMetadata(metadataKey, target);
|
|
44
|
+
}
|
|
45
|
+
getAllAndOverride(metadataKey, targets) {
|
|
46
|
+
for (const target of targets) {
|
|
47
|
+
const value = Reflect.getMetadata(metadataKey, target);
|
|
48
|
+
if (value !== undefined)
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
getAllAndMerge(metadataKey, targets) {
|
|
54
|
+
const result = [];
|
|
55
|
+
for (const target of targets) {
|
|
56
|
+
const value = Reflect.getMetadata(metadataKey, target);
|
|
57
|
+
if (value !== undefined) {
|
|
58
|
+
if (Array.isArray(value))
|
|
59
|
+
result.push(...value);
|
|
60
|
+
else
|
|
61
|
+
result.push(value);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Composes multiple decorators into one, applying them left-to-right.
|
|
69
|
+
*
|
|
70
|
+
* @param decorators - One or more class/method/property decorators
|
|
71
|
+
* @returns A single decorator that applies all provided decorators
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* export const Auth = (...roles: string[]) => applyDecorators(
|
|
75
|
+
* SetMetadata('roles', roles),
|
|
76
|
+
* UseGuards(AuthGuard, RolesGuard),
|
|
77
|
+
* );
|
|
78
|
+
*
|
|
79
|
+
* @Get('/admin')
|
|
80
|
+
* @Auth('admin')
|
|
81
|
+
* adminOnly() {}
|
|
82
|
+
*/
|
|
83
|
+
export function applyDecorators(...decorators) {
|
|
84
|
+
return (target, key, descriptor) => {
|
|
85
|
+
let currentTarget = target;
|
|
86
|
+
let currentDescriptor = descriptor;
|
|
87
|
+
for (const decorator of decorators) {
|
|
88
|
+
if (key !== undefined && currentDescriptor !== undefined) {
|
|
89
|
+
const nextDescriptor = decorator(currentTarget, key, currentDescriptor);
|
|
90
|
+
currentDescriptor = nextDescriptor ?? currentDescriptor;
|
|
91
|
+
}
|
|
92
|
+
else if (key !== undefined) {
|
|
93
|
+
decorator(currentTarget, key);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
const nextTarget = decorator(currentTarget);
|
|
97
|
+
currentTarget = nextTarget ?? currentTarget;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return currentDescriptor ?? currentTarget;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Creates a custom parameter decorator that calls `factory` to produce the
|
|
105
|
+
* injected value at request time.
|
|
106
|
+
*
|
|
107
|
+
* @param factory - Called with `(data, ctx)` where `data` is the argument passed
|
|
108
|
+
* to the decorator and `ctx` is the current `ExecutionContext`.
|
|
109
|
+
* @returns A decorator factory: `(data?) => ParameterDecorator`
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* const CurrentUser = createParamDecorator((data, ctx: ExecutionContext) => {
|
|
113
|
+
* return ctx.getRequest().user;
|
|
114
|
+
* });
|
|
115
|
+
*
|
|
116
|
+
* @Get('/profile')
|
|
117
|
+
* getProfile(@CurrentUser() user: User) {}
|
|
118
|
+
*/
|
|
119
|
+
export function createParamDecorator(factory) {
|
|
120
|
+
return (data) => {
|
|
121
|
+
return (target, propertyKey, parameterIndex) => {
|
|
122
|
+
if (!propertyKey)
|
|
123
|
+
return;
|
|
124
|
+
const existingParams = Reflect.getMetadata("params", target, propertyKey) || [];
|
|
125
|
+
existingParams.push({
|
|
126
|
+
index: parameterIndex,
|
|
127
|
+
type: "custom",
|
|
128
|
+
data: data,
|
|
129
|
+
factory: (d, ctx) => factory(d, ctx),
|
|
130
|
+
});
|
|
131
|
+
Reflect.defineMetadata("params", existingParams, target, propertyKey);
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
}
|
|
@@ -3,12 +3,38 @@ import "reflect-metadata";
|
|
|
3
3
|
* Parameter Decorators for WynkJS Framework
|
|
4
4
|
* Extract data from request context
|
|
5
5
|
*/
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Identifies the source from which a parameter decorator extracts its value.
|
|
8
|
+
*
|
|
9
|
+
* - `body` — request body (JSON payload)
|
|
10
|
+
* - `param` — URL path parameter (e.g. `/users/:id`)
|
|
11
|
+
* - `query` — query string parameter (e.g. `?page=1`)
|
|
12
|
+
* - `headers` — HTTP request headers
|
|
13
|
+
* - `request` — full Elysia request object
|
|
14
|
+
* - `response` — Elysia response/set object
|
|
15
|
+
* - `context` — full Elysia context
|
|
16
|
+
* - `user` — user object attached to context by a guard
|
|
17
|
+
* - `file` — single uploaded file
|
|
18
|
+
* - `files` — multiple uploaded files
|
|
19
|
+
* - `custom` — value produced by a `createParamDecorator` factory function
|
|
20
|
+
*/
|
|
21
|
+
export type ParamType = "body" | "param" | "query" | "headers" | "request" | "response" | "context" | "user" | "file" | "files" | "custom";
|
|
22
|
+
/**
|
|
23
|
+
* Internal metadata stored for each decorated parameter in a controller method.
|
|
24
|
+
* Populated by parameter decorators (`@Body`, `@Param`, `@Query`, etc.) and
|
|
25
|
+
* consumed by the ultra-optimized handler at request time.
|
|
26
|
+
*/
|
|
7
27
|
export interface ParamMetadata {
|
|
28
|
+
/** Zero-based position of this parameter in the method signature. */
|
|
8
29
|
index: number;
|
|
30
|
+
/** Where to extract the value from — see {@link ParamType}. */
|
|
9
31
|
type: ParamType;
|
|
32
|
+
/** Optional key to pluck from the source (e.g. param name or header name). */
|
|
10
33
|
data?: string;
|
|
34
|
+
/** Optional pipes applied to the extracted value before it reaches the handler. */
|
|
11
35
|
pipes?: any[];
|
|
36
|
+
/** Factory function used when `type === 'custom'` (from `createParamDecorator`). */
|
|
37
|
+
factory?: (data: any, ctx: any) => any;
|
|
12
38
|
}
|
|
13
39
|
/**
|
|
14
40
|
* @Body decorator - Extracts request body
|
|
@@ -141,4 +167,3 @@ export declare function Session(property?: string): ParameterDecorator;
|
|
|
141
167
|
* }
|
|
142
168
|
*/
|
|
143
169
|
export declare function HostParam(property: string): ParameterDecorator;
|
|
144
|
-
//# sourceMappingURL=param.decorators.d.ts.map
|