quantum-flow 1.3.5 → 1.3.7

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 CHANGED
@@ -66,7 +66,7 @@ export class User {
66
66
  @Body(UserDto) body: UserDto,
67
67
  @Query() query: any,
68
68
  @Headers() headers: any,
69
- @Params() params: any,
69
+ @Params(ParamDTO, 'param') params: any,
70
70
  @Request() req: any,
71
71
  @Response() resp: any,
72
72
  @InjectWS() ws: IWebSocketService,
@@ -103,13 +103,17 @@ class HttpServer extends Socket_1.Socket {
103
103
  const request = await this.createRequest(req);
104
104
  let appRequest = await this.applyMiddlewares(request, req, res);
105
105
  let data = await this.findController(appRequest, req, res);
106
+ const isError = !_constants_1.OK_STATUSES.includes(data.status);
107
+ if (isError) {
108
+ return this.handleError(data, req, res, startTime);
109
+ }
106
110
  if (this.config.interceptor) {
107
111
  data = await this.config.interceptor(data, req, res);
108
112
  }
109
- await this.sendResponse(res, data, startTime);
113
+ return this.sendResponse(res, data, startTime);
110
114
  }
111
115
  catch (error) {
112
- await this.handleError(error, req, res, startTime);
116
+ return this.handleError(error, req, res, startTime);
113
117
  }
114
118
  }
