quantum-flow 1.3.10 → 1.4.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.
Files changed (39) hide show
  1. package/README.md +6 -8
  2. package/dist/app/aws/helpers.d.ts +25 -0
  3. package/dist/app/aws/helpers.js +46 -0
  4. package/dist/app/aws/lambda.js +23 -7
  5. package/dist/app/aws/utils/response.d.ts +7 -0
  6. package/dist/app/aws/utils/response.js +13 -0
  7. package/dist/app/http/Application.js +10 -0
  8. package/dist/app/http/decorators.js +1 -0
  9. package/dist/constants.d.ts +1 -0
  10. package/dist/constants.js +2 -1
  11. package/dist/core/Controller.d.ts +1 -9
  12. package/dist/core/Controller.js +23 -57
  13. package/dist/core/index.d.ts +1 -1
  14. package/dist/core/utils/cors.d.ts +2 -0
  15. package/dist/core/utils/cors.js +21 -0
  16. package/dist/core/utils/index.d.ts +1 -0
  17. package/dist/core/utils/index.js +1 -0
  18. package/dist/examples/app.js +9 -3
  19. package/dist/examples/controllers/user.js +2 -1
  20. package/dist/examples/controllers/userMetadata.d.ts +1 -1
  21. package/dist/examples/controllers/userMetadata.js +13 -5
  22. package/dist/types/common.d.ts +0 -13
  23. package/dist/types/controller.d.ts +3 -0
  24. package/dist/types/cors.d.ts +10 -0
  25. package/dist/types/cors.js +2 -0
  26. package/dist/types/http.d.ts +2 -0
  27. package/dist/types/index.d.ts +1 -0
  28. package/dist/types/index.js +1 -0
  29. package/dist/types/lambda.d.ts +5 -0
  30. package/dist/utils/controller.d.ts +9 -1
  31. package/dist/utils/controller.js +62 -5
  32. package/dist/utils/cors.d.ts +8 -0
  33. package/dist/utils/cors.js +126 -0
  34. package/dist/utils/index.d.ts +1 -0
  35. package/dist/utils/index.js +1 -0
  36. package/dist/utils/multipart.d.ts +1 -0
  37. package/dist/utils/multipart.js +98 -1
  38. package/dist/utils/server.js +1 -0
  39. package/package.json +1 -1
package/README.md CHANGED
@@ -41,7 +41,8 @@ import {
41
41
  Request,
42
42
  Response,
43
43
  Status,
44
- USE
44
+ USE,
45
+ CORS
45
46
  } from 'quantum-flow/core';
46
47
  import {IsString} from 'class-validator'
47
48
 
@@ -58,10 +59,12 @@ class UserDto {
58
59
  return { data, intercepted: true };
59
60
  },
60
61
  })
62
+ @CORS({ origin: '*' })
61
63
  @Catch((err) => ({ status: 500, err }))
