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.
Files changed (84) hide show
  1. package/README.md +76 -0
  2. package/dist/common/http-status.enum.d.ts +129 -0
  3. package/dist/common/http-status.enum.js +135 -0
  4. package/dist/cors.d.ts +0 -1
  5. package/dist/cors.js +2 -2
  6. package/dist/database.d.ts +0 -1
  7. package/dist/decorators/database.decorators.d.ts +0 -1
  8. package/dist/decorators/database.decorators.js +2 -2
  9. package/dist/decorators/di.decorators.d.ts +13 -0
  10. package/dist/decorators/di.decorators.js +28 -0
  11. package/dist/decorators/exception.decorators.d.ts +34 -1
  12. package/dist/decorators/exception.decorators.js +44 -6
  13. package/dist/decorators/formatter.decorators.d.ts +0 -1
  14. package/dist/decorators/guard.decorators.d.ts +22 -3
  15. package/dist/decorators/guard.decorators.js +1 -0
  16. package/dist/decorators/http.decorators.d.ts +30 -1
  17. package/dist/decorators/http.decorators.js +25 -4
  18. package/dist/decorators/interceptor.advanced.d.ts +0 -1
  19. package/dist/decorators/interceptor.decorators.d.ts +40 -3
  20. package/dist/decorators/metadata.decorators.d.ts +71 -0
  21. package/dist/decorators/metadata.decorators.js +134 -0
  22. package/dist/decorators/param.decorators.d.ts +27 -2
  23. package/dist/decorators/pipe.advanced.d.ts +19 -26
  24. package/dist/decorators/pipe.advanced.js +84 -54
  25. package/dist/decorators/pipe.decorators.d.ts +76 -12
  26. package/dist/decorators/pipe.decorators.js +55 -8
  27. package/dist/dto.d.ts +0 -1
  28. package/dist/factory.d.ts +270 -20
  29. package/dist/factory.js +284 -68
  30. package/dist/filters/exception.filters.d.ts +0 -1
  31. package/dist/filters/exception.filters.js +3 -3
  32. package/dist/global-prefix.d.ts +2 -3
  33. package/dist/global-prefix.js +4 -6
  34. package/dist/index.d.ts +13 -1
  35. package/dist/index.js +13 -0
  36. package/dist/interfaces/interceptor.interface.d.ts +0 -1
  37. package/dist/interfaces/lifecycle.interface.d.ts +53 -0
  38. package/dist/interfaces/lifecycle.interface.js +1 -0
  39. package/dist/module.d.ts +53 -0
  40. package/dist/module.js +35 -0
  41. package/dist/pipes/validation.pipe.d.ts +1 -2
  42. package/dist/pipes/validation.pipe.js +1 -1
  43. package/dist/plugins/compression.d.ts +0 -1
  44. package/dist/plugins/compression.js +24 -9
  45. package/dist/request.d.ts +126 -0
  46. package/dist/request.js +214 -0
  47. package/dist/response.d.ts +128 -0
  48. package/dist/response.js +261 -0
  49. package/dist/schema-registry.d.ts +0 -1
  50. package/dist/testing/index.d.ts +0 -1
  51. package/dist/testing/test-utils.d.ts +0 -1
  52. package/dist/ultra-optimized-handler.d.ts +0 -1
  53. package/dist/ultra-optimized-handler.js +44 -4
  54. package/package.json +18 -6
  55. package/dist/cors.d.ts.map +0 -1
  56. package/dist/database.d.ts.map +0 -1
  57. package/dist/decorators/database.decorators.d.ts.map +0 -1
  58. package/dist/decorators/exception.advanced.d.ts +0 -457
  59. package/dist/decorators/exception.advanced.d.ts.map +0 -1
  60. package/dist/decorators/exception.advanced.js +0 -742
  61. package/dist/decorators/exception.decorators.d.ts.map +0 -1
  62. package/dist/decorators/formatter.decorators.d.ts.map +0 -1
  63. package/dist/decorators/guard.decorators.d.ts.map +0 -1
  64. package/dist/decorators/http.decorators.d.ts.map +0 -1
  65. package/dist/decorators/interceptor.advanced.d.ts.map +0 -1
  66. package/dist/decorators/interceptor.decorators.d.ts.map +0 -1
  67. package/dist/decorators/param.decorators.d.ts.map +0 -1
  68. package/dist/decorators/pipe.advanced.d.ts.map +0 -1
  69. package/dist/decorators/pipe.decorators.d.ts.map +0 -1
  70. package/dist/dto.d.ts.map +0 -1
  71. package/dist/factory.d.ts.map +0 -1
  72. package/dist/filters/exception.filters.d.ts.map +0 -1
  73. package/dist/global-prefix.d.ts.map +0 -1
  74. package/dist/index.d.ts.map +0 -1
  75. package/dist/interfaces/interceptor.interface.d.ts.map +0 -1
  76. package/dist/optimized-handler.d.ts +0 -31
  77. package/dist/optimized-handler.d.ts.map +0 -1
  78. package/dist/optimized-handler.js +0 -180
  79. package/dist/pipes/validation.pipe.d.ts.map +0 -1
  80. package/dist/plugins/compression.d.ts.map +0 -1
  81. package/dist/schema-registry.d.ts.map +0 -1
  82. package/dist/testing/index.d.ts.map +0 -1
  83. package/dist/testing/test-utils.d.ts.map +0 -1
  84. 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 response = context.getResponse();
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 response = context.getResponse();
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 response = context.getResponse();
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 response = context.getResponse();
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 response = context.getResponse();
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 response = context.getResponse();
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) {
@@ -90,4 +90,3 @@ export declare class SimpleErrorFormatter implements ErrorFormatter {
90
90
  export declare class DetailedErrorFormatter implements ErrorFormatter {
91
91
  format(error: any): any;
92
92
  }
93
- //# sourceMappingURL=formatter.decorators.d.ts.map
@@ -4,17 +4,37 @@ import "reflect-metadata";
4
4
  * Guards for route protection and authorization
5
5
  */
6
6
  /**
7
- * Execution context interface - provides access to request details
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
- * CanActivate interface - All guards must implement this
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
@@ -37,6 +37,7 @@ export function createExecutionContext(ctx, handler, controllerClass) {
37
37
  getContext: () => ctx,
38
38
  getHandler: () => handler,
39
39
  getClass: () => controllerClass,
40
+ getType: () => 'http',
40
41
  };
41
42
  }
42
43
  /**
@@ -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
- * Call handler interface for interceptors
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
- * WynkInterceptor interface - All interceptors must implement this
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
- export type ParamType = "body" | "param" | "query" | "headers" | "request" | "response" | "context" | "user" | "file" | "files";
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