115
119
  async createRequest(req) {
@@ -70,7 +70,6 @@ function Controller(config, middlewares = []) {
70
70
  super(...args);
71
71
  }
72
72
  async getResponse(data) {
73
- let y;
74
73
  try {
75
74
  let appResponse = await this.executeControllerMethod(data.controllerInstance, data.name, data.payload, data.request, data.response);
76
75
  let status = appResponse.status ?? 200;
@@ -93,7 +92,6 @@ function Controller(config, middlewares = []) {
93
92
  return { status, data: appResponse };
94
93
  }
95
94
  catch (err) {
96
- console.error(err);
97
95
  throw err;
98
96
  }
99
97
  }
@@ -114,6 +112,7 @@ function Controller(config, middlewares = []) {
114
112
  response,
115
113
  middlewareChain: [],
116
114
  interceptorChain: [],
115
+ errorHandlerChain: [Reflect.getMetadata(_constants_1.CATCH, proto)],
117
116
  subPath: Reflect.getMetadata(_constants_1.ROUTE_PREFIX, proto) || '',
118
117
  };
119
118
  const result = await this.routeWalker(context);
@@ -127,7 +126,7 @@ function Controller(config, middlewares = []) {
127
126
  routePrefix: Reflect.getMetadata(_constants_1.ROUTE_PREFIX, SubController.prototype) || '',
128
127
  middlewares: Reflect.getMetadata(_constants_1.MIDDLEWARES, SubController.prototype) || [],
129
128
  interceptor: Reflect.getMetadata(_constants_1.INTERCEPTOR, SubController.prototype),
130
- errorHandler: Reflect.getMetadata(_constants_1.CATCH, SubController.prototype),
129
+ errorHandler: Reflect.getMetadata(_constants_1.CATCH, SubController),
131
130
  subControllers: Reflect.getMetadata(_constants_1.CONTROLLERS, SubController.prototype) || [],
132
131
  };
133
132
  const fullSubPath = [subPath, subMeta.routePrefix]
@@ -142,6 +141,7 @@ function Controller(config, middlewares = []) {
142
141
  controllerMeta: subMeta,
143
142
  path,
144
143
  middlewareChain: [...context.middlewareChain, ...controllerMeta.middlewares],
144
+ errorHandlerChain: [...context.errorHandlerChain, subMeta.errorHandler].filter((el) => !!el),
145
145
  interceptorChain: [...context.interceptorChain, controllerMeta.interceptor].filter((el) => !!el),
146
146
  });
147
147
  if (subResult && subResult.status !== 404) {
@@ -162,19 +162,21 @@ function Controller(config, middlewares = []) {
162
162
  const mwResult = await mw(payload, context.request, context.response);
163
163
  payload = mwResult ?? payload;
164
164
  }
165
- return this.getResponse({
165
+ let apiResponse = await this.getResponse({
166
166
  interceptors: [...context.interceptorChain, controllerMeta.interceptor].filter((el) => !!el),
167
167
  controllerInstance,
168
168
  name,
169
169
  payload,
170
170
  response: context.response,
171
171
  request: context.request,
172
- }).catch((error) => {
173
- if (controllerMeta.errorHandler) {
174
- return controllerMeta.errorHandler(error, context.request, context.response);
172
+ }).catch((err) => err);
173
+ const isError = !_constants_1.OK_STATUSES.includes(apiResponse.status);
174
+ if (isError) {
175
+ for (const handler of context.errorHandlerChain?.reverse() || []) {
176
+ apiResponse = handler(apiResponse);
175
177
  }
176
- return error;
177
- });
178
+ }
179
+ return apiResponse;
178
180
  }
179
181
  return null;
180
182
  }
@@ -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, IController, InterceptorCB, IWebSocketService, MiddlewareCB, ResponseWithStatus, Router, WebSocketClient, WebSocketEvent, WebSocketMessage, } from '../types/index.js';
7
+ export { AppRequest, 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';
@@ -7,12 +7,12 @@ export declare const Body: (dto?: any) => (target: any, propertyKey: string | sy
7
7
  * Parameter decorator to extract route parameters.
8
8
  * @param name Optional name of the parameter to extract.
9
9
  */
10
- export declare const Params: (name?: string) => (target: any, propertyKey: string | symbol, parameterIndex: number) => void;
10
+ export declare const Params: (dto?: any, name?: string) => (target: any, propertyKey: string | symbol, parameterIndex: number) => void;
11
11
  /**
12
12
  * Parameter decorator to extract query parameters.
13
13
  * @param name Optional name of the query parameter to extract.
14
14
  */
15
- export declare const Query: (name?: string) => (target: any, propertyKey: string | symbol, parameterIndex: number) => void;
15
+ export declare const Query: (dto?: any, name?: string) => (target: any, propertyKey: string | symbol, parameterIndex: number) => void;
16
16
  /**
17
17
  * Parameter decorator to inject the entire request object.
18
18
  */
@@ -12,13 +12,13 @@ exports.Body = Body;
12
12
  * Parameter decorator to extract route parameters.
13
13
  * @param name Optional name of the parameter to extract.
14
14
  */
15
- const Params = (name) => (0, _utils_1.createParamDecorator)('params', undefined, name);
15
+ const Params = (dto, name) => (0, _utils_1.createParamDecorator)('params', typeof dto == 'string' ? undefined : dto, typeof dto == 'string' ? dto : name);
16
16
  exports.Params = Params;
17
17
  /**
18
18
  * Parameter decorator to extract query parameters.
19
19
  * @param name Optional name of the query parameter to extract.
20
20
  */
21
- const Query = (name) => (0, _utils_1.createParamDecorator)('query', undefined, name);
21
+ const Query = (dto, name) => (0, _utils_1.createParamDecorator)('query', typeof dto == 'string' ? undefined : dto, typeof dto == 'string' ? dto : name);
22
22
  exports.Query = Query;
23
23
  /**
24
24
  * Parameter decorator to inject the entire request object.
@@ -67,8 +67,5 @@ exports.User = User = __decorate([
67
67
  interceptor: (data, req, res) => {
68
68
  return { data, intercepted: true };
69
69
  },
70
- }),
71
- (0, core_1.Catch)((err) => {
72
- return { status: 401, err };
73
70
  })
74
71
  ], User);
@@ -13,7 +13,16 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.UserMetadata = void 0;
16
+ const class_validator_1 = require("class-validator");
16
17
  const core_1 = require("quantum-flow/core");
18
+ class DTO {
19
+ constructor() { }
20
+ meta;
21
+ }
22
+ __decorate([
23
+ (0, class_validator_1.IsString)(),
24
+ __metadata("design:type", String)
25
+ ], DTO.prototype, "meta", void 0);
17
26
  let UserMetadata = class UserMetadata {
18
27
  async getUserMetadata(params) {
19
28
  return params;
@@ -21,8 +30,8 @@ let UserMetadata = class UserMetadata {
21
30
  };
22
31
  exports.UserMetadata = UserMetadata;
23
32
  __decorate([
24
- (0, core_1.GET)('/:name'),
25
- __param(0, (0, core_1.Params)()),
33
+ (0, core_1.GET)('/:meta'),
34
+ __param(0, (0, core_1.Params)(DTO, 'meta')),
26
35
  __metadata("design:type", Function),
27
36
  __metadata("design:paramtypes", [Object]),
28
37
  __metadata("design:returntype", Promise)
@@ -15,18 +15,23 @@ let Root = class Root {
15
15
  Root = __decorate([
16
16
  (0, core_1.Controller)({ prefix: 'api', controllers: [user_1.User] })
17
17
  ], Root);
18
- let App = class App {
18
+ let App =
19
+ // @Catch((error) => ({ status: 400, error }))
20
+ class App {
19
21
  };
20
22
  App = __decorate([
21
23
  (0, http_1.Server)({
22
24
  controllers: [Root],
23
25
  websocket: { enabled: true },
24
26
  interceptor: (data) => data,
27
+ errorHandler: (err) => {
28
+ return err;
29
+ },
25
30
  }),
26
31
  (0, http_1.Port)(3000),
27
32
  (0, core_1.Use)((data) => data),
28
- (0, core_1.Use)((data) => data),
29
- (0, core_1.Catch)((error) => ({ status: 400, error }))
33
+ (0, core_1.Use)((data) => data)
34
+ // @Catch((error) => ({ status: 400, error }))
30
35
  ], App);
31
36
  const server = new http_1.HttpServer(App);
32
37
  server.listen().catch(console.error);
@@ -1,5 +1,14 @@
1
1
  import { IncomingHttpHeaders, IncomingMessage, ServerResponse } from 'http';
2
2
  type P_Q = Record<string, string | undefined> | null | unknown;
3
+ export interface HttpError extends Error {
4
+ statusCode?: number;
5
+ status: number;
6
+ data?: any;
7
+ messages?: string[];
8
+ errors?: Array<{
9
+ message: string;
10
+ }>;
11
+ }
3
12
  export type AppRequest<B = unknown, Q extends P_Q = unknown, P extends P_Q = unknown> = {
4
13
  method: HTTP_METHODS;
5
14
  url: URL;
@@ -40,7 +49,7 @@ export interface IController {
40
49
  }
41
50
  export type MiddlewareCB = (appRequest: AppRequest, request?: IncomingMessage, response?: ServerResponse) => void | Promise<AppRequest> | AppRequest;
42
51
  export type InterceptorCB = (data: any, req?: IncomingMessage, res?: ServerResponse) => Promise<unknown> | unknown;
43
- export type ErrorCB = (error: Error, req?: IncomingMessage, res?: ServerResponse) => Promise<ResponseWithStatus> | ResponseWithStatus;
52
+ export type ErrorCB = (error: HttpError, req?: IncomingMessage, res?: ServerResponse) => Promise<ResponseWithStatus> | ResponseWithStatus;
44
53
  export type ParamDecoratorType = 'body' | 'params' | 'query' | 'request' | 'headers' | 'cookies' | 'response' | 'multipart' | 'event' | 'context';
45
54
  export interface ParamMetadata {
46
55
  index: number;
@@ -33,5 +33,6 @@ export type RouteContext = {
33
33
  response?: ServerResponse;
34
34
  middlewareChain: MiddlewareCB[];
35
35
  interceptorChain: InterceptorCB[];
36
+ errorHandlerChain: ErrorCB[];
36
37
  subPath: string;
37
38
  };
@@ -43,10 +43,10 @@ const executeControllerMethod = async (controller, propertyName, payload, reques
43
43
  }
44
44
  const prototype = Object.getPrototypeOf(controller);
45
45
  const paramMetadata = Reflect.getMetadata(_constants_1.PARAM_METADATA_KEY, prototype, propertyName) || [];
46
- const { body, multipart } = getBodyAndMultipart(payload);
47
46
  if (paramMetadata.length === 0) {
48
47
  return fn.call(controller, payload);
49
48
  }
49
+ const { body, multipart } = getBodyAndMultipart(payload);
50
50
  const args = [];
51
51
  const wsParams = Reflect.getMetadata(_constants_1.WS_SERVICE_KEY, controller, propertyName) || [];
52
52
  const totalParams = Math.max(paramMetadata.length ? Math.max(...paramMetadata.map((p) => p.index)) + 1 : 0, wsParams.length ? Math.max(...wsParams.map((p) => p.index)) + 1 : 0);
@@ -78,7 +78,7 @@ const executeControllerMethod = async (controller, propertyName, payload, reques
78
78
  value = response;
79
79
  }
80
80
  if (_constants_1.TO_VALIDATE.includes(param.type)) {
81
- value = await (0, validate_1.validate)(param.dto, value);
81
+ value = await (0, validate_1.validate)(param.dto, typeof value === 'string' ? { [param.name ?? '']: value } : value);
82
82
  }
83
83
  args[i] = value;
84
84
  }
@@ -8,6 +8,5 @@ function createParamDecorator(type, dto, name) {
8
8
  existingParams.push({ index: parameterIndex, type, dto, name });
9
9
  existingParams.sort((a, b) => a.index - b.index);
10
10
  Reflect.defineMetadata(_constants_1.PARAM_METADATA_KEY, existingParams, target, propertyKey);
11
- const saved = Reflect.getMetadata(_constants_1.PARAM_METADATA_KEY, target, propertyKey);
12
11
  };
13
12
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quantum-flow",
3
- "version": "1.3.5",
3
+ "version": "1.3.7",
4
4
  "description": "Decorator-based API framework",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,3 +0,0 @@
1
- type ToValidate = 'query' | 'body' | 'params' | 'headers';
2
- export declare function Validate(param: ToValidate, dtoClass: any): (target: any, propertyKey?: string, descriptor?: PropertyDescriptor) => void;
3
- export {};
@@ -1,40 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Validate = Validate;
4
- /* eslint-disable @typescript-eslint/no-explicit-any */
5
- const class_validator_1 = require("class-validator");
6
- function Validate(param, dtoClass) {
7
- return function (target, propertyKey, descriptor) {
8
- // METHOD DECORATOR
9
- if (descriptor) {
10
- wrapMethod(descriptor, param, dtoClass);
11
- return;
12
- }
13
- // CLASS DECORATOR
14
- const prototype = target.prototype;
15
- Object.getOwnPropertyNames(prototype).forEach((method) => {
16
- if (method === 'constructor')
17
- return;
18
- const desc = Object.getOwnPropertyDescriptor(prototype, method);
19
- if (!desc || typeof desc.value !== 'function')
20
- return;
21
- wrapMethod(desc, param, dtoClass);
22
- Object.defineProperty(prototype, method, desc);
23
- });
24
- };
25
- }
26
- function wrapMethod(descriptor, param, dtoClass) {
27
- const originalMethod = descriptor.value;
28
- descriptor.value = async function (...args) {
29
- const value = args[0][param];
30
- const instance = new dtoClass();
31
- Object.entries(value || {}).forEach(([key, val]) => {
32
- instance[key] = val;
33
- });
34
- const errors = await (0, class_validator_1.validate)(instance, { whitelist: true });
35
- if (errors.length) {
36
- throw { status: 422, message: 'Validation failed', data: errors };
37
- }
38
- return originalMethod.apply(this, args);
39
- };
40
- }
@@ -1 +0,0 @@
1
- export * from './Validate';
@@ -1,17 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./Validate"), exports);