@zenofolio/hyper-decor 1.0.4 → 1.0.8

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 (189) hide show
  1. package/.agent/rules/philosophy.md +103 -0
  2. package/.agent/rules/writing.md +32 -0
  3. package/README.md +107 -142
  4. package/dist/__internals/constants.d.ts +1 -58
  5. package/dist/__internals/constants.js +3 -65
  6. package/dist/__internals/helpers/lifecycle.helper.d.ts +3 -0
  7. package/dist/__internals/helpers/lifecycle.helper.js +25 -0
  8. package/dist/__internals/helpers/merge-metadata.d.ts +2 -3
  9. package/dist/__internals/helpers/merge-metadata.js +43 -23
  10. package/dist/__internals/helpers/prepare.helper.d.ts +5 -0
  11. package/dist/__internals/helpers/prepare.helper.js +392 -0
  12. package/dist/__internals/stores/hyper.store.d.ts +5 -0
  13. package/dist/__internals/stores/hyper.store.js +5 -0
  14. package/dist/__internals/stores/index.d.ts +4 -15
  15. package/dist/__internals/stores/index.js +18 -35
  16. package/dist/__internals/stores/meta.store.d.ts +34 -0
  17. package/dist/__internals/stores/meta.store.js +107 -0
  18. package/dist/__internals/stores/scope.store.d.ts +14 -0
  19. package/dist/__internals/stores/scope.store.js +29 -0
  20. package/dist/__internals/stores/serivces.store.d.ts +1 -0
  21. package/dist/__internals/stores/{store.interface.js → serivces.store.js} +2 -0
  22. package/dist/__internals/transform/middleware.transform.d.ts +3 -0
  23. package/dist/__internals/transform/middleware.transform.js +19 -0
  24. package/dist/__internals/transform/role.transform.d.ts +1 -1
  25. package/dist/__internals/transform/role.transform.js +10 -7
  26. package/dist/__internals/transform/scope.transfrom.d.ts +5 -7
  27. package/dist/__internals/transform/scope.transfrom.js +53 -39
  28. package/dist/__internals/transform/transform.registry.d.ts +33 -0
  29. package/dist/__internals/transform/transform.registry.js +59 -0
  30. package/dist/__internals/types.d.ts +53 -4
  31. package/dist/__internals/utils/function.util.d.ts +1 -4
  32. package/dist/__internals/utils/function.util.js +22 -10
  33. package/dist/common/bootstrap.d.ts +6 -2
  34. package/dist/common/bootstrap.js +51 -8
  35. package/dist/common/helpers/index.d.ts +1 -0
  36. package/dist/common/helpers/index.js +1 -0
  37. package/dist/common/helpers/scopes.d.ts +3 -3
  38. package/dist/common/helpers/scopes.js +7 -8
  39. package/dist/common/helpers/state.d.ts +17 -0
  40. package/dist/common/helpers/state.js +44 -0
  41. package/dist/common/message-bus.d.ts +11 -0
  42. package/dist/common/message-bus.js +51 -0
  43. package/dist/common/testing.d.ts +56 -0
  44. package/dist/common/testing.js +193 -0
  45. package/dist/common/transport.d.ts +10 -0
  46. package/dist/common/transport.js +59 -0
  47. package/dist/constants.d.ts +1 -0
  48. package/dist/constants.js +2 -1
  49. package/dist/decorators.d.ts +1 -0
  50. package/dist/{common/openapi/index.js → decorators.js} +1 -2
  51. package/dist/extension.js +11 -2
  52. package/dist/index.d.ts +11 -3
  53. package/dist/index.js +11 -3
  54. package/dist/lib/event/meta.store.d.ts +4 -0
  55. package/dist/lib/event/meta.store.js +5 -0
  56. package/dist/lib/openapi/collectors/class.collector.d.ts +5 -0
  57. package/dist/lib/openapi/collectors/class.collector.js +10 -0
  58. package/dist/lib/openapi/collectors/index.d.ts +3 -0
  59. package/dist/lib/openapi/collectors/index.js +19 -0
  60. package/dist/lib/openapi/collectors/method.collector.d.ts +7 -0
  61. package/dist/lib/openapi/collectors/method.collector.js +101 -0
  62. package/dist/lib/openapi/collectors/schema.collector.d.ts +6 -0
  63. package/dist/lib/openapi/collectors/schema.collector.js +29 -0
  64. package/dist/lib/openapi/constants.d.ts +47 -0
  65. package/dist/lib/openapi/constants.js +61 -0
  66. package/dist/lib/openapi/decorators.d.ts +16 -0
  67. package/dist/lib/openapi/decorators.js +93 -0
  68. package/dist/lib/openapi/index.d.ts +30 -0
  69. package/dist/lib/openapi/index.js +136 -0
  70. package/dist/lib/openapi/metadata.d.ts +7 -0
  71. package/dist/lib/openapi/metadata.js +8 -0
  72. package/dist/lib/openapi/metadata.registry.d.ts +29 -0
  73. package/dist/lib/openapi/metadata.registry.js +41 -0
  74. package/dist/lib/openapi/types.d.ts +131 -0
  75. package/dist/lib/server/decorators/File.d.ts +37 -0
  76. package/dist/{decorators → lib/server/decorators}/File.js +62 -75
  77. package/dist/lib/server/decorators/Http.d.ts +12 -0
  78. package/dist/lib/server/decorators/Http.js +56 -0
  79. package/dist/lib/server/decorators/HyperApp.d.ts +7 -0
  80. package/dist/lib/server/decorators/HyperApp.js +14 -0
  81. package/dist/lib/server/decorators/HyperController.d.ts +6 -0
  82. package/dist/lib/server/decorators/HyperController.js +15 -0
  83. package/dist/lib/server/decorators/HyperModule.d.ts +6 -0
  84. package/dist/lib/server/decorators/HyperModule.js +13 -0
  85. package/dist/lib/server/decorators/HyperService.d.ts +12 -0
  86. package/dist/lib/server/decorators/HyperService.js +30 -0
  87. package/dist/lib/server/decorators/Messaging.d.ts +8 -0
  88. package/dist/lib/server/decorators/Messaging.js +19 -0
  89. package/dist/lib/server/decorators/Middleware.d.ts +18 -0
  90. package/dist/lib/server/decorators/Middleware.js +52 -0
  91. package/dist/lib/server/decorators/Output.d.ts +6 -0
  92. package/dist/lib/server/decorators/Output.js +14 -0
  93. package/dist/lib/server/decorators/Pass.d.ts +10 -0
  94. package/dist/lib/server/decorators/Pass.js +13 -0
  95. package/dist/lib/server/decorators/Role.d.ts +7 -0
  96. package/dist/lib/server/decorators/Role.js +14 -0
  97. package/dist/lib/server/decorators/Routes.d.ts +14 -0
  98. package/dist/lib/server/decorators/Routes.js +39 -0
  99. package/dist/lib/server/decorators/Scope.d.ts +7 -0
  100. package/dist/lib/server/decorators/Scope.js +14 -0
  101. package/dist/{decorators → lib/server/decorators}/index.d.ts +9 -4
  102. package/dist/{decorators → lib/server/decorators}/index.js +9 -4
  103. package/dist/lib/server/decorators/metadata.d.ts +1 -0
  104. package/dist/lib/server/decorators/metadata.js +5 -0
  105. package/dist/lib/server/decorators/types.d.ts +125 -0
  106. package/dist/lib/server/decorators/types.js +6 -0
  107. package/dist/{exeptions → lib/server/exeptions}/HyperException.d.ts +2 -1
  108. package/dist/{exeptions → lib/server/exeptions}/HyperException.js +2 -1
  109. package/dist/{exeptions → lib/server/exeptions}/HyperFileException.js +1 -1
  110. package/dist/{exeptions → lib/server/exeptions}/NotRoleException.js +1 -1
  111. package/dist/{exeptions → lib/server/exeptions}/NotScopeException.js +1 -1
  112. package/dist/lib/tree/tree.d.ts +36 -0
  113. package/dist/lib/tree/tree.js +106 -0
  114. package/dist/type.d.ts +13 -2
  115. package/hyper-express-decorators.d.ts +1 -0
  116. package/package.json +81 -60
  117. package/scripts/clean.js +56 -0
  118. package/scripts/test-server.ts +85 -0
  119. package/tsconfig.json +18 -13
  120. package/vitest.config.mjs +30 -0
  121. package/.mocharc.js +0 -5
  122. package/dist/__internals/creators/request.creator.d.ts +0 -12
  123. package/dist/__internals/creators/request.creator.js +0 -53
  124. package/dist/__internals/creators/routes.creator.d.ts +0 -10
  125. package/dist/__internals/creators/routes.creator.js +0 -37
  126. package/dist/__internals/decorator-base.d.ts +0 -30
  127. package/dist/__internals/decorator-base.js +0 -86
  128. package/dist/__internals/store.d.ts +0 -10
  129. package/dist/__internals/store.js +0 -17
  130. package/dist/__internals/stores/middleware.store.d.ts +0 -7
  131. package/dist/__internals/stores/middleware.store.js +0 -19
  132. package/dist/__internals/stores/params.store.d.ts +0 -21
  133. package/dist/__internals/stores/params.store.js +0 -65
  134. package/dist/__internals/stores/routes.store.d.ts +0 -17
  135. package/dist/__internals/stores/routes.store.js +0 -43
  136. package/dist/__internals/stores/store.interface.d.ts +0 -8
  137. package/dist/__internals/transform/method.transform.d.ts +0 -2
  138. package/dist/__internals/transform/method.transform.js +0 -20
  139. package/dist/__internals/transform/pass.transfrom.d.ts +0 -1
  140. package/dist/__internals/transform/pass.transfrom.js +0 -2
  141. package/dist/__internals/utils/mixin.utils.d.ts +0 -11
  142. package/dist/__internals/utils/mixin.utils.js +0 -34
  143. package/dist/__internals/utils/router.d.ts +0 -1
  144. package/dist/__internals/utils/router.js +0 -2
  145. package/dist/common/openapi/collect-class-data.d.ts +0 -21
  146. package/dist/common/openapi/collect-class-data.js +0 -45
  147. package/dist/common/openapi/collect-function-data.d.ts +0 -32
  148. package/dist/common/openapi/collect-function-data.js +0 -70
  149. package/dist/common/openapi/index.d.ts +0 -2
  150. package/dist/decorators/File.d.ts +0 -65
  151. package/dist/decorators/Http.d.ts +0 -55
  152. package/dist/decorators/Http.js +0 -93
  153. package/dist/decorators/HyperApp.d.ts +0 -7
  154. package/dist/decorators/HyperApp.js +0 -262
  155. package/dist/decorators/HyperController.d.ts +0 -2
  156. package/dist/decorators/HyperController.js +0 -19
  157. package/dist/decorators/HyperModule.d.ts +0 -5
  158. package/dist/decorators/HyperModule.js +0 -14
  159. package/dist/decorators/Middleware.d.ts +0 -24
  160. package/dist/decorators/Middleware.js +0 -51
  161. package/dist/decorators/Pass.d.ts +0 -12
  162. package/dist/decorators/Pass.js +0 -29
  163. package/dist/decorators/Role.d.ts +0 -6
  164. package/dist/decorators/Role.js +0 -34
  165. package/dist/decorators/Routes.d.ts +0 -14
  166. package/dist/decorators/Routes.js +0 -21
  167. package/dist/decorators/Scope.d.ts +0 -6
  168. package/dist/decorators/Scope.js +0 -25
  169. package/dist/decorators/types.d.ts +0 -89
  170. /package/dist/{decorators → lib/openapi}/types.js +0 -0
  171. /package/dist/{exeptions → lib/server/exeptions}/DuplicateControllerPathException.d.ts +0 -0
  172. /package/dist/{exeptions → lib/server/exeptions}/DuplicateControllerPathException.js +0 -0
  173. /package/dist/{exeptions → lib/server/exeptions}/DuplicatedException.d.ts +0 -0
  174. /package/dist/{exeptions → lib/server/exeptions}/DuplicatedException.js +0 -0
  175. /package/dist/{exeptions → lib/server/exeptions}/DuplicatedHandlerException.d.ts +0 -0
  176. /package/dist/{exeptions → lib/server/exeptions}/DuplicatedHandlerException.js +0 -0
  177. /package/dist/{exeptions → lib/server/exeptions}/HyperFileException.d.ts +0 -0
  178. /package/dist/{exeptions → lib/server/exeptions}/MethodNotFountException.d.ts +0 -0
  179. /package/dist/{exeptions → lib/server/exeptions}/MethodNotFountException.js +0 -0
  180. /package/dist/{exeptions → lib/server/exeptions}/NotPropertyException.d.ts +0 -0
  181. /package/dist/{exeptions → lib/server/exeptions}/NotPropertyException.js +0 -0
  182. /package/dist/{exeptions → lib/server/exeptions}/NotRoleException.d.ts +0 -0
  183. /package/dist/{exeptions → lib/server/exeptions}/NotScopeException.d.ts +0 -0
  184. /package/dist/{exeptions → lib/server/exeptions}/WrongPlaceException.d.ts +0 -0
  185. /package/dist/{exeptions → lib/server/exeptions}/WrongPlaceException.js +0 -0
  186. /package/dist/{exeptions → lib/server/exeptions}/index.d.ts +0 -0
  187. /package/dist/{exeptions → lib/server/exeptions}/index.js +0 -0
  188. /package/dist/{exeptions → lib/server/exeptions}/types.d.ts +0 -0
  189. /package/dist/{exeptions → lib/server/exeptions}/types.js +0 -0