62
64
  export class User {
63
65
  @Status(201)
64
66
  @PUT(':id',[...middlewares])
67
+ @CORS({ origin: '*' })
65
68
  async createUser(
66
69
  @Body(UserDto) body: UserDto,
67
70
  @Query() query: any,
@@ -97,7 +100,7 @@ Use the `@Server` decorator with configuration options like port, host, controll
97
100
  ```typescript
98
101
  import { Server, Port, Host, Use, Catch, HttpServer } from 'quantum-flow/http';
99
102
 
100
- @Server({ controllers: [RootController] })
103
+ @Server({ controllers: [RootController], cors: { origin: '*' } })
101
104
  @Port(3000)
102
105
  @Host('localhost')
103
106
  @Use((data) => data)
@@ -115,6 +118,7 @@ server.listen().catch(console.error);
115
118
  - Use `@Use` to apply middlewares.
116
119
  - Use `@Catch` to handle errors.
117
120
  - Use `@Port` and `@Host` to configure server port and host.
121
+ - Use `@CORS` to configure cors.
118
122
 
119
123
  ## Request decorators
120
124
 
@@ -160,8 +164,6 @@ Enable WebSocket in the server configuration and register WebSocket controllers.
160
164
  export class Socket {
161
165
  @OnConnection()
162
166
  onConnection(event: WebSocketEvent) {
163
- console.log(`✅ Connected: ${event.client.id}`);
164
-
165
167
  // Send greeting ONLY to this client
166
168
  event.client.socket.send(
167
169
  JSON.stringify({
@@ -181,8 +183,6 @@ export class Socket {
181
183
  // The message is ALREADY automatically broadcast to all!
182
184
 
183
185
  const msg = event.message?.data;
184
- console.log(`💬 Message in chat: ${msg?.text}`);
185
-
186
186
  // You can add logic, but no need to broadcast
187
187
  if (msg?.text.includes('bad')) {
188
188
  // If return empty, the message will not be sent
@@ -197,7 +197,6 @@ export class Socket {
197
197
  */
198
198
  @Subscribe('news')
199
199
  onNewsMessage(event: WebSocketEvent) {
200
- console.log(`📰 News: ${event.message?.data.title}`);
201
200
  // Automatic broadcast to all subscribed to 'news'
202
201
  }
203
202
 
@@ -221,7 +220,6 @@ export class Socket {
221
220
  @OnMessage('subscribe')
222
221
  onSubscribe(event: WebSocketEvent) {
223
222
  const topic = event.message?.data.topic;
224
- console.log(`📌 Client ${event.client.id} subscribed to ${topic}`);
225
223
 
226
224
  // Server will save the subscription automatically, no need to do anything!
227
225
  // Just confirm
@@ -0,0 +1,25 @@
1
+ import { AppRequest, HTTP_METHODS } from '../../types/index.js';
2
+ import { IncomingHttpHeaders } from 'http';
3
+ export declare class LResponse {
4
+ headers: IncomingHttpHeaders;
5
+ constructor();
6
+ setHeader(header: string, value: string): void;
7
+ }
8
+ export declare class LRequest {
9
+ headers: IncomingHttpHeaders;
10
+ url: URL;
11
+ method: HTTP_METHODS;
12
+ path?: string;
13
+ query?: any;
14
+ params?: any;
15
+ body: any;
16
+ cookies: Record<string, string>;
17
+ _startTime: number;
18
+ event?: any;
19
+ context?: any;
20
+ requestId?: string;
21
+ stage?: string;
22
+ sourceIp?: string;
23
+ userAgent?: string;
24
+ constructor(request: AppRequest);
25
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LRequest = exports.LResponse = void 0;
4
+ class LResponse {
5
+ headers = {};
6
+ constructor() { }
7
+ setHeader(header, value) {
8
+ this.headers[header] = value;
9
+ }
10
+ }
11
+ exports.LResponse = LResponse;
12
+ class LRequest {
13
+ headers;
14
+ url;
15
+ method;
16
+ path;
17
+ query;
18
+ params;
19
+ body;
20
+ cookies;
21
+ _startTime;
22
+ event;
23
+ context;
24
+ requestId;
25
+ stage;
26
+ sourceIp;
27
+ userAgent;
28
+ constructor(request) {
29
+ this.headers = { ...request.headers };
30
+ this.url = request.url;
31
+ this.method = request.method;
32
+ this.path = request.path;
33
+ this.query = request.query;
34
+ this.params = request.params;
35
+ this.body = request.body;
36
+ this.cookies = request.cookies;
37
+ this._startTime = request._startTime;
38
+ this.event = request.event;
39
+ this.context = request.context;
40
+ this.requestId = request.requestId;
41
+ this.stage = request.stage;
42
+ this.sourceIp = request.sourceIp;
43
+ this.userAgent = request.userAgent;
44
+ }
45
+ }
46
+ exports.LRequest = LRequest;
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LambdaAdapter = void 0;
4
+ const _constants_1 = require("../../constants.js");
4
5
  const _utils_1 = require("../../utils/index.js");
6
+ const helpers_1 = require("./helpers");
5
7
  class LambdaAdapter {
6
8
  static createHandler(Controller) {
7
9
  return async (event, context) => {
@@ -10,14 +12,27 @@ class LambdaAdapter {
10
12
  await instance.beforeStart?.();
11
13
  }
12
14
  try {
15
+ const cors = Reflect.getMetadata(_constants_1.CORS_METADATA, instance);
13
16
  const eventType = this.getEventType(event);
14
17
  const normalizedEvent = (0, _utils_1.normalizeEvent)(event, eventType);
15
18
  const request = this.toRequest(normalizedEvent, context);
19
+ const lambdaRequest = new helpers_1.LRequest(request);
20
+ const lambdaResponse = new helpers_1.LResponse();
21
+ let handledCors = { permitted: true, continue: true };
22
+ if (cors) {
23
+ handledCors = (0, _utils_1.handleCORS)(request, lambdaResponse, cors);
24
+ }
25
+ if (!handledCors.permitted) {
26
+ return this.toLambdaResponse({ status: 403, message: 'CORS: Origin not allowed' }, lambdaRequest, lambdaResponse, eventType);
27
+ }
28
+ if (!handledCors.continue && handledCors.permitted) {
29
+ return this.toLambdaResponse({ status: 204 }, lambdaRequest, lambdaResponse, eventType);
30
+ }
16
31
  if (typeof instance.handleRequest !== 'function') {
17
32
  throw new Error('Controller must have handleRequest method');
18
33
  }
19
- const response = await instance.handleRequest(request);
20
- return this.toLambdaResponse(response, request, eventType);
34
+ const response = await instance.handleRequest(request, lambdaRequest, lambdaResponse);
35
+ return this.toLambdaResponse(response, lambdaRequest, lambdaResponse, eventType);
21
36
  }
22
37
  catch (error) {
23
38
  return this.handleError(error, event, context);
@@ -109,12 +124,13 @@ class LambdaAdapter {
109
124
  : event.headers['user-agent']?.[0] || 'unknown',
110
125
  };
111
126
  }
112
- static toLambdaResponse(response, request, eventType) {
113
- const statusCode = response.status || 200;
127
+ static toLambdaResponse(appResponse, request, res, eventType) {
128
+ const statusCode = appResponse.status || 200;
114
129
  const headers = {
115
130
  'Content-Type': 'application/json',
116
131
  'X-Request-Id': request.requestId,
117
- ...(response.headers || {}),
132
+ ...(appResponse.headers || {}),
133
+ ...res.headers,
118
134
  };
119
135
  const originHeader = request.headers['origin'] || request.headers['Origin'];
120
136
  let origin;
@@ -135,13 +151,13 @@ class LambdaAdapter {
135
151
  }
136
152
  const body = JSON.stringify({
137
153
  success: statusCode < 400,
138
- data: response.data,
154
+ data: appResponse.data,
139
155
  timestamp: new Date().toISOString(),
140
156
  });
141
157
  const commonResponse = {
142
158
  statusCode,
143
159
  headers,
144
- body: response.data,
160
+ body: appResponse.data,
145
161
  timestamp: new Date().toISOString(),
146
162
  };
147
163
  switch (eventType) {
@@ -0,0 +1,7 @@
1
+ import { AppRequest } from '../../../types/index.js';
2
+ import { IncomingHttpHeaders } from 'http';
3
+ export declare class Response {
4
+ headers: IncomingHttpHeaders;
5
+ constructor(request: AppRequest);
6
+ setHeader(header: string, value: string): void;
7
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Response = void 0;
4
+ class Response {
5
+ headers;
6
+ constructor(request) {
7
+ this.headers = { ...request.headers };
8
+ }
9
+ setHeader(header, value) {
10
+ this.headers[header] = value;
11
+ }
12
+ }
13
+ exports.Response = Response;
@@ -101,6 +101,16 @@ class HttpServer extends Socket_1.Socket {
101
101
  const startTime = Date.now();
102
102
  try {
103
103
  const request = await this.createRequest(req);
104
+ let handledCors = { permitted: true, continue: true };
105
+ if (this.config.cors) {
106
+ handledCors = (0, _utils_1.handleCORS)(request, res, this.config.cors);
107
+ }
108
+ if (!handledCors.permitted) {
109
+ return this.sendResponse(res, { status: 403, message: 'CORS: Origin not allowed' }, startTime);
110
+ }
111
+ if (!handledCors.continue && handledCors.permitted) {
112
+ return this.sendResponse(res, { status: 204 }, startTime);
113
+ }
104
114
  let appRequest = await this.applyMiddlewares(request, req, res);
105
115
  let data = await this.findController(appRequest, req, res);
106
116
  const isError = !_constants_1.OK_STATUSES.includes(data.status);
@@ -12,6 +12,7 @@ function Server(config = {}) {
12
12
  ...config,
13
13
  controllers: [...(existingConfig.controllers || []), ...(config.controllers || [])],
14
14
  middlewares: [...(existingConfig.middlewares ?? []), ...(config.middlewares ?? [])],
15
+ cors: config.cors,
15
16
  interceptors: existingConfig.interceptor ?? config.interceptor,
16
17
  };
17
18
  Reflect.defineMetadata(_constants_1.SERVER_CONFIG_KEY, mergedConfig, target);
@@ -20,3 +20,4 @@ export declare const OK_STATUSES: number[];
20
20
  export declare const TO_VALIDATE: string[];
21
21
  export declare const STATISTIC: Record<'controllers' | 'routes', number>;
22
22
  export declare const INCREMENT_STATISTIC: (prop: "controllers" | "routes") => void;
23
+ export declare const CORS_METADATA = "cors:config";
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.INCREMENT_STATISTIC = exports.STATISTIC = exports.TO_VALIDATE = exports.OK_STATUSES = exports.STOPPED = exports.CATCH = exports.INTECEPT = exports.WS_SERVICE_KEY = exports.WS_TOPIC_KEY = exports.WS_METADATA_KEY = exports.USE_MIDDLEWARE = exports.SERVER_MODULES_KEY = exports.SERVER_CONFIG_KEY = exports.OK_METADATA_KEY = exports.ENDPOINT = exports.INTERCEPTOR = exports.CONTROLLERS = exports.MIDDLEWARES = exports.ROUTE_MIDDLEWARES = exports.ROUTE_PREFIX = exports.APP_METADATA_KEY = exports.PARAM_METADATA_KEY = void 0;
3
+ exports.CORS_METADATA = exports.INCREMENT_STATISTIC = exports.STATISTIC = exports.TO_VALIDATE = exports.OK_STATUSES = exports.STOPPED = exports.CATCH = exports.INTECEPT = exports.WS_SERVICE_KEY = exports.WS_TOPIC_KEY = exports.WS_METADATA_KEY = exports.USE_MIDDLEWARE = exports.SERVER_MODULES_KEY = exports.SERVER_CONFIG_KEY = exports.OK_METADATA_KEY = exports.ENDPOINT = exports.INTERCEPTOR = exports.CONTROLLERS = exports.MIDDLEWARES = exports.ROUTE_MIDDLEWARES = exports.ROUTE_PREFIX = exports.APP_METADATA_KEY = exports.PARAM_METADATA_KEY = void 0;
4
4
  exports.PARAM_METADATA_KEY = 'design:parameters';
5
5
  exports.APP_METADATA_KEY = 'app:configuration';
6
6
  exports.ROUTE_PREFIX = 'route:prefix';
@@ -34,3 +34,4 @@ const INCREMENT_STATISTIC = (prop) => {
34
34
  exports.STATISTIC[prop] = exports.STATISTIC[prop] + 1;
35
35
  };
36
36
  exports.INCREMENT_STATISTIC = INCREMENT_STATISTIC;
37
+ exports.CORS_METADATA = 'cors:config';
@@ -1,4 +1,4 @@
1
- import { AppRequest, ControllerClass, ControllerConfig, ControllerInstance, InterceptorCB, MiddlewareCB, RouteContext } from '../types/index.js';
1
+ import { AppRequest, ControllerClass, ControllerConfig, ControllerInstance, InterceptorCB, RouteContext } from '../types/index.js';
2
2
  import { IncomingMessage, ServerResponse } from 'http';
3
3
  import 'reflect-metadata';
4
4
  /**
@@ -40,13 +40,5 @@ export declare function Controller(config: string | ControllerConfig, middleware
40
40
  }>;
41
41
  handleRequest: (appRequest: AppRequest, request?: IncomingMessage, response?: ServerResponse) => Promise<any>;
42
42
  routeWalker(context: RouteContext): Promise<any>;
43
- getAllMethods(obj: any): string[];
44
- findRouteInController(instance: any, path: string, route: string, method: string): {
45
- name: string;
46
- pathParams: Record<string, string>;
47
- priority: number;
48
- methodMiddlewares: MiddlewareCB[];
49
- methodInterceptors: InterceptorCB[];
50
- };
51
43
  };
52
44
  } & T;
@@ -104,6 +104,7 @@ function Controller(config, middlewares = []) {
104
104
  interceptor: Reflect.getMetadata(_constants_1.INTERCEPTOR, proto),
105
105
  subControllers: Reflect.getMetadata(_constants_1.CONTROLLERS, proto) || [],
106
106
  errorHandler: Reflect.getMetadata(_constants_1.CATCH, proto),
107
+ cors: Reflect.getMetadata(_constants_1.CORS_METADATA, proto),
107
108
  },
108
109
  path: (appRequest.url.pathname ?? '').replace(/^\/+/g, ''),
109
110
  method: appRequest.method.toUpperCase(),
@@ -112,6 +113,7 @@ function Controller(config, middlewares = []) {
112
113
  response,
113
114
  middlewareChain: [],
114
115
  interceptorChain: [],
116
+ corsChain: [Reflect.getMetadata(_constants_1.CORS_METADATA, proto)],
115
117
  errorHandlerChain: [Reflect.getMetadata(_constants_1.CATCH, proto)],
116
118
  subPath: Reflect.getMetadata(_constants_1.ROUTE_PREFIX, proto) || '',
117
119
  };
@@ -128,6 +130,7 @@ function Controller(config, middlewares = []) {
128
130
  interceptor: Reflect.getMetadata(_constants_1.INTERCEPTOR, SubController.prototype),
129
131
  errorHandler: Reflect.getMetadata(_constants_1.CATCH, SubController),
130
132
  subControllers: Reflect.getMetadata(_constants_1.CONTROLLERS, SubController.prototype) || [],
133
+ cors: Reflect.getMetadata(_constants_1.CORS_METADATA, SubController.prototype) || [],
131
134
  };
132
135
  const fullSubPath = [subPath, subMeta.routePrefix]
133
136
  .filter(Boolean)
@@ -143,21 +146,38 @@ function Controller(config, middlewares = []) {
143
146
  middlewareChain: [...context.middlewareChain, ...controllerMeta.middlewares],
144
147
  errorHandlerChain: [...context.errorHandlerChain, subMeta.errorHandler].filter((el) => !!el),
145
148
  interceptorChain: [...context.interceptorChain, controllerMeta.interceptor].filter((el) => !!el),
149
+ corsChain: [...context.corsChain, subMeta.cors].filter((el) => !!el),
146
150
  });
147
151
  if (subResult && subResult.status !== 404) {
148
152
  return subResult;
149
153
  }
150
154
  }
151
155
  }
152
- const routeMatch = this.findRouteInController(controllerInstance, subPath, path, method);
156
+ const routeMatch = (0, _utils_1.findRouteInController)(controllerInstance, subPath, path, method);
153
157
  if (routeMatch) {
154
- const { name, pathParams, methodMiddlewares, methodInterceptors } = routeMatch;
158
+ const { name, pathParams, methodMiddlewares, cors } = routeMatch;
159
+ let payload = { ...context.appRequest, params: pathParams };
160
+ const handledCors = context.corsChain
161
+ .concat(cors ?? [])
162
+ .flat()
163
+ .reduce((acc, conf) => {
164
+ const cors = (0, _utils_1.handleCORS)(payload, context.response, conf);
165
+ return {
166
+ permitted: acc.permitted && cors.permitted,
167
+ continue: acc.continue && cors.continue,
168
+ };
169
+ }, { permitted: true, continue: true });
170
+ if (!handledCors.permitted) {
171
+ return { status: 403, message: 'CORS: Origin not allowed' };
172
+ }
173
+ if (!handledCors.continue && handledCors.permitted) {
174
+ return { status: 204 };
175
+ }
155
176
  const allMiddlewares = [
156
177
  ...context.middlewareChain,
157
178
  ...controllerMeta.middlewares,
158
179
  ...methodMiddlewares,
159
180
  ];
160
- let payload = { ...context.appRequest, params: pathParams };
161
181
  for (const mw of allMiddlewares) {
162
182
  const mwResult = await mw(payload, context.request, context.response);
163
183
  payload = mwResult ?? payload;
@@ -180,60 +200,6 @@ function Controller(config, middlewares = []) {
180
200
  }
181
201
  return null;
182
202
  }
183
- getAllMethods(obj) {
184
- let methods = new Set();
185
- let current = Object.getPrototypeOf(obj);
186
- while (current && current !== Object.prototype) {
187
- Object.getOwnPropertyNames(current).forEach((name) => {
188
- if (name !== 'constructor' && typeof current[name] === 'function') {
189
- methods.add(name);
190
- }
191
- });
192
- current = Object.getPrototypeOf(current);
193
- }
194
- return Array.from(methods);
195
- }
196
- findRouteInController(instance, path, route, method) {
197
- const prototype = Object.getPrototypeOf(instance);
198
- const propertyNames = this.getAllMethods(instance);
199
- const matches = [];
200
- for (const name of propertyNames) {
201
- if ([
202
- 'constructor',
203
- 'getResponse',
204
- 'routeWalker',
205
- 'getAllMethods',
206
- 'findRouteInController',
207
- ].includes(name))
208
- continue;
209
- const endpointMeta = Reflect.getMetadata(_constants_1.ENDPOINT, prototype, name) || [];
210
- if (endpointMeta.length === 0)
211
- continue;
212
- const [httpMethod, routePattern] = endpointMeta;
213
- if (httpMethod !== method && httpMethod !== 'USE') {
214
- continue;
215
- }
216
- if (httpMethod === 'USE') {
217
- let useRoute = route.split('/');
218
- useRoute.pop();
219
- route = useRoute.join('/');
220
- }
221
- const current = [path, routePattern].join('/').replace(/\/+/g, '/');
222
- const pathParams = (0, _utils_1.matchRoute)(current, route);
223
- if (pathParams) {
224
- const priority = httpMethod === 'USE' ? 0 : Object.keys(pathParams).length > 0 ? 1 : 2;
225
- matches.push({
226
- name,
227
- pathParams,
228
- priority,
229
- methodMiddlewares: Reflect.getMetadata(_constants_1.MIDDLEWARES, prototype, name) || [],
230
- methodInterceptors: Reflect.getMetadata(_constants_1.INTERCEPTOR, prototype, name) || [],
231
- });
232
- }
233
- }
234
- matches.sort((a, b) => b.priority - a.priority);
235
- return matches[0] || null;
236
- }
237
203
  };
238
204
  };
239
205
  }
@@ -4,7 +4,7 @@
4
4
  * This module provides centralized exports for controller and endpoint decorators,
5
5
  * as well as related types and utility functions used throughout the core framework.
6
6
  */
7
- export { AppRequest, EndpointResponse, ErrorCB, HttpError, IController, InterceptorCB, IWebSocketService, MiddlewareCB, ResponseWithStatus, Router, WebSocketClient, WebSocketEvent, WebSocketMessage, } from '../types/index.js';
7
+ export { AppRequest, CORSConfig, EndpointResponse, ErrorCB, HttpError, IController, InterceptorCB, IWebSocketService, MiddlewareCB, ResponseWithStatus, Router, WebSocketClient, WebSocketEvent, WebSocketMessage, } from '../types/index.js';
8
8
  export * from './Controller';
9
9
  export * from './Endpoint';
10
10
  export * from './utils';
@@ -0,0 +1,2 @@
1
+ import { CORSConfig } from '../../types/index.js';
2
+ export declare function CORS(config?: CORSConfig): (target: any, propertyKey?: string, descriptor?: PropertyDescriptor) => void;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CORS = CORS;
4
+ const _constants_1 = require("../../constants.js");
5
+ const _types_1 = require("../../types/index.js");
6
+ function CORS(config = {}) {
7
+ return function (target, propertyKey, descriptor) {
8
+ const defaultConfig = {
9
+ origin: '*',
10
+ optionsSuccessStatus: 204,
11
+ methods: Object.keys(_types_1.HTTP_METHODS),
12
+ };
13
+ const finalConfig = { ...defaultConfig, ...config };
14
+ if (propertyKey && descriptor) {
15
+ Reflect.defineMetadata(_constants_1.CORS_METADATA, finalConfig, target, propertyKey);
16
+ }
17
+ else {
18
+ Reflect.defineMetadata(_constants_1.CORS_METADATA, finalConfig, target.prototype || target);
19
+ }
20
+ };
21
+ }
@@ -1,3 +1,4 @@
1
+ export * from './cors';
1
2
  export * from './extractors';
2
3
  export * from './helpers';
3
4
  export * from './middlewares';
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./cors"), exports);
17
18
  __exportStar(require("./extractors"), exports);
18
19
  __exportStar(require("./helpers"), exports);
19
20
  __exportStar(require("./middlewares"), exports);
@@ -15,7 +15,8 @@ let Root = class Root {
15
15
  };
16
16
  exports.Root = Root;
17
17
  exports.Root = Root = __decorate([
18
- (0, core_1.Controller)({ prefix: 'api', controllers: [user_1.User] })
18
+ (0, core_1.Controller)({ prefix: 'api', controllers: [user_1.User] }),
19
+ (0, core_1.CORS)({ origin: '*' })
19
20
  ], Root);
20
21
  let App = class App {
21
22
  };
@@ -26,9 +27,14 @@ exports.App = App = __decorate([
26
27
  websocket: { enabled: true },
27
28
  interceptor: (data) => data,
28
29
  errorHandler: (err) => err,
30
+ cors: { origin: '*' },
29
31
  }),
30
32
  (0, http_1.Port)(3000),
31
- (0, core_1.Use)((data) => data),
32
- (0, core_1.Use)((data) => data),
33
+ (0, core_1.Use)((data) => {
34
+ return data;
35
+ }),
36
+ (0, core_1.Use)((data) => {
37
+ return data;
38
+ }),
33
39
  (0, core_1.Catch)((err) => err)
34
40
  ], App);
@@ -67,5 +67,6 @@ exports.User = User = __decorate([
67
67
  interceptor: (data, req, res) => {
68
68
  return { data, intercepted: true };
69
69
  },
70
- })
70
+ }),
71
+ (0, core_1.CORS)({ origin: '*' })
71
72
  ], User);
@@ -1,6 +1,6 @@
1
1
  export declare class UserMetadata {
2
2
  getUserMetadata(params: any): Promise<any>;
3
- createMeta(body: any, params: any): Promise<{
3
+ createMeta(mult: any, body: any, params: any): Promise<{
4
4
  body: any;
5
5
  params: any;
6
6
  }>;
@@ -27,7 +27,7 @@ let UserMetadata = class UserMetadata {
27
27
  async getUserMetadata(params) {
28
28
  return params;
29
29
  }
30
- async createMeta(body, params) {
30
+ async createMeta(mult, body, params) {
31
31
  return { body, params };
32
32
  }
33
33
  };
@@ -41,12 +41,20 @@ __decorate([
41
41
  ], UserMetadata.prototype, "getUserMetadata", null);
42
42
  __decorate([
43
43
  (0, core_1.POST)('/:meta'),
44
- __param(0, (0, core_1.Body)()),
45
- __param(1, (0, core_1.Params)(DTO, 'meta')),
44
+ __param(0, (0, core_1.Multipart)()),
45
+ __param(1, (0, core_1.Body)()),
46
+ __param(2, (0, core_1.Params)(DTO, 'meta')),
46
47
  __metadata("design:type", Function),
47
- __metadata("design:paramtypes", [Object, Object]),
48
+ __metadata("design:paramtypes", [Object, Object, Object]),
48
49
  __metadata("design:returntype", Promise)
49
50
  ], UserMetadata.prototype, "createMeta", null);
50
51
  exports.UserMetadata = UserMetadata = __decorate([
51
- (0, core_1.Controller)({ prefix: 'metadata' })
52
+ (0, core_1.Controller)({
53
+ prefix: 'metadata',
54
+ middlewares: [
55
+ (req) => {
56
+ return req;
57
+ },
58
+ ],
59
+ })
52
60
  ], UserMetadata);
@@ -38,19 +38,6 @@ export type EndpointResponse<T = any> = {
38
38
  data?: T;
39
39
  error?: any;
40
40
  };
41
- export type AxiosQuery = {
42
- data?: {
43
- [key: string]: any;
44
- };
45
- headers?: {
46
- [key: string]: any;
47
- };
48
- params?: {
49
- [key: string]: any;
50
- };
51
- url: string;
52
- method: 'POST' | 'GET' | 'PATCH' | 'DELETE';
53
- };
54
41
  export interface IController {
55
42
  handleRequest: Router;
56
43
  }
@@ -1,5 +1,6 @@
1
1
  import { IncomingMessage, ServerResponse } from 'http';
2
2
  import { AppRequest, ErrorCB, HTTP_METHODS, InterceptorCB, MiddlewareCB } from './common';
3
+ import { CORSConfig } from './cors';
3
4
  export type ControllerClass = {
4
5
  new (...args: any[]): any;
5
6
  };
@@ -16,6 +17,7 @@ export type ControllerMetadata = {
16
17
  interceptor?: InterceptorCB;
17
18
  subControllers: ControllerClass[];
18
19
  errorHandler?: ErrorCB;
20
+ cors?: CORSConfig;
19
21
  };
20
22
  export interface ControllerConfig {
21
23
  prefix: string;
@@ -33,6 +35,7 @@ export type RouteContext = {
33
35
  response?: ServerResponse;
34
36
  middlewareChain: MiddlewareCB[];
35
37
  interceptorChain: InterceptorCB[];
38
+ corsChain: CORSConfig[];
36
39
  errorHandlerChain: ErrorCB[];
37
40
  subPath: string;
38
41
  };
@@ -0,0 +1,10 @@
1
+ export interface CORSConfig {
2
+ origin?: string | string[] | ((origin: string) => boolean);
3
+ methods?: string[];
4
+ allowedHeaders?: string[];
5
+ exposedHeaders?: string[];
6
+ credentials?: boolean;
7
+ maxAge?: number;
8
+ preflightContinue?: boolean;
9
+ optionsSuccessStatus?: number;
10
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,4 +1,5 @@
1
1
  import { ErrorCB, InterceptorCB, MiddlewareCB } from './common';
2
+ import { CORSConfig } from './cors';
2
3
  export interface ServerConfig {
3
4
  port?: number;
4
5
  host?: string;
@@ -6,6 +7,7 @@ export interface ServerConfig {
6
7
  interceptor?: InterceptorCB;
7
8
  errorHandler?: ErrorCB;
8
9
  controllers?: (new (...args: any[]) => any)[];
10
+ cors?: CORSConfig;
9
11
  websocket?: {
10
12
  enabled: boolean;
11
13
  path?: string;
@@ -1,5 +1,6 @@
1
1
  export * from './common';
2
2
  export * from './controller';
3
+ export * from './cors';
3
4
  export * from './http';
4
5
  export * from './lambda';
5
6
  export * from './websocket';
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./common"), exports);
18
18
  __exportStar(require("./controller"), exports);
19
+ __exportStar(require("./cors"), exports);
19
20
  __exportStar(require("./http"), exports);
20
21
  __exportStar(require("./lambda"), exports);
21
22
  __exportStar(require("./websocket"), exports);
@@ -56,6 +56,11 @@ export interface LambdaRequest {
56
56
  url: URL;
57
57
  event: NormalizedEvent;
58
58
  _startTime: number;
59
+ routeInfo?: {
60
+ controller: any;
61
+ methodName: string;
62
+ pathParams: Record<string, string>;
63
+ };
59
64
  }
60
65
  export interface LambdaResponse {
61
66
  statusCode: number;
@@ -1,4 +1,12 @@
1
- import { ControllerInstance, ControllerMethods } from '../types/index.js';
1
+ import { ControllerInstance, ControllerMethods, CORSConfig, MiddlewareCB } from '../types/index.js';
2
2
  import { IncomingMessage, ServerResponse } from 'http';
3
3
  export declare const executeControllerMethod: (controller: ControllerInstance, propertyName: string, payload: any, request?: IncomingMessage, response?: ServerResponse) => Promise<any>;
4
4
  export declare const getControllerMethods: (controller: ControllerInstance) => ControllerMethods;
5
+ export declare const getAllMethods: (obj: any) => string[];
6
+ export declare const findRouteInController: (instance: any, path: string, route: string, method: string) => {
7
+ name: string;
8
+ pathParams: Record<string, string>;
9
+ priority: number;
10
+ methodMiddlewares: MiddlewareCB[];
11
+ cors?: CORSConfig;
12
+ };
@@ -1,17 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getControllerMethods = exports.executeControllerMethod = void 0;
3
+ exports.findRouteInController = exports.getAllMethods = exports.getControllerMethods = exports.executeControllerMethod = void 0;
4
+ const _constants_1 = require("../constants.js");
4
5
  const _types_1 = require("../types/index.js");
5
- const _utils_1 = require("./index.js");
6
6
  const WebsocketService_1 = require("../app/http/websocket/WebsocketService");
7
+ const helper_1 = require("./helper");
8
+ const multipart_1 = require("./multipart");
7
9
  const validate_1 = require("./validate");
8
- const _constants_1 = require("../constants.js");
9
10
  const getBodyAndMultipart = (payload) => {
10
11
  let body = payload.body;
11
12
  let multipart;
12
- if (_utils_1.MultipartProcessor.isMultipart({ headers: payload.headers })) {
13
+ if (multipart_1.MultipartProcessor.isMultipart({ headers: payload.headers })) {
13
14
  try {
14
- const { fields, files } = _utils_1.MultipartProcessor.parse({
15
+ const { fields, files } = multipart_1.MultipartProcessor.parse({
15
16
  body: payload.rawBody || payload.body,
16
17
  headers: payload.headers,
17
18
  isBase64Encoded: payload.isBase64Encoded,
@@ -110,3 +111,59 @@ const getControllerMethods = (controller) => {
110
111
  return methods.sort((a, b) => (a.httpMethod === _types_1.HTTP_METHODS.USE ? 1 : -1));
111
112
  };
112
113
  exports.getControllerMethods = getControllerMethods;
114
+ const getAllMethods = (obj) => {
115
+ let methods = new Set();
116
+ let current = Object.getPrototypeOf(obj);
117
+ while (current && current !== Object.prototype) {
118
+ Object.getOwnPropertyNames(current).forEach((name) => {
119
+ if (name !== 'constructor' && typeof current[name] === 'function') {
120
+ methods.add(name);
121
+ }
122
+ });
123
+ current = Object.getPrototypeOf(current);
124
+ }
125
+ return Array.from(methods);
126
+ };
127
+ exports.getAllMethods = getAllMethods;
128
+ const findRouteInController = (instance, path, route, method) => {
129
+ const prototype = Object.getPrototypeOf(instance);
130
+ const propertyNames = (0, exports.getAllMethods)(instance);
131
+ const matches = [];
132
+ for (const name of propertyNames) {
133
+ if ([
134
+ 'constructor',
135
+ 'getResponse',
136
+ 'routeWalker',
137
+ 'getAllMethods',
138
+ 'findRouteInController',
139
+ ].includes(name))
140
+ continue;
141
+ const endpointMeta = Reflect.getMetadata(_constants_1.ENDPOINT, prototype, name) || [];
142
+ if (endpointMeta.length === 0)
143
+ continue;
144
+ const [httpMethod, routePattern] = endpointMeta;
145
+ if (httpMethod !== method && httpMethod !== 'USE') {
146
+ continue;
147
+ }
148
+ if (httpMethod === 'USE') {
149
+ let useRoute = route.split('/');
150
+ useRoute.pop();
151
+ route = useRoute.join('/');
152
+ }
153
+ const current = [path, routePattern].join('/').replace(/\/+/g, '/');
154
+ const pathParams = (0, helper_1.matchRoute)(current, route);
155
+ if (pathParams) {
156
+ const priority = httpMethod === 'USE' ? 0 : Object.keys(pathParams).length > 0 ? 1 : 2;
157
+ matches.push({
158
+ name,
159
+ pathParams,
160
+ priority,
161
+ cors: Reflect.getMetadata(_constants_1.CORS_METADATA, prototype, name),
162
+ methodMiddlewares: Reflect.getMetadata(_constants_1.MIDDLEWARES, prototype, name) || [],
163
+ });
164
+ }
165
+ }
166
+ matches.sort((a, b) => b.priority - a.priority);
167
+ return matches[0] || null;
168
+ };
169
+ exports.findRouteInController = findRouteInController;
@@ -0,0 +1,8 @@
1
+ import { CORSConfig } from '../types/index.js';
2
+ export declare function handleCORS(req: any, res: any, config: CORSConfig): {
3
+ permitted: boolean;
4
+ continue: boolean;
5
+ };
6
+ export declare function isPreflightRequest(req: any): boolean;
7
+ export declare const getCORSConfig: (controller: any, methodName?: string) => CORSConfig | null;
8
+ export declare const getCORSHeaders: (req: any, config: CORSConfig) => Record<string, string>;
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCORSHeaders = exports.getCORSConfig = void 0;
4
+ exports.handleCORS = handleCORS;
5
+ exports.isPreflightRequest = isPreflightRequest;
6
+ const _constants_1 = require("../constants.js");
7
+ function handleCORS(req, res, config) {
8
+ const origin = req.headers.origin || req.headers.Origin || req.url.origin;
9
+ function isOriginAllowed() {
10
+ if (!origin)
11
+ return false;
12
+ if (config.origin === '*')
13
+ return true;
14
+ if (typeof config.origin === 'string')
15
+ return config.origin === origin;
16
+ if (Array.isArray(config.origin))
17
+ return config.origin.includes(origin);
18
+ if (typeof config.origin === 'function')
19
+ return config.origin(origin);
20
+ return false;
21
+ }
22
+ if (origin && !isOriginAllowed()) {
23
+ res.statusCode = 403;
24
+ res.setHeader('Content-Type', 'application/json');
25
+ return { permitted: false, continue: false };
26
+ }
27
+ if (req.method === 'OPTIONS') {
28
+ if (origin) {
29
+ res.setHeader('Access-Control-Allow-Origin', origin);
30
+ }
31
+ else if (config.origin === '*') {
32
+ res.setHeader('Access-Control-Allow-Origin', '*');
33
+ }
34
+ if (config.methods) {
35
+ res.setHeader('Access-Control-Allow-Methods', config.methods.join(', '));
36
+ }
37
+ if (config.allowedHeaders) {
38
+ res.setHeader('Access-Control-Allow-Headers', config.allowedHeaders.join(', '));
39
+ }
40
+ if (config.credentials) {
41
+ res.setHeader('Access-Control-Allow-Credentials', 'true');
42
+ }
43
+ if (config.maxAge) {
44
+ res.setHeader('Access-Control-Max-Age', config.maxAge.toString());
45
+ }
46
+ res.statusCode = config.optionsSuccessStatus || 204;
47
+ return { permitted: true, continue: false };
48
+ }
49
+ if (origin) {
50
+ res.setHeader('Access-Control-Allow-Origin', origin);
51
+ if (config.credentials) {
52
+ res.setHeader('Access-Control-Allow-Credentials', 'true');
53
+ }
54
+ if (config.exposedHeaders) {
55
+ res.setHeader('Access-Control-Expose-Headers', config.exposedHeaders.join(', '));
56
+ }
57
+ }
58
+ return { permitted: true, continue: true };
59
+ }
60
+ function isPreflightRequest(req) {
61
+ return (req.method === 'OPTIONS' && req.headers['access-control-request-method'] && req.headers.origin);
62
+ }
63
+ const getCORSConfig = (controller, methodName) => {
64
+ if (methodName) {
65
+ const methodConfig = Reflect.getMetadata(_constants_1.CORS_METADATA, controller, methodName);
66
+ if (methodConfig) {
67
+ return methodConfig;
68
+ }
69
+ }
70
+ if (controller && controller.constructor) {
71
+ const classConfig = Reflect.getMetadata(_constants_1.CORS_METADATA, controller.constructor.prototype);
72
+ if (classConfig) {
73
+ return classConfig;
74
+ }
75
+ }
76
+ return null;
77
+ };
78
+ exports.getCORSConfig = getCORSConfig;
79
+ const getCORSHeaders = (req, config) => {
80
+ const headers = {};
81
+ const origin = req?.headers?.origin || req?.headers?.Origin;
82
+ if (!origin)
83
+ return headers;
84
+ let allowedOrigin = null;
85
+ if (config.origin === '*') {
86
+ allowedOrigin = '*';
87
+ }
88
+ else if (typeof config.origin === 'string') {
89
+ allowedOrigin = config.origin;
90
+ }
91
+ else if (Array.isArray(config.origin)) {
92
+ if (config.origin.includes(origin)) {
93
+ allowedOrigin = origin;
94
+ }
95
+ }
96
+ else if (typeof config.origin === 'function') {
97
+ if (config.origin(origin)) {
98
+ allowedOrigin = origin;
99
+ }
100
+ }
101
+ else if (config.origin === true) {
102
+ allowedOrigin = origin;
103
+ }
104
+ if (allowedOrigin) {
105
+ headers['Access-Control-Allow-Origin'] = allowedOrigin;
106
+ if (config.credentials) {
107
+ headers['Access-Control-Allow-Credentials'] = 'true';
108
+ }
109
+ if (config.exposedHeaders?.length) {
110
+ headers['Access-Control-Expose-Headers'] = config.exposedHeaders.join(', ');
111
+ }
112
+ if (req.method === 'OPTIONS') {
113
+ if (config.methods?.length) {
114
+ headers['Access-Control-Allow-Methods'] = config.methods.join(', ');
115
+ }
116
+ if (config.allowedHeaders?.length) {
117
+ headers['Access-Control-Allow-Headers'] = config.allowedHeaders.join(', ');
118
+ }
119
+ if (config.maxAge) {
120
+ headers['Access-Control-Max-Age'] = config.maxAge.toString();
121
+ }
122
+ }
123
+ }
124
+ return headers;
125
+ };
126
+ exports.getCORSHeaders = getCORSHeaders;
@@ -1,4 +1,5 @@
1
1
  export * from './controller';
2
+ export * from './cors';
2
3
  export * from './endpoint';
3
4
  export * from './helper';
4
5
  export * from './lambda';
@@ -15,6 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./controller"), exports);
18
+ __exportStar(require("./cors"), exports);
18
19
  __exportStar(require("./endpoint"), exports);
19
20
  __exportStar(require("./helper"), exports);
20
21
  __exportStar(require("./lambda"), exports);
@@ -12,4 +12,5 @@ export declare class MultipartProcessor {
12
12
  files: Record<string, MultipartFile | MultipartFile[]>;
13
13
  };
14
14
  static isMultipart(request: any): boolean;
15
+ private static getContentType;
15
16
  }
@@ -69,10 +69,11 @@ class MultipartProcessor {
69
69
  parts.forEach((part) => {
70
70
  if (part.filename) {
71
71
  const fieldName = part.name || 'file';
72
+ const contentType = this.getContentType(part);
72
73
  const fileData = {
73
74
  fieldname: fieldName,
74
75
  filename: part.filename,
75
- contentType: part.type,
76
+ contentType: contentType ?? part.type,
76
77
  data: part.data,
77
78
  size: part.data.length,
78
79
  encoding: part.encoding,
@@ -105,5 +106,101 @@ class MultipartProcessor {
105
106
  const contentType = request.headers?.['content-type'] || request.headers?.['Content-Type'] || '';
106
107
  return contentType.startsWith('multipart/form-data');
107
108
  }
109
+ static getContentType(part) {
110
+ const filename = part.filename || '';
111
+ const extension = filename.split('.').pop()?.toLowerCase() ?? '';
112
+ const mimeMap = {
113
+ txt: 'text/plain',
114
+ text: 'text/plain',
115
+ log: 'text/plain',
116
+ md: 'text/markdown',
117
+ csv: 'text/csv',
118
+ ts: 'application/typescript',
119
+ tsx: 'application/typescript',
120
+ js: 'application/javascript',
121
+ jsx: 'application/javascript',
122
+ mjs: 'application/javascript',
123
+ cjs: 'application/javascript',
124
+ json: 'application/json',
125
+ xml: 'application/xml',
126
+ yaml: 'application/yaml',
127
+ yml: 'application/yaml',
128
+ toml: 'application/toml',
129
+ php: 'application/x-httpd-php',
130
+ py: 'text/x-python',
131
+ rb: 'text/x-ruby',
132
+ java: 'text/x-java',
133
+ c: 'text/x-c',
134
+ cpp: 'text/x-c++',
135
+ h: 'text/x-c',
136
+ hpp: 'text/x-c++',
137
+ go: 'text/x-go',
138
+ rs: 'text/x-rust',
139
+ swift: 'text/x-swift',
140
+ kt: 'text/x-kotlin',
141
+ kts: 'text/x-kotlin',
142
+ html: 'text/html',
143
+ htm: 'text/html',
144
+ css: 'text/css',
145
+ scss: 'text/x-scss',
146
+ sass: 'text/x-sass',
147
+ less: 'text/x-less',
148
+ jpg: 'image/jpeg',
149
+ jpeg: 'image/jpeg',
150
+ png: 'image/png',
151
+ gif: 'image/gif',
152
+ webp: 'image/webp',
153
+ svg: 'image/svg+xml',
154
+ ico: 'image/x-icon',
155
+ bmp: 'image/bmp',
156
+ tiff: 'image/tiff',
157
+ tif: 'image/tiff',
158
+ avif: 'image/avif',
159
+ heic: 'image/heic',
160
+ heif: 'image/heif',
161
+ pdf: 'application/pdf',
162
+ doc: 'application/msword',
163
+ docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
164
+ xls: 'application/vnd.ms-excel',
165
+ xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
166
+ ppt: 'application/vnd.ms-powerpoint',
167
+ pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
168
+ odt: 'application/vnd.oasis.opendocument.text',
169
+ ods: 'application/vnd.oasis.opendocument.spreadsheet',
170
+ odp: 'application/vnd.oasis.opendocument.presentation',
171
+ zip: 'application/zip',
172
+ rar: 'application/vnd.rar',
173
+ '7z': 'application/x-7z-compressed',
174
+ tar: 'application/x-tar',
175
+ gz: 'application/gzip',
176
+ bz2: 'application/x-bzip2',
177
+ mp3: 'audio/mpeg',
178
+ wav: 'audio/wav',
179
+ ogg: 'audio/ogg',
180
+ m4a: 'audio/mp4',
181
+ flac: 'audio/flac',
182
+ aac: 'audio/aac',
183
+ mp4: 'video/mp4',
184
+ mpg: 'video/mpeg',
185
+ mpeg: 'video/mpeg',
186
+ mov: 'video/quicktime',
187
+ avi: 'video/x-msvideo',
188
+ wmv: 'video/x-ms-wmv',
189
+ flv: 'video/x-flv',
190
+ webm: 'video/webm',
191
+ mkv: 'video/x-matroska',
192
+ m4v: 'video/x-m4v',
193
+ bin: 'application/octet-stream',
194
+ exe: 'application/vnd.microsoft.portable-executable',
195
+ dll: 'application/vnd.microsoft.portable-executable',
196
+ deb: 'application/vnd.debian.binary-package',
197
+ rpm: 'application/x-rpm',
198
+ iso: 'application/x-iso9660-image',
199
+ sh: 'application/x-sh',
200
+ bat: 'application/x-msdos-program',
201
+ ps1: 'application/x-powershell',
202
+ };
203
+ return mimeMap[extension];
204
+ }
108
205
  }
109
206
  exports.MultipartProcessor = MultipartProcessor;
@@ -15,6 +15,7 @@ const resolveConfig = (configOrClass) => {
15
15
  ...decoratorConfig,
16
16
  errorHandler: decoratorConfig.errorHandler ?? errorHandler,
17
17
  interceptors,
18
+ cors: decoratorConfig.cors,
18
19
  controllers: [...controllers, ...(decoratorConfig.controllers || [])],
19
20
  };
20
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quantum-flow",
3
- "version": "1.3.10",
3
+ "version": "1.4.0",
4
4
  "description": "Decorator-based API framework",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",