quantum-flow 1.3.2 → 1.3.6

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,
@@ -36,7 +36,7 @@ class HttpServer extends Socket_1.Socket {
36
36
  ║ 🔌 Port: ${this.config.port}
37
37
  ║ 🔌 Websocket: ${!!this.config.websocket}
38
38
  ║ 🔧 Global Middlewares: ${this.config.middlewares?.length || 0}
39
- ║ 🔧 Error middlewares: ${this.config.errorHandler?.length || 0}
39
+ ║ 🔧 Error handler: ${!this.config.errorHandler}
40
40
  ║ 🎯 Global Interceptors: ${!!this.config.interceptor?.length}
41
41
  ║ 📦 Controllers: ${_constants_1.STATISTIC.controllers}
42
42
  ║ 📦 Routes: ${_constants_1.STATISTIC.routes}
@@ -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) {
@@ -141,9 +145,7 @@ class HttpServer extends Socket_1.Socket {
141
145
  let processed = appRequest;
142
146
  for (const middleware of this.config.middlewares?.reverse() || []) {
143
147
  const result = await middleware(processed, request, response);
144
- if (result) {
145
- processed = result;
146
- }
148
+ processed = result ?? processed;
147
149
  }
148
150
  return processed;
149
151
  }
@@ -1,4 +1,4 @@
1
- import { AppRequest, ControllerClass, ControllerConfig, ControllerInstance, InterceptorCB, RouteContext } from '../types/index.js';
1
+ import { AppRequest, ControllerClass, ControllerConfig, ControllerInstance, InterceptorCB, MiddlewareCB, RouteContext } from '../types/index.js';
2
2
  import { IncomingMessage, ServerResponse } from 'http';
3
3
  import 'reflect-metadata';
4
4
  /**
@@ -45,8 +45,8 @@ export declare function Controller(config: string | ControllerConfig, middleware
45
45
  name: string;
46
46
  pathParams: Record<string, string>;
47
47
  priority: number;
48
- methodMiddlewares: any[];
49
- methodInterceptors: any[];
48
+ methodMiddlewares: MiddlewareCB[];
49
+ methodInterceptors: InterceptorCB[];
50
50
  };
51
51
  };
52
52
  } & T;
@@ -92,7 +92,6 @@ function Controller(config, middlewares = []) {
92
92
  return { status, data: appResponse };
93
93
  }
94
94
  catch (err) {
95
- console.error(err);
96
95
  throw err;
97
96
  }
98
97
  }
@@ -113,6 +112,7 @@ function Controller(config, middlewares = []) {
113
112
  response,
114
113
  middlewareChain: [],
115
114
  interceptorChain: [],
115
+ errorHandlerChain: [Reflect.getMetadata(_constants_1.CATCH, proto)],
116
116
  subPath: Reflect.getMetadata(_constants_1.ROUTE_PREFIX, proto) || '',
117
117
  };
118
118
  const result = await this.routeWalker(context);
@@ -126,7 +126,7 @@ function Controller(config, middlewares = []) {
126
126
  routePrefix: Reflect.getMetadata(_constants_1.ROUTE_PREFIX, SubController.prototype) || '',
127
127
  middlewares: Reflect.getMetadata(_constants_1.MIDDLEWARES, SubController.prototype) || [],
128
128
  interceptor: Reflect.getMetadata(_constants_1.INTERCEPTOR, SubController.prototype),
129
- errorHandler: Reflect.getMetadata(_constants_1.CATCH, SubController.prototype),
129
+ errorHandler: Reflect.getMetadata(_constants_1.CATCH, SubController),
130
130
  subControllers: Reflect.getMetadata(_constants_1.CONTROLLERS, SubController.prototype) || [],
131
131
  };
132
132
  const fullSubPath = [subPath, subMeta.routePrefix]
@@ -141,6 +141,7 @@ function Controller(config, middlewares = []) {
141
141
  controllerMeta: subMeta,
142
142
  path,
143
143
  middlewareChain: [...context.middlewareChain, ...controllerMeta.middlewares],
144
+ errorHandlerChain: [...context.errorHandlerChain, subMeta.errorHandler].filter((el) => !!el),
144
145
  interceptorChain: [...context.interceptorChain, controllerMeta.interceptor].filter((el) => !!el),
145
146
  });
146
147
  if (subResult && subResult.status !== 404) {
@@ -159,21 +160,23 @@ function Controller(config, middlewares = []) {
159
160
  let payload = { ...context.appRequest, params: pathParams };
160
161
  for (const mw of allMiddlewares) {
161
162
  const mwResult = await mw(payload, context.request, context.response);
162
- payload = { ...payload, ...mwResult };
163
+ payload = mwResult ?? payload;
163
164
  }
164
- return this.getResponse({
165
+ let apiResponse = await this.getResponse({
165
166
  interceptors: [...context.interceptorChain, controllerMeta.interceptor].filter((el) => !!el),
166
167
  controllerInstance,
167
168
  name,
168
169
  payload,
169
170
  response: context.response,
170
171
  request: context.request,
171
- }).catch((error) => {
172
- if (controllerMeta.errorHandler) {
173
- 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);
174
177
  }
175
- return error;
176
- });
178
+ }
179
+ return apiResponse;
177
180
  }
178
181
  return null;
179
182
  }
@@ -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.
@@ -59,11 +59,13 @@ exports.User = User = __decorate([
59
59
  (0, core_1.Controller)({
60
60
  prefix: 'user',
61
61
  controllers: [userMetadata_1.UserMetadata],
62
+ middlewares: [
63
+ (req) => {
64
+ return req;
65
+ },
66
+ ],
62
67
  interceptor: (data, req, res) => {
63
68
  return { data, intercepted: true };
64
69
  },
65
- }),
66
- (0, core_1.Catch)((err) => {
67
- return { status: 401, err };
68
70
  })
69
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;
@@ -38,9 +47,9 @@ export type AxiosQuery = {
38
47
  export interface IController {
39
48
  handleRequest: Router;
40
49
  }
41
- export type MiddlewareCB = (appRequest: AppRequest, request?: IncomingMessage, respinse?: ServerResponse) => Promise<AppRequest> | AppRequest;
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.2",
3
+ "version": "1.3.6",
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);