@@ -0,0 +1,131 @@
1
+ export interface OpenAPIDocument {
2
+ openapi: string;
3
+ info: Info;
4
+ paths: Paths;
5
+ components?: Components;
6
+ security?: SecurityRequirement[];
7
+ tags?: Tag[];
8
+ }
9
+ export interface Info {
10
+ title: string;
11
+ description?: string;
12
+ termsOfService?: string;
13
+ contact?: Contact;
14
+ license?: License;
15
+ version: string;
16
+ }
17
+ export interface Contact {
18
+ name?: string;
19
+ url?: string;
20
+ email?: string;
21
+ }
22
+ export interface License {
23
+ name: string;
24
+ url?: string;
25
+ }
26
+ export interface Paths {
27
+ [path: string]: PathItem;
28
+ }
29
+ export interface PathItem {
30
+ get?: Operation;
31
+ post?: Operation;
32
+ put?: Operation;
33
+ delete?: Operation;
34
+ patch?: Operation;
35
+ head?: Operation;
36
+ options?: Operation;
37
+ trace?: Operation;
38
+ }
39
+ export interface Operation {
40
+ summary?: string;
41
+ description?: string;
42
+ operationId?: string;
43
+ tags?: Tag[];
44
+ parameters?: OpenApiParameter[];
45
+ requestBody?: RequestBody;
46
+ responses: OpenApiResponses;
47
+ security?: SecurityRequirement[];
48
+ }
49
+ export interface OpenApiParameter {
50
+ name: string;
51
+ in: "query" | "header" | "path" | "cookie";
52
+ description?: string;
53
+ required?: boolean;
54
+ deprecated?: boolean;
55
+ allowEmptyValue?: boolean;
56
+ schema: Schema;
57
+ }
58
+ export interface RequestBody {
59
+ description?: string;
60
+ content: {
61
+ [mediaType: string]: MediaType;
62
+ };
63
+ }
64
+ export interface MediaType {
65
+ schema: Schema;
66
+ }
67
+ export interface OpenApiResponses {
68
+ [statusCode: string]: OpenApiResponse;
69
+ }
70
+ export interface OpenApiResponse {
71
+ description: string;
72
+ content?: {
73
+ [mediaType: string]: MediaType;
74
+ };
75
+ headers?: {
76
+ [name: string]: Header;
77
+ };
78
+ }
79
+ export interface Header {
80
+ description?: string;
81
+ required?: boolean;
82
+ schema: Schema;
83
+ }
84
+ export interface Schema {
85
+ type: string;
86
+ format?: string;
87
+ items?: Schema;
88
+ properties?: {
89
+ [key: string]: Schema;
90
+ };
91
+ additionalProperties?: boolean;
92
+ example?: any;
93
+ }
94
+ export interface SecurityRequirement {
95
+ [securityScheme: string]: string[];
96
+ }
97
+ export interface Tag {
98
+ name: string;
99
+ description?: string;
100
+ }
101
+ export interface Components {
102
+ schemas?: {
103
+ [schemaName: string]: Schema;
104
+ };
105
+ responses?: {
106
+ [responseName: string]: OpenApiResponse;
107
+ };
108
+ parameters?: {
109
+ [parameterName: string]: OpenApiParameter;
110
+ };
111
+ securitySchemes?: {
112
+ [schemeName: string]: SecurityScheme;
113
+ };
114
+ }
115
+ export interface SecurityScheme {
116
+ type: "apiKey" | "http" | "oauth2" | "openIdConnect";
117
+ in?: "header" | "query" | "cookie";
118
+ name?: string;
119
+ scheme?: string;
120
+ bearerFormat?: string;
121
+ openIdConnectUrl?: string;
122
+ oauth2?: OAuth2Scheme;
123
+ }
124
+ export interface OAuth2Scheme {
125
+ authorizationUrl: string;
126
+ tokenUrl: string;
127
+ refreshUrl?: string;
128
+ scopes: {
129
+ [scope: string]: string;
130
+ };
131
+ }
@@ -0,0 +1,37 @@
1
+ import { Request } from "hyper-express/types";
2
+ /**
3
+ * File upload restrictions
4
+ */
5
+ export interface FileUploadRestrictions {
6
+ allowedMimeTypes: string[];
7
+ maxFileSize: number;
8
+ }
9
+ /**
10
+ * File restrictions resolver
11
+ */
12
+ export type FileRestrictions = FileUploadRestrictions | ((request: Request) => FileUploadRestrictions | Promise<FileUploadRestrictions>);
13
+ /**
14
+ * File decorator options
15
+ */
16
+ export interface FileOptions {
17
+ fieldName: string | string[];
18
+ restrictions?: FileRestrictions;
19
+ required?: boolean;
20
+ }
21
+ export interface UploadedFile {
22
+ field: string;
23
+ name: string;
24
+ filename: string;
25
+ mimeType: string;
26
+ size: number;
27
+ extension: string;
28
+ buffer: Buffer;
29
+ }
30
+ /**
31
+ * Decorator to extract file from the request
32
+ */
33
+ export declare const File: {
34
+ (options: FileOptions | string): (target: object, propertyKey: string | symbol, index: number) => void;
35
+ options(options: FileOptions, required?: boolean): (fieldName: string | string[]) => (target: object, propertyKey: string | symbol, index: number) => void;
36
+ restrictions(restrictions: FileRestrictions): (fieldName: string | string[], required?: boolean) => (target: object, propertyKey: string | symbol, index: number) => void;
37
+ };
@@ -8,46 +8,37 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __asyncValues = (this && this.__asyncValues) || function (o) {
12
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
13
+ var m = o[Symbol.asyncIterator], i;
14
+ return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
15
+ function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
16
+ function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
17
+ };
11
18
  var __importDefault = (this && this.__importDefault) || function (mod) {
12
19
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
20
  };
14
21
  Object.defineProperty(exports, "__esModule", { value: true });
15
22
  exports.File = void 0;
16
23
  const Http_1 = require("./Http");
17
- const consumers_1 = require("stream/consumers");
18
24
  const HyperFileException_1 = __importDefault(require("../exeptions/HyperFileException"));
19
25
  /**
20
26
  * Decorator to extract file from the request
21
- *
22
- * @param param0
23
27
  */
24
28
  const File = (options) => {
25
29
  const _options = typeof options === "string" ? { fieldName: options } : options;
26
30
  return (0, Http_1.createCustomRequestDecorator)("File", (request) => __awaiter(void 0, void 0, void 0, function* () {
27
- var _a, _b;
31
+ var _a;
28
32
  const { allowedMimeTypes, maxFileSize } = yield resolveRestrictions(request, _options.restrictions);
29
33
  const passTypes = allowedMimeTypes.includes("*") || allowedMimeTypes.length === 0;
30
34
  const passSize = maxFileSize === Infinity;
31
35
  const contentType = (_a = request.headers) === null || _a === void 0 ? void 0 : _a["content-type"];
32
- const fileSize = Number((_b = request.headers) === null || _b === void 0 ? void 0 : _b["content-length"]);
33
36
  const isMultipart = contentType === null || contentType === void 0 ? void 0 : contentType.includes("multipart/form-data");
34
37
  if (!isMultipart) {
35
38
  throw new HyperFileException_1.default("Invalid request, expected multipart form data", {
36
39
  fieldName: _options.fieldName,
37
40
  });
38
41
  }
39
- if (isNaN(fileSize) || fileSize <= 0) {
40
- throw new HyperFileException_1.default(`File ${_options.fieldName} is missing or empty`, {
41
- fieldName: _options.fieldName,
42
- fileSize,
43
- });
44
- }
45
- if (!passSize && fileSize > maxFileSize) {
46
- throw new HyperFileException_1.default(`File ${_options.fieldName} is too large. Max size is ${maxFileSize} bytes`, {
47
- fieldName: _options.fieldName,
48
- maxFileSize,
49
- });
50
- }
51
42
  const files = yield extractFiles(request, {
52
43
  maxSize: passSize ? undefined : maxFileSize,
53
44
  mimeTypes: passTypes ? undefined : allowedMimeTypes,
@@ -64,35 +55,16 @@ const File = (options) => {
64
55
  }));
65
56
  };
66
57
  exports.File = File;
67
- /**
68
- *
69
- * Helper function to create a file decorator with options
70
- *
71
- * @param options
72
- * @returns
73
- */
74
58
  exports.File.options = (options, required = false) => {
75
59
  return (fieldName) => {
76
60
  return (0, exports.File)(Object.assign(Object.assign({}, options), { required, fieldName }));
77
61
  };
78
62
  };
79
- /**
80
- * Helper function to create a file decorator with restrictions
81
- *
82
- * @param restrictions
83
- * @returns
84
- */
85
63
  exports.File.restrictions = (restrictions) => {
86
64
  return (fieldName, required = false) => {
87
65
  return (0, exports.File)({ fieldName, restrictions, required });
88
66
  };
89
67
  };
90
- /////////////////////////////
91
- // Types
92
- /////////////////////////////
93
- /////////////////////////////
94
- /// Utility
95
- /////////////////////////////
96
68
  const resolveRestrictions = (request, restrictions) => __awaiter(void 0, void 0, void 0, function* () {
97
69
  if (typeof restrictions === "function") {
98
70
  return yield restrictions(request);
@@ -103,63 +75,78 @@ const resolveRestrictions = (request, restrictions) => __awaiter(void 0, void 0,
103
75
  });
104
76
  });
105
77
  /**
106
- * Extract files from a request with validation, transformation, and required files check.
107
- *
108
- * @param request
109
- * @param options Validation and transformation options
110
- * @returns Transformed or raw file details
78
+ * Extract files from a request with validation and secure streaming.
111
79
  */
112
80
  const extractFiles = (request, options) => __awaiter(void 0, void 0, void 0, function* () {
113
81
  var _a;
114
- const contentType = (_a = request.headers) === null || _a === void 0 ? void 0 : _a["content-type"];
115
- if (!(contentType === null || contentType === void 0 ? void 0 : contentType.includes("multipart/form-data"))) {
116
- throw new Error("Invalid request, expected multipart form data");
117
- }
118
82
  const filesMap = {};
83
+ // Track if we are already over total limit (Content-Length check as first line of defense)
84
+ const totalLength = Number((_a = request.headers) === null || _a === void 0 ? void 0 : _a["content-length"]);
85
+ if ((options === null || options === void 0 ? void 0 : options.maxSize) && !isNaN(totalLength) && totalLength > options.maxSize + 1024 * 10) { // Buffer for boundaries
86
+ // Content-Length is significantly larger than allowed file size
87
+ // We don't throw yet because multipart might have multiple files or large fields
88
+ }
119
89
  yield request.multipart((field) => __awaiter(void 0, void 0, void 0, function* () {
120
- var _a, _b, _c, _d;
90
+ var _a, e_1, _b, _c;
91
+ var _d, _e;
121
92
  if (field.file && field.file.stream) {
122
- const bufferFile = yield (0, consumers_1.buffer)(field.file.stream);
123
- const type = yield (yield import("file-type")).fileTypeFromBuffer(bufferFile);
124
- if (!type) {
125
- throw new HyperFileException_1.default(`Invalid file type`, {
126
- field: field.name,
127
- });
93
+ const chunks = [];
94
+ let totalRead = 0;
95
+ try {
96
+ // Safe stream reading with early exit
97
+ for (var _f = true, _g = __asyncValues(field.file.stream), _h; _h = yield _g.next(), _a = _h.done, !_a; _f = true) {
98
+ _c = _h.value;
99
+ _f = false;
100
+ const chunk = _c;
101
+ totalRead += chunk.length;
102
+ if ((options === null || options === void 0 ? void 0 : options.maxSize) && totalRead > options.maxSize) {
103
+ throw new HyperFileException_1.default(`File '${field.name}' exceeds the maximum limit of ${options.maxSize} bytes`, { field: field.name, maxSize: options.maxSize });
104
+ }
105
+ chunks.push(chunk);
106
+ }
128
107
  }
129
- const mimeType = type.mime;
130
- const extention = type.ext;
131
- // Validate MIME type early
132
- if ((options === null || options === void 0 ? void 0 : options.mimeTypes) && !options.mimeTypes.includes(mimeType)) {
133
- throw new HyperFileException_1.default(`Invalid file type, only ${options.mimeTypes.join(", ")} is allowed`, {
134
- field: field.name,
135
- allowedMimeTypes: options.mimeTypes,
136
- mimeType,
137
- });
108
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
109
+ finally {
110
+ try {
111
+ if (!_f && !_a && (_b = _g.return)) yield _b.call(_g);
112
+ }
113
+ finally { if (e_1) throw e_1.error; }
138
114
  }
139
- if (!type) {
140
- throw new HyperFileException_1.default(`Invalid file type`, {
141
- field: field.name,
142
- });
115
+ const bufferFile = Buffer.concat(chunks);
116
+ const { fileTypeFromBuffer } = yield import("file-type");
117
+ const type = yield fileTypeFromBuffer(bufferFile);
118
+ const mimeType = (type === null || type === void 0 ? void 0 : type.mime) || "unknown/unrecognized";
119
+ const extension = (type === null || type === void 0 ? void 0 : type.ext) || "bin";
120
+ // Validate MIME type early if unrecognized
121
+ if (!type && (options === null || options === void 0 ? void 0 : options.mimeTypes) && options.mimeTypes.length > 0) {
122
+ throw new HyperFileException_1.default(`Invalid file type for field '${field.name}'. Could not recognize file signature. Expected one of: ${options.mimeTypes.join(", ")}`, { field: field.name, allowedMimeTypes: options.mimeTypes });
143
123
  }
144
- if ((options === null || options === void 0 ? void 0 : options.maxSize) && bufferFile.byteLength > options.maxSize) {
145
- throw new HyperFileException_1.default(`File '${field.name}' size exceeds the maximum limit of ${options.maxSize} bytes`, {
124
+ // Validate MIME type if recognized
125
+ if ((options === null || options === void 0 ? void 0 : options.mimeTypes) && !options.mimeTypes.includes(mimeType)) {
126
+ throw new HyperFileException_1.default(`Invalid file type for field '${field.name}'. Expected: ${options.mimeTypes.join(", ")}, Received: ${mimeType}`, {
146
127
  field: field.name,
147
- maxSize: options.maxSize,
128
+ allowedMimeTypes: options.mimeTypes,
129
+ receivedMimeType: mimeType,
148
130
  });
149
131
  }
150
- if ((options === null || options === void 0 ? void 0 : options.requireName) && !((_a = field.file) === null || _a === void 0 ? void 0 : _a.name)) {
151
- throw new HyperFileException_1.default(`File name is required`, {
132
+ if ((options === null || options === void 0 ? void 0 : options.requireName) && !((_d = field.file) === null || _d === void 0 ? void 0 : _d.name)) {
133
+ throw new HyperFileException_1.default(`File name is required for field '${field.name}'`, {
152
134
  field: field.name,
153
135
  });
154
136
  }
155
- // Derive file details
156
- const name = (_d = (_c = (_b = field.file) === null || _b === void 0 ? void 0 : _b.name) === null || _c === void 0 ? void 0 : _c.split(".").shift()) !== null && _d !== void 0 ? _d : field.name;
157
- const filename = `${name === null || name === void 0 ? void 0 : name.replace(extention, "")}.${extention}`;
137
+ // Secure filename resolution
138
+ const rawName = ((_e = field.file) === null || _e === void 0 ? void 0 : _e.name) || field.name;
139
+ // Sanitize: remove null bytes, path traversal sequences, and extract base name
140
+ const sanitizedBase = rawName.replace(/\0/g, "").split(/[\\/]/).pop() || "file";
141
+ const nameOnly = sanitizedBase.includes(".")
142
+ ? sanitizedBase.substring(0, sanitizedBase.lastIndexOf("."))
143
+ : sanitizedBase;
144
+ const filename = `${nameOnly}.${extension}`;
158
145
  filesMap[field.name] = {
159
146
  field: field.name,
160
- name: name,
147
+ name: nameOnly,
161
148
  filename: filename,
162
- ext: extention,
149
+ extension: extension,
163
150
  size: bufferFile.byteLength,
164
151
  mimeType: mimeType,
165
152
  buffer: bufferFile,
@@ -0,0 +1,12 @@
1
+ import { ParameterResolver } from "./types";
2
+ /**
3
+ * 🛠️ Helper to create parameter decorators
4
+ */
5
+ export declare function createParamDecorator(source: "body" | "query" | "params" | "headers" | "req" | "res", decorator: string, keyOrSchema?: string | object | Function, schemaOrTransform?: object | Function, isWholeSource?: boolean, customResolver?: ParameterResolver): (target: object, propertyKey: string | symbol, index: number) => void;
6
+ export declare function Query(keyOrSchema?: string | object | Function, schemaOrTransform?: object | Function): (target: object, propertyKey: string | symbol, index: number) => void;
7
+ export declare function Body(keyOrSchema?: string | object | Function, schemaOrTransform?: object | Function): (target: object, propertyKey: string | symbol, index: number) => void;
8
+ export declare function Param(keyOrSchema: string | object | Function, schemaOrTransform?: object | Function): (target: object, propertyKey: string | symbol, index: number) => void;
9
+ export declare function Headers(keyOrSchema?: string | object | Function, schemaOrTransform?: object | Function): (target: object, propertyKey: string | symbol, index: number) => void;
10
+ export declare const Req: () => (target: object, propertyKey: string | symbol, index: number) => void;
11
+ export declare const Res: () => (target: object, propertyKey: string | symbol, index: number) => void;
12
+ export declare const createCustomRequestDecorator: (decoratorName: string, resolver: ParameterResolver) => (target: object, propertyKey: string | symbol, index: number) => void;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createCustomRequestDecorator = exports.Res = exports.Req = void 0;
4
+ exports.createParamDecorator = createParamDecorator;
5
+ exports.Query = Query;
6
+ exports.Body = Body;
7
+ exports.Param = Param;
8
+ exports.Headers = Headers;
9
+ const metadata_1 = require("./metadata");
10
+ /**
11
+ * 🛠️ Helper to create parameter decorators
12
+ */
13
+ function createParamDecorator(source, decorator, keyOrSchema, schemaOrTransform, isWholeSource = false, customResolver) {
14
+ return (target, propertyKey, index) => {
15
+ var _a;
16
+ const root = metadata_1.HyperMeta.get(target, propertyKey);
17
+ const params = ((_a = root.params) === null || _a === void 0 ? void 0 : _a.params) || [];
18
+ const picker = typeof keyOrSchema === 'string' ? keyOrSchema : undefined;
19
+ const schema = (typeof keyOrSchema === 'object' || typeof keyOrSchema === 'function')
20
+ ? keyOrSchema
21
+ : schemaOrTransform;
22
+ params.push({
23
+ index,
24
+ type: (Reflect.getMetadata("design:paramtypes", target, propertyKey) || [])[index],
25
+ source,
26
+ picker,
27
+ schema,
28
+ isWholeSource: isWholeSource || (picker === undefined && keyOrSchema !== undefined),
29
+ decorator,
30
+ resolver: customResolver,
31
+ });
32
+ metadata_1.HyperMeta.set(target, propertyKey, {
33
+ params: { params }
34
+ });
35
+ };
36
+ }
37
+ function Query(keyOrSchema, schemaOrTransform) {
38
+ return createParamDecorator("query", "Query", keyOrSchema, schemaOrTransform);
39
+ }
40
+ function Body(keyOrSchema, schemaOrTransform) {
41
+ return createParamDecorator("body", "Body", keyOrSchema, schemaOrTransform);
42
+ }
43
+ function Param(keyOrSchema, schemaOrTransform) {
44
+ return createParamDecorator("params", "Param", keyOrSchema, schemaOrTransform);
45
+ }
46
+ function Headers(keyOrSchema, schemaOrTransform) {
47
+ return createParamDecorator("headers", "Headers", keyOrSchema, schemaOrTransform);
48
+ }
49
+ const Req = () => createParamDecorator("req", "Req", undefined, undefined, true, (req) => req);
50
+ exports.Req = Req;
51
+ const Res = () => createParamDecorator("res", "Res", undefined, undefined, true, (_req, res) => res);
52
+ exports.Res = Res;
53
+ const createCustomRequestDecorator = (decoratorName, resolver) => {
54
+ return createParamDecorator("req", decoratorName, undefined, undefined, true, resolver);
55
+ };
56
+ exports.createCustomRequestDecorator = createCustomRequestDecorator;
@@ -0,0 +1,7 @@
1
+ import { HyperAppMetadata, Constructor } from "./types";
2
+ /**
3
+ * 🚀 HyperApp Decorator
4
+ * Purely injects metadata and a prepare method into the target class.
5
+ * No class wrapping or modification of the original constructor.
6
+ */
7
+ export declare function HyperApp(options: HyperAppMetadata): (Target: Constructor) => void;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HyperApp = HyperApp;
4
+ const metadata_1 = require("./metadata");
5
+ /**
6
+ * 🚀 HyperApp Decorator
7
+ * Purely injects metadata and a prepare method into the target class.
8
+ * No class wrapping or modification of the original constructor.
9
+ */
10
+ function HyperApp(options) {
11
+ return (Target) => {
12
+ metadata_1.HyperMeta.set(Target, undefined, Object.assign({ type: "app" }, options));
13
+ };
14
+ }
@@ -0,0 +1,6 @@
1
+ import { HyperControllerMetadata } from "./types";
2
+ /**
3
+ * 🚀 HyperController Decorator
4
+ * Purely injects metadata into the target class.
5
+ */
6
+ export declare function HyperController(options?: HyperControllerMetadata | string): (Target: any) => void;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HyperController = HyperController;
4
+ const metadata_1 = require("./metadata");
5
+ /**
6
+ * 🚀 HyperController Decorator
7
+ * Purely injects metadata into the target class.
8
+ */
9
+ function HyperController(options) {
10
+ return (Target) => {
11
+ const isString = typeof options === "string";
12
+ const data = isString ? { path: options } : (options !== null && options !== void 0 ? options : {});
13
+ metadata_1.HyperMeta.set(Target, undefined, Object.assign({ type: "controller" }, data));
14
+ };
15
+ }
@@ -0,0 +1,6 @@
1
+ import { HyperModuleMetadata, Constructor } from "./types";
2
+ /**
3
+ * 🚀 HyperModule Decorator
4
+ * Purely injects metadata into the target class.
5
+ */
6
+ export declare function HyperModule(options: HyperModuleMetadata): (Target: Constructor) => void;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HyperModule = HyperModule;
4
+ const metadata_1 = require("./metadata");
5
+ /**
6
+ * 🚀 HyperModule Decorator
7
+ * Purely injects metadata into the target class.
8
+ */
9
+ function HyperModule(options) {
10
+ return (Target) => {
11
+ metadata_1.HyperMeta.set(Target, undefined, Object.assign({ type: "module" }, options));
12
+ };
13
+ }
@@ -0,0 +1,12 @@
1
+ import "reflect-metadata";
2
+ import { Constructor } from "./types";
3
+ interface ServiceDecoratorOptions {
4
+ singleton?: boolean;
5
+ token?: string | symbol | Constructor | (abstract new (...args: any[]) => any);
6
+ }
7
+ /**
8
+ * 🚀 HyperService Decorator
9
+ * Purely injects metadata and registers the class in the DI container.
10
+ */
11
+ export declare function HyperService({ token, singleton, }?: ServiceDecoratorOptions): (Target: any) => any;
12
+ export {};
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HyperService = HyperService;
4
+ require("reflect-metadata");
5
+ const tsyringe_1 = require("tsyringe");
6
+ const metadata_1 = require("./metadata");
7
+ /**
8
+ * 🚀 HyperService Decorator
9
+ * Purely injects metadata and registers the class in the DI container.
10
+ */
11
+ function HyperService({ token, singleton = true, } = {}) {
12
+ return (Target) => {
13
+ const useToken = token !== null && token !== void 0 ? token : Target;
14
+ // 1. DI Registration
15
+ (0, tsyringe_1.injectable)()(Target);
16
+ if (!tsyringe_1.container.isRegistered(useToken)) {
17
+ if (singleton) {
18
+ tsyringe_1.container.registerSingleton(useToken, Target);
19
+ }
20
+ else {
21
+ tsyringe_1.container.register(useToken, { useClass: Target });
22
+ }
23
+ }
24
+ // 2. Hierarchical Metadata Injection
25
+ metadata_1.HyperMeta.set(Target, undefined, {
26
+ type: 'service',
27
+ });
28
+ return Target;
29
+ };
30
+ }
@@ -0,0 +1,8 @@
1
+ import "reflect-metadata";
2
+ /**
3
+ * 🚀 OnMessage Decorator
4
+ * Purely injects message subscription metadata into the method.
5
+ *
6
+ * @param topic The topic or pattern to listen to (e.g. "user.created", "user.*")
7
+ */
8
+ export declare const OnMessage: (topic: string) => (target: any, propertyKey: any) => void;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OnMessage = void 0;
4
+ require("reflect-metadata");
5
+ const metadata_1 = require("./metadata");
6
+ /**
7
+ * 🚀 OnMessage Decorator
8
+ * Purely injects message subscription metadata into the method.
9
+ *
10
+ * @param topic The topic or pattern to listen to (e.g. "user.created", "user.*")
11
+ */
12
+ const OnMessage = (topic) => {
13
+ return (target, propertyKey) => {
14
+ metadata_1.HyperMeta.set(target, propertyKey, {
15
+ onMessage: { topic }
16
+ });
17
+ };
18
+ };
19
+ exports.OnMessage = OnMessage;
@@ -0,0 +1,18 @@
1
+ import "reflect-metadata";
2
+ import { MiddlewareHandler } from "hyper-express";
3
+ import { MiddlewareType } from "./types";
4
+ /**
5
+ * 🚀 Middleware Decorator
6
+ * Purely injects middleware metadata into the target class or method.
7
+ */
8
+ export declare const Middleware: {
9
+ (...middleware: MiddlewareType[]): any;
10
+ /**
11
+ * Exclude middleware from matching paths.
12
+ */
13
+ exclude(expressions: RegExp | RegExp[], middleware: MiddlewareHandler): any;
14
+ /**
15
+ * Only run middleware on matching paths.
16
+ */
17
+ only(expressions: RegExp | RegExp[], middleware: MiddlewareHandler): any;
18
+ };