quantum-flow 1.4.0 → 1.7.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 (66) hide show
  1. package/README.md +20 -11
  2. package/dist/app/aws/lambda.d.ts +0 -3
  3. package/dist/app/aws/lambda.js +16 -119
  4. package/dist/app/aws/utils/helpers.d.ts +4 -0
  5. package/dist/app/aws/utils/helpers.js +83 -0
  6. package/dist/app/aws/utils/index.d.ts +3 -0
  7. package/dist/app/aws/utils/index.js +19 -0
  8. package/dist/app/aws/utils/request.d.ts +23 -0
  9. package/dist/app/aws/utils/request.js +96 -0
  10. package/dist/app/aws/utils/response.d.ts +13 -6
  11. package/dist/app/aws/utils/response.js +32 -8
  12. package/dist/app/http/Application.d.ts +1 -1
  13. package/dist/app/http/Application.js +29 -24
  14. package/dist/constants.d.ts +1 -0
  15. package/dist/constants.js +2 -1
  16. package/dist/core/Controller.d.ts +6 -17
  17. package/dist/core/Controller.js +80 -80
  18. package/dist/core/Endpoint.js +1 -2
  19. package/dist/core/index.d.ts +1 -1
  20. package/dist/core/utils/index.d.ts +0 -3
  21. package/dist/core/utils/index.js +0 -3
  22. package/dist/examples/app.d.ts +0 -1
  23. package/dist/examples/app.js +69 -10
  24. package/dist/examples/controllers/user.js +43 -8
  25. package/dist/examples/controllers/userMetadata.js +54 -12
  26. package/dist/middlewares/catch.d.ts +2 -0
  27. package/dist/middlewares/catch.js +10 -0
  28. package/dist/middlewares/cors.d.ts +2 -0
  29. package/dist/{core/utils → middlewares}/cors.js +4 -4
  30. package/dist/middlewares/index.d.ts +5 -0
  31. package/dist/middlewares/index.js +21 -0
  32. package/dist/middlewares/sanitize.d.ts +2 -0
  33. package/dist/middlewares/sanitize.js +15 -0
  34. package/dist/{core/utils/helpers.js → middlewares/status.js} +1 -1
  35. package/dist/middlewares/use.d.ts +2 -0
  36. package/dist/middlewares/use.js +11 -0
  37. package/dist/types/common.d.ts +15 -19
  38. package/dist/types/controller.d.ts +4 -5
  39. package/dist/types/http.d.ts +2 -0
  40. package/dist/types/index.d.ts +2 -0
  41. package/dist/types/index.js +2 -0
  42. package/dist/types/lambda.d.ts +7 -22
  43. package/dist/types/multipart.d.ts +8 -0
  44. package/dist/types/multipart.js +2 -0
  45. package/dist/types/sanitize.d.ts +8 -0
  46. package/dist/types/sanitize.js +2 -0
  47. package/dist/utils/controller.d.ts +20 -4
  48. package/dist/utils/controller.js +64 -22
  49. package/dist/utils/cors.d.ts +2 -2
  50. package/dist/utils/cors.js +2 -1
  51. package/dist/utils/headers.d.ts +2 -0
  52. package/dist/utils/headers.js +9 -0
  53. package/dist/utils/index.d.ts +2 -0
  54. package/dist/utils/index.js +2 -0
  55. package/dist/utils/multipart.d.ts +1 -8
  56. package/dist/utils/multipart.js +0 -1
  57. package/dist/utils/sanitize.d.ts +30 -0
  58. package/dist/utils/sanitize.js +134 -0
  59. package/dist/utils/server.js +4 -0
  60. package/package.json +9 -2
  61. package/dist/app/aws/helpers.d.ts +0 -25
  62. package/dist/app/aws/helpers.js +0 -46
  63. package/dist/core/utils/cors.d.ts +0 -2
  64. package/dist/core/utils/middlewares.d.ts +0 -3
  65. package/dist/core/utils/middlewares.js +0 -22
  66. /package/dist/{core/utils/helpers.d.ts → middlewares/status.d.ts} +0 -0
@@ -1,11 +1,4 @@
1
- export interface MultipartFile {
2
- fieldname: string;
3
- filename: string;
4
- contentType: string;
5
- data: Buffer;
6
- size: number;
7
- encoding?: string;
8
- }
1
+ import { MultipartFile } from '../types/index.js';
9
2
  export declare class MultipartProcessor {
10
3
  static parse(request: any): {
11
4
  fields: Record<string, any>;
@@ -34,7 +34,6 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.MultipartProcessor = void 0;
37
- // utils/MultipartProcessor.ts
38
37
  const multipart = __importStar(require("parse-multipart-data"));
39
38
  class MultipartProcessor {
40
39
  static parse(request) {
@@ -0,0 +1,30 @@
1
+ import { AppRequest, SanitizerConfig } from '../types/index.js';
2
+ import * as Joi from 'joi';
3
+ export declare const SanitizeSchemas: {
4
+ string: {
5
+ trim: () => Joi.StringSchema<string>;
6
+ email: () => Joi.StringSchema<string>;
7
+ name: () => Joi.StringSchema<string>;
8
+ slug: () => Joi.StringSchema<string>;
9
+ phone: () => Joi.StringSchema<string>;
10
+ };
11
+ number: {
12
+ integer: () => Joi.NumberSchema<number>;
13
+ positive: () => Joi.NumberSchema<number>;
14
+ range: (min: number, max: number) => Joi.NumberSchema<number>;
15
+ };
16
+ object: {
17
+ stripUnknown: (schema: Joi.Schema) => Joi.ObjectSchema<any>;
18
+ withDefaults: (schema: Joi.Schema) => Joi.ObjectSchema<any>;
19
+ };
20
+ date: {
21
+ iso: () => Joi.DateSchema<Date>;
22
+ timestamp: () => Joi.DateSchema<Date>;
23
+ };
24
+ xss: () => Joi.StringSchema<string>;
25
+ };
26
+ export declare function applyJoiSanitization(value: any, config: SanitizerConfig): {
27
+ value: any;
28
+ error?: Joi.ValidationError;
29
+ };
30
+ export declare const sanitizeRequest: (request: AppRequest, config: SanitizerConfig[]) => void;
@@ -0,0 +1,134 @@
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.sanitizeRequest = exports.SanitizeSchemas = void 0;
37
+ exports.applyJoiSanitization = applyJoiSanitization;
38
+ const Joi = __importStar(require("joi"));
39
+ exports.SanitizeSchemas = {
40
+ string: {
41
+ trim: () => Joi.string().trim(),
42
+ email: () => Joi.string().email().trim().lowercase(),
43
+ name: () => Joi.string()
44
+ .trim()
45
+ .min(2)
46
+ .max(50)
47
+ .pattern(/^[a-zA-Z\s-]+$/),
48
+ slug: () => Joi.string()
49
+ .trim()
50
+ .lowercase()
51
+ .pattern(/^[a-z0-9-]+$/),
52
+ phone: () => Joi.string()
53
+ .trim()
54
+ .pattern(/^[\d\s\+\-\(\)]+$/),
55
+ },
56
+ number: {
57
+ integer: () => Joi.number().integer(),
58
+ positive: () => Joi.number().positive(),
59
+ range: (min, max) => Joi.number().min(min).max(max),
60
+ },
61
+ object: {
62
+ stripUnknown: (schema) => Joi.object(schema).unknown(false),
63
+ withDefaults: (schema) => Joi.object(schema).options({ stripUnknown: true }),
64
+ },
65
+ date: {
66
+ iso: () => Joi.date().iso(),
67
+ timestamp: () => Joi.date().timestamp(),
68
+ },
69
+ xss: () => Joi.string().custom((value, helpers) => {
70
+ if (typeof value !== 'string')
71
+ return value;
72
+ const sanitized = value
73
+ .replace(/javascript:/gi, '')
74
+ .replace(/on\w+=/gi, '')
75
+ .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
76
+ .replace(/data:/gi, '');
77
+ return sanitized;
78
+ }, 'XSS sanitization'),
79
+ };
80
+ function applyJoiSanitization(value, config) {
81
+ if (!['headers', 'body', 'params', 'query'].includes(config.type)) {
82
+ return { value };
83
+ }
84
+ if (value === null || value === undefined) {
85
+ return { value };
86
+ }
87
+ const action = config.action || 'both';
88
+ const options = {
89
+ convert: true,
90
+ stripUnknown: config.stripUnknown ?? true,
91
+ abortEarly: false,
92
+ ...config.options,
93
+ };
94
+ try {
95
+ let result;
96
+ switch (action) {
97
+ case 'validate':
98
+ result = config.schema.validate(value, { ...options, convert: false, noDefaults: true });
99
+ break;
100
+ case 'sanitize':
101
+ result = config.schema.validate(value, {
102
+ ...options,
103
+ convert: true,
104
+ presence: 'optional',
105
+ noDefaults: false,
106
+ });
107
+ break;
108
+ case 'both':
109
+ default:
110
+ result = config.schema.validate(value, options);
111
+ break;
112
+ }
113
+ return {
114
+ value: result.value,
115
+ error: result.error,
116
+ };
117
+ }
118
+ catch (error) {
119
+ return {
120
+ value,
121
+ error: error,
122
+ };
123
+ }
124
+ }
125
+ const sanitizeRequest = (request, config) => {
126
+ config.forEach((conf) => {
127
+ const { value, error } = applyJoiSanitization(request[conf.type], conf);
128
+ if (error) {
129
+ throw { error, status: 400 };
130
+ }
131
+ request[conf.type] = value;
132
+ });
133
+ };
134
+ exports.sanitizeRequest = sanitizeRequest;
@@ -9,14 +9,18 @@ const resolveConfig = (configOrClass) => {
9
9
  const controllers = Reflect.getMetadata(_constants_1.SERVER_MODULES_KEY, configOrClass) || [];
10
10
  const errorHandler = Reflect.getMetadata(_constants_1.CATCH, configOrClass);
11
11
  const interceptors = Reflect.getMetadata(_constants_1.INTECEPT, configOrClass);
12
+ const middlewares = Reflect.getMetadata(_constants_1.USE_MIDDLEWARE, configOrClass);
13
+ const sanitizers = Reflect.getMetadata(_constants_1.SANITIZE, configOrClass.prototype) || [];
12
14
  config = {
13
15
  port: 3000,
14
16
  host: 'localhost',
15
17
  ...decoratorConfig,
16
18
  errorHandler: decoratorConfig.errorHandler ?? errorHandler,
17
19
  interceptors,
20
+ middlewares: decoratorConfig.middlewares.concat(middlewares),
18
21
  cors: decoratorConfig.cors,
19
22
  controllers: [...controllers, ...(decoratorConfig.controllers || [])],
23
+ sanitizers,
20
24
  };
21
25
  }
22
26
  else if (configOrClass && typeof configOrClass === 'object') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quantum-flow",
3
- "version": "1.4.0",
3
+ "version": "1.7.0",
4
4
  "description": "Decorator-based API framework",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -30,6 +30,11 @@
30
30
  "import": "./dist/app/aws/index.js",
31
31
  "require": "./dist/app/aws/index.js",
32
32
  "types": "./dist/app/aws/index.d.ts"
33
+ },
34
+ "./middlewares": {
35
+ "import": "./dist/middlewares/index.js",
36
+ "require": "./dist/middlewares/index.js",
37
+ "types": "./dist/middlewares/index.d.ts"
33
38
  }
34
39
  },
35
40
  "repository": {
@@ -54,12 +59,14 @@
54
59
  "aws-lambda": "^1.0.7",
55
60
  "class-transformer": "^0.5.1",
56
61
  "class-validator": "^0.15.1",
62
+ "joi": "^18.0.2",
57
63
  "parse-multipart-data": "^1.5.0",
58
64
  "reflect-metadata": "^0.2.2",
59
65
  "tsconfig-paths": "^4.2.0",
60
66
  "typescript": ">=4.0.0",
61
67
  "uuid": "^13.0.0",
62
- "ws": "^8.19.0"
68
+ "ws": "^8.19.0",
69
+ "xss": "^1.0.15"
63
70
  },
64
71
  "peerDependencies": {
65
72
  "ts-node": ">=10.9.2",
@@ -1,25 +0,0 @@
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
- }
@@ -1,46 +0,0 @@
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,2 +0,0 @@
1
- import { CORSConfig } from '../../types/index.js';
2
- export declare function CORS(config?: CORSConfig): (target: any, propertyKey?: string, descriptor?: PropertyDescriptor) => void;
@@ -1,3 +0,0 @@
1
- import { ErrorCB, MiddlewareCB } from '../../types/index.js';
2
- export declare function Use(middleware: MiddlewareCB): (target: any) => any;
3
- export declare function Catch(handler: ErrorCB): (target: any) => any;
@@ -1,22 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Use = Use;
4
- exports.Catch = Catch;
5
- const _constants_1 = require("../../constants.js");
6
- function Use(middleware) {
7
- return function (target) {
8
- const config = Reflect.getMetadata(_constants_1.SERVER_CONFIG_KEY, target) || {};
9
- const mergedConfig = {
10
- ...config,
11
- middlewares: [...(config?.middlewares ?? []), middleware].filter((el) => !!el),
12
- };
13
- Reflect.defineMetadata(_constants_1.SERVER_CONFIG_KEY, mergedConfig, target);
14
- return target;
15
- };
16
- }
17
- function Catch(handler) {
18
- return function (target) {
19
- Reflect.defineMetadata(_constants_1.CATCH, handler, target);
20
- return target;
21
- };
22
- }