@avleon/core 0.0.45 → 0.0.48

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 (131) hide show
  1. package/README.md +355 -369
  2. package/dist/chunk-9hOWP6kD.cjs +64 -0
  3. package/dist/chunk-DORXReHP.js +37 -0
  4. package/dist/index-BxIMWhgy.d.ts +1284 -0
  5. package/dist/index-DPn7qtzq.d.cts +1283 -0
  6. package/dist/index.cjs +3194 -0
  7. package/dist/index.cjs.map +1 -0
  8. package/dist/index.js +3022 -83
  9. package/dist/index.js.map +1 -0
  10. package/dist/lib-Bk8hUm06.cjs +7847 -0
  11. package/dist/lib-Bk8hUm06.cjs.map +1 -0
  12. package/dist/lib-CvDxBMkR.js +7843 -0
  13. package/dist/lib-CvDxBMkR.js.map +1 -0
  14. package/package.json +67 -116
  15. package/dist/application.d.ts +0 -47
  16. package/dist/application.js +0 -50
  17. package/dist/authentication.d.ts +0 -13
  18. package/dist/authentication.js +0 -16
  19. package/dist/cache.d.ts +0 -12
  20. package/dist/cache.js +0 -78
  21. package/dist/cache.test.d.ts +0 -1
  22. package/dist/cache.test.js +0 -36
  23. package/dist/collection.d.ts +0 -43
  24. package/dist/collection.js +0 -231
  25. package/dist/collection.test.d.ts +0 -1
  26. package/dist/collection.test.js +0 -59
  27. package/dist/config.d.ts +0 -18
  28. package/dist/config.js +0 -58
  29. package/dist/config.test.d.ts +0 -1
  30. package/dist/config.test.js +0 -40
  31. package/dist/constants.d.ts +0 -1
  32. package/dist/constants.js +0 -4
  33. package/dist/container.d.ts +0 -30
  34. package/dist/container.js +0 -55
  35. package/dist/controller.d.ts +0 -50
  36. package/dist/controller.js +0 -71
  37. package/dist/controller.test.d.ts +0 -1
  38. package/dist/controller.test.js +0 -111
  39. package/dist/decorators.d.ts +0 -15
  40. package/dist/decorators.js +0 -41
  41. package/dist/environment-variables.d.ts +0 -49
  42. package/dist/environment-variables.js +0 -130
  43. package/dist/environment-variables.test.d.ts +0 -1
  44. package/dist/environment-variables.test.js +0 -70
  45. package/dist/event-dispatcher.d.ts +0 -23
  46. package/dist/event-dispatcher.js +0 -100
  47. package/dist/event-subscriber.d.ts +0 -14
  48. package/dist/event-subscriber.js +0 -87
  49. package/dist/exceptions/http-exceptions.d.ts +0 -50
  50. package/dist/exceptions/http-exceptions.js +0 -85
  51. package/dist/exceptions/index.d.ts +0 -1
  52. package/dist/exceptions/index.js +0 -17
  53. package/dist/exceptions/system-exception.d.ts +0 -22
  54. package/dist/exceptions/system-exception.js +0 -26
  55. package/dist/file-storage.d.ts +0 -69
  56. package/dist/file-storage.js +0 -323
  57. package/dist/file-storage.test.d.ts +0 -1
  58. package/dist/file-storage.test.js +0 -104
  59. package/dist/helpers.d.ts +0 -44
  60. package/dist/helpers.js +0 -419
  61. package/dist/helpers.test.d.ts +0 -1
  62. package/dist/helpers.test.js +0 -95
  63. package/dist/icore.d.ts +0 -226
  64. package/dist/icore.js +0 -968
  65. package/dist/icore.test.d.ts +0 -1
  66. package/dist/icore.test.js +0 -14
  67. package/dist/index.d.ts +0 -55
  68. package/dist/interfaces/avleon-application.d.ts +0 -27
  69. package/dist/interfaces/avleon-application.js +0 -1
  70. package/dist/kenx-provider.d.ts +0 -7
  71. package/dist/kenx-provider.js +0 -44
  72. package/dist/kenx-provider.test.d.ts +0 -1
  73. package/dist/kenx-provider.test.js +0 -36
  74. package/dist/logger.d.ts +0 -12
  75. package/dist/logger.js +0 -87
  76. package/dist/logger.test.d.ts +0 -1
  77. package/dist/logger.test.js +0 -42
  78. package/dist/map-types.d.ts +0 -17
  79. package/dist/map-types.js +0 -89
  80. package/dist/middleware.d.ts +0 -27
  81. package/dist/middleware.js +0 -64
  82. package/dist/middleware.test.d.ts +0 -1
  83. package/dist/middleware.test.js +0 -121
  84. package/dist/multipart.d.ts +0 -17
  85. package/dist/multipart.js +0 -70
  86. package/dist/multipart.test.d.ts +0 -1
  87. package/dist/multipart.test.js +0 -87
  88. package/dist/openapi.d.ts +0 -343
  89. package/dist/openapi.js +0 -27
  90. package/dist/openapi.test.d.ts +0 -1
  91. package/dist/openapi.test.js +0 -111
  92. package/dist/params.d.ts +0 -17
  93. package/dist/params.js +0 -64
  94. package/dist/params.test.d.ts +0 -1
  95. package/dist/params.test.js +0 -83
  96. package/dist/queue.d.ts +0 -29
  97. package/dist/queue.js +0 -84
  98. package/dist/response.d.ts +0 -16
  99. package/dist/response.js +0 -56
  100. package/dist/results.d.ts +0 -20
  101. package/dist/results.js +0 -32
  102. package/dist/route-methods.d.ts +0 -25
  103. package/dist/route-methods.js +0 -49
  104. package/dist/route-methods.test.d.ts +0 -1
  105. package/dist/route-methods.test.js +0 -129
  106. package/dist/swagger-schema.d.ts +0 -43
  107. package/dist/swagger-schema.js +0 -452
  108. package/dist/swagger-schema.test.d.ts +0 -1
  109. package/dist/swagger-schema.test.js +0 -105
  110. package/dist/testing.d.ts +0 -55
  111. package/dist/testing.js +0 -196
  112. package/dist/types/app-builder.interface.d.ts +0 -15
  113. package/dist/types/app-builder.interface.js +0 -8
  114. package/dist/types/application.interface.d.ts +0 -8
  115. package/dist/types/application.interface.js +0 -2
  116. package/dist/utils/hash.d.ts +0 -4
  117. package/dist/utils/hash.js +0 -15
  118. package/dist/utils/index.d.ts +0 -2
  119. package/dist/utils/index.js +0 -18
  120. package/dist/utils/optional-require.d.ts +0 -8
  121. package/dist/utils/optional-require.js +0 -70
  122. package/dist/validation.d.ts +0 -39
  123. package/dist/validation.js +0 -111
  124. package/dist/validation.test.d.ts +0 -1
  125. package/dist/validation.test.js +0 -61
  126. package/dist/validator-extend.d.ts +0 -7
  127. package/dist/validator-extend.js +0 -28
  128. package/dist/websocket.d.ts +0 -7
  129. package/dist/websocket.js +0 -20
  130. package/dist/websocket.test.d.ts +0 -1
  131. package/dist/websocket.test.js +0 -27
package/dist/index.cjs ADDED
@@ -0,0 +1,3194 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_chunk = require("./chunk-9hOWP6kD.cjs");
3
+ let class_validator = require("class-validator");
4
+ let typedi = require("typedi");
5
+ typedi = require_chunk.__toESM(typedi);
6
+ require("reflect-metadata");
7
+ let node_fs = require("node:fs");
8
+ node_fs = require_chunk.__toESM(node_fs);
9
+ let node_crypto = require("node:crypto");
10
+ node_crypto = require_chunk.__toESM(node_crypto);
11
+ let class_transformer = require("class-transformer");
12
+ let fastify = require("fastify");
13
+ fastify = require_chunk.__toESM(fastify);
14
+ let node_path = require("node:path");
15
+ node_path = require_chunk.__toESM(node_path);
16
+ let mime = require("mime");
17
+ mime = require_chunk.__toESM(mime);
18
+ let node_stream = require("node:stream");
19
+ node_stream = require_chunk.__toESM(node_stream);
20
+ let node_async_hooks = require("node:async_hooks");
21
+ let bull = require("bull");
22
+ bull = require_chunk.__toESM(bull);
23
+ let node_stream_promises = require("node:stream/promises");
24
+ let dotenv = require("dotenv");
25
+ dotenv = require_chunk.__toESM(dotenv);
26
+ let pino = require("pino");
27
+ pino = require_chunk.__toESM(pino);
28
+ //#region src/container.ts
29
+ function registerController(controller) {
30
+ controllerRegistry.add(controller);
31
+ }
32
+ function registerService(service) {
33
+ Container.set(service, service);
34
+ serviceRegistry.add(service);
35
+ }
36
+ function getRegisteredServices() {
37
+ return Array.from(serviceRegistry);
38
+ }
39
+ function getRegisteredControllers() {
40
+ return Array.from(controllerRegistry);
41
+ }
42
+ function isApiController(target) {
43
+ return Reflect.getMetadata(API_CONTROLLER_METADATA_KEY, target) === true;
44
+ }
45
+ function registerDataSource(dataSource) {
46
+ Container.set("idatasource", dataSource);
47
+ }
48
+ function registerKnex(dataSource) {
49
+ Container.set("KnexConnection", dataSource);
50
+ }
51
+ var FEATURE_KEY, ROUTE_META_KEY, CONTROLLER_META_KEY, PARAM_META_KEY, QUERY_META_KEY, REQUEST_BODY_META_KEY, REQUEST_BODY_FILE_KEY, REQUEST_BODY_FILES_KEY, REQUEST_USER_META_KEY, REQUEST_HEADER_META_KEY, DATASOURCE_META_KEY, AUTHORIZATION_META_KEY, controllerRegistry, serviceRegistry, Container, API_CONTROLLER_METADATA_KEY;
52
+ var init_container = require_chunk.__esmMin((() => {
53
+ FEATURE_KEY = Symbol.for("features");
54
+ ROUTE_META_KEY = Symbol("iroute:options");
55
+ CONTROLLER_META_KEY = Symbol("icontroller:options");
56
+ PARAM_META_KEY = Symbol("iparam:options");
57
+ QUERY_META_KEY = Symbol("iparam:options");
58
+ REQUEST_BODY_META_KEY = Symbol("iparam:options");
59
+ REQUEST_BODY_FILE_KEY = Symbol("iparam:options");
60
+ REQUEST_BODY_FILES_KEY = Symbol("iparam:options");
61
+ REQUEST_USER_META_KEY = Symbol("iparam:options");
62
+ REQUEST_HEADER_META_KEY = Symbol("iheader:options");
63
+ DATASOURCE_META_KEY = Symbol("idatasource:options");
64
+ AUTHORIZATION_META_KEY = Symbol("idatasource:authorization");
65
+ controllerRegistry = /* @__PURE__ */ new Set();
66
+ serviceRegistry = /* @__PURE__ */ new Set();
67
+ Container = typedi.default;
68
+ API_CONTROLLER_METADATA_KEY = Symbol("apiController");
69
+ Container.set("appName", "Iqra");
70
+ }));
71
+ //#endregion
72
+ //#region src/swagger-schema.ts
73
+ /**
74
+ * @copyright 2024
75
+ * @author Tareq Hossain
76
+ * @email xtrinsic96@gmail.com
77
+ * @url https://github.com/xtareq
78
+ */
79
+ init_container();
80
+ function OpenApiProperty$1(options) {
81
+ return function(target, propertyKey) {
82
+ let meta = options ? { ...options } : {};
83
+ if (meta.format === "binary") if (meta.isArray) meta = {
84
+ ...meta,
85
+ type: "array",
86
+ items: meta.items ?? {
87
+ type: "string",
88
+ format: "binary"
89
+ },
90
+ description: meta.description || "Array of files"
91
+ };
92
+ else meta = {
93
+ ...meta,
94
+ type: "string",
95
+ format: "binary",
96
+ description: meta.description || "File upload"
97
+ };
98
+ Reflect.defineMetadata("property:openapi", meta, target, propertyKey);
99
+ };
100
+ }
101
+ function extractOpenApiFields(meta) {
102
+ const result = {};
103
+ const jsonSchemaFields = [
104
+ "description",
105
+ "deprecated",
106
+ "example",
107
+ "enum",
108
+ "format",
109
+ "default",
110
+ "minimum",
111
+ "maximum",
112
+ "minLength",
113
+ "maxLength",
114
+ "pattern",
115
+ "oneOf",
116
+ "allOf",
117
+ "anyOf",
118
+ "title",
119
+ "readOnly",
120
+ "writeOnly",
121
+ "nullable"
122
+ ];
123
+ const validFormats = [
124
+ "date-time",
125
+ "date",
126
+ "time",
127
+ "duration",
128
+ "email",
129
+ "idn-email",
130
+ "hostname",
131
+ "idn-hostname",
132
+ "ipv4",
133
+ "ipv6",
134
+ "uri",
135
+ "uri-reference",
136
+ "iri",
137
+ "iri-reference",
138
+ "uuid",
139
+ "uri-template",
140
+ "json-pointer",
141
+ "relative-json-pointer",
142
+ "regex",
143
+ "int32",
144
+ "int64",
145
+ "float",
146
+ "double",
147
+ "byte",
148
+ "binary",
149
+ "password"
150
+ ];
151
+ jsonSchemaFields.forEach((field) => {
152
+ if (meta[field] !== void 0) if (field === "format") {
153
+ const formatValue = meta[field];
154
+ if (validFormats.includes(formatValue)) result[field] = formatValue;
155
+ } else result[field] = meta[field];
156
+ });
157
+ return result;
158
+ }
159
+ function CreateSwaggerObjectSchema(classType) {
160
+ const validationMetadata = (0, class_validator.getMetadataStorage)().getTargetValidationMetadatas(classType, "", true, false);
161
+ const schema = {
162
+ type: "object",
163
+ properties: {},
164
+ required: []
165
+ };
166
+ const prototype = classType.prototype;
167
+ const propertyKeys = /* @__PURE__ */ new Set();
168
+ Object.getOwnPropertyNames(prototype).forEach((k) => propertyKeys.add(k));
169
+ Object.keys(prototype).forEach((k) => propertyKeys.add(k));
170
+ validationMetadata.forEach((m) => propertyKeys.add(m.propertyName));
171
+ try {
172
+ const instance = new classType();
173
+ Reflect.ownKeys(instance).forEach((k) => {
174
+ if (typeof k === "string") propertyKeys.add(k);
175
+ });
176
+ } catch (_) {}
177
+ propertyKeys.forEach((propertyName) => {
178
+ if (!propertyName || propertyName === "constructor") return;
179
+ const openApiMeta = Reflect.getMetadata("property:openapi", prototype, propertyName);
180
+ if (openApiMeta?.exclude) return;
181
+ const propertyType = Reflect.getMetadata("design:type", prototype, propertyName);
182
+ let swaggerProperty = {};
183
+ switch (propertyType) {
184
+ case String:
185
+ swaggerProperty.type = "string";
186
+ break;
187
+ case Number:
188
+ swaggerProperty.type = "number";
189
+ break;
190
+ case Boolean:
191
+ swaggerProperty.type = "boolean";
192
+ break;
193
+ case Date:
194
+ swaggerProperty.type = "string";
195
+ swaggerProperty.format = "date-time";
196
+ break;
197
+ case Array:
198
+ swaggerProperty.type = "array";
199
+ swaggerProperty.items = { type: "string" };
200
+ break;
201
+ case Object:
202
+ swaggerProperty = CreateSwaggerObjectSchema(propertyType);
203
+ break;
204
+ default: if (propertyType && typeof propertyType === "function") swaggerProperty.$ref = `#/components/schemas/${propertyType.name}`;
205
+ else swaggerProperty.type = propertyType?.name?.toLowerCase() || "string";
206
+ }
207
+ if (openApiMeta) {
208
+ swaggerProperty = {
209
+ ...swaggerProperty,
210
+ ...openApiMeta,
211
+ ...extractOpenApiFields(openApiMeta)
212
+ };
213
+ if (openApiMeta.format === "binary") if (openApiMeta.isArray || propertyType === Array) swaggerProperty = {
214
+ type: "array",
215
+ items: {
216
+ type: "string",
217
+ format: "binary"
218
+ },
219
+ description: openApiMeta.description || "Array of files"
220
+ };
221
+ else swaggerProperty = {
222
+ type: "string",
223
+ format: "binary",
224
+ description: openApiMeta.description || "File upload"
225
+ };
226
+ }
227
+ schema.properties[propertyName] = swaggerProperty;
228
+ });
229
+ validationMetadata.forEach((meta) => {
230
+ const propertyName = meta.propertyName;
231
+ const property = schema.properties[propertyName];
232
+ if (!property) return;
233
+ switch (meta.name) {
234
+ case "isNotEmpty":
235
+ case "isDefined":
236
+ if (!schema.required.includes(propertyName)) schema.required.push(propertyName);
237
+ break;
238
+ case "isOptional":
239
+ schema.required = schema.required.filter((item) => item !== propertyName);
240
+ break;
241
+ case "minLength":
242
+ property.minLength = meta.constraints[0];
243
+ break;
244
+ case "maxLength":
245
+ property.maxLength = meta.constraints[0];
246
+ break;
247
+ case "min":
248
+ property.minimum = meta.constraints[0];
249
+ break;
250
+ case "max":
251
+ property.maximum = meta.constraints[0];
252
+ break;
253
+ case "isEmail":
254
+ property.format = "email";
255
+ break;
256
+ case "isDate":
257
+ property.format = "date-time";
258
+ break;
259
+ case "isIn":
260
+ property.enum = meta.constraints[0];
261
+ break;
262
+ case "isNumber":
263
+ property.type = "number";
264
+ break;
265
+ case "isInt":
266
+ property.type = "integer";
267
+ break;
268
+ case "isBoolean":
269
+ property.type = "boolean";
270
+ break;
271
+ case "isString":
272
+ property.type = "string";
273
+ break;
274
+ }
275
+ });
276
+ if (schema.required.length === 0) delete schema.required;
277
+ return schema;
278
+ }
279
+ function generateClassSchema(classType) {
280
+ const schema = {
281
+ type: "object",
282
+ properties: {},
283
+ required: []
284
+ };
285
+ if (!classType || !classType.prototype) return schema;
286
+ const validationMetadata = (0, class_validator.getMetadataStorage)().getTargetValidationMetadatas(classType, "", true, false);
287
+ const prototype = classType.prototype;
288
+ const propertyKeys = new Set([...Object.getOwnPropertyNames(prototype), ...validationMetadata.map((m) => m.propertyName)]);
289
+ try {
290
+ const instance = new classType();
291
+ Reflect.ownKeys(instance).forEach((k) => {
292
+ if (typeof k === "string") propertyKeys.add(k);
293
+ });
294
+ } catch (_) {}
295
+ propertyKeys.forEach((propertyName) => {
296
+ if (!propertyName || propertyName === "constructor") return;
297
+ const openApiMeta = Reflect.getMetadata("property:openapi", prototype, propertyName);
298
+ if (openApiMeta?.exclude) return;
299
+ const propertyType = Reflect.getMetadata("design:type", prototype, propertyName);
300
+ let swaggerProperty = {};
301
+ switch (propertyType) {
302
+ case String:
303
+ swaggerProperty.type = "string";
304
+ break;
305
+ case Number:
306
+ swaggerProperty.type = "number";
307
+ break;
308
+ case Boolean:
309
+ swaggerProperty.type = "boolean";
310
+ break;
311
+ case Date:
312
+ swaggerProperty.type = "string";
313
+ swaggerProperty.format = "date-time";
314
+ break;
315
+ case Array:
316
+ swaggerProperty.type = "array";
317
+ swaggerProperty.items = { type: "string" };
318
+ break;
319
+ case Object:
320
+ swaggerProperty = generateClassSchema(propertyType);
321
+ break;
322
+ default: if (propertyType && typeof propertyType === "function") swaggerProperty.$ref = `#/components/schemas/${propertyType.name}`;
323
+ else swaggerProperty.type = propertyType?.name?.toLowerCase() || "string";
324
+ }
325
+ if (openApiMeta) {
326
+ const { required: _required, exclude: _exclude, isArray: _isArray, ...safeOpenApiMeta } = openApiMeta;
327
+ swaggerProperty = {
328
+ ...swaggerProperty,
329
+ ...extractOpenApiFields(safeOpenApiMeta)
330
+ };
331
+ }
332
+ schema.properties[propertyName] = swaggerProperty;
333
+ });
334
+ validationMetadata.forEach((meta) => {
335
+ const propertyName = meta.propertyName;
336
+ if (!schema.properties[propertyName]) schema.properties[propertyName] = { type: "string" };
337
+ switch (meta.name) {
338
+ case "isNotEmpty":
339
+ case "isDefined":
340
+ if (!schema.required.includes(propertyName)) schema.required.push(propertyName);
341
+ break;
342
+ case "isOptional":
343
+ schema.required = schema.required.filter((item) => item !== propertyName);
344
+ break;
345
+ case "minLength":
346
+ schema.properties[propertyName].minLength = meta.constraints[0];
347
+ break;
348
+ case "maxLength":
349
+ schema.properties[propertyName].maxLength = meta.constraints[0];
350
+ break;
351
+ case "min":
352
+ schema.properties[propertyName].minimum = meta.constraints[0];
353
+ break;
354
+ case "max":
355
+ schema.properties[propertyName].maximum = meta.constraints[0];
356
+ break;
357
+ case "isEmail":
358
+ schema.properties[propertyName].format = "email";
359
+ break;
360
+ case "isDate":
361
+ schema.properties[propertyName].format = "date-time";
362
+ break;
363
+ case "isIn":
364
+ schema.properties[propertyName].enum = meta.constraints[0];
365
+ break;
366
+ case "isNumber":
367
+ schema.properties[propertyName].type = "number";
368
+ break;
369
+ case "isInt":
370
+ schema.properties[propertyName].type = "integer";
371
+ break;
372
+ case "isBoolean":
373
+ schema.properties[propertyName].type = "boolean";
374
+ break;
375
+ case "isString":
376
+ schema.properties[propertyName].type = "string";
377
+ break;
378
+ }
379
+ });
380
+ if (schema.required.length === 0) delete schema.required;
381
+ return schema;
382
+ }
383
+ function generateSwaggerSchema(controllers) {
384
+ if (!Array.isArray(controllers)) return generateClassSchema(controllers);
385
+ const components = {};
386
+ for (const controller of controllers) {
387
+ if (!controller || typeof controller !== "function") continue;
388
+ if (!controller.prototype) continue;
389
+ if (Reflect.getMetadata(CONTROLLER_META_KEY, controller)) continue;
390
+ if (!Reflect.getMetadata("openapi:schema", controller)) continue;
391
+ components[controller.name] = generateClassSchema(controller);
392
+ }
393
+ return { components: Object.keys(components).length > 0 ? { schemas: components } : void 0 };
394
+ }
395
+ function OpenApiResponse$1(code = 200, model, description = "Successful response") {
396
+ let dataSchema;
397
+ if (typeof model === "function") dataSchema = generateClassSchema(model);
398
+ else if (model && typeof model === "object") dataSchema = inferSchemaFromExample(model);
399
+ else dataSchema = { type: "string" };
400
+ let message = "OK";
401
+ switch (code) {
402
+ case 400:
403
+ message = "Error";
404
+ description = "Error: Bad Request";
405
+ break;
406
+ case 401:
407
+ message = "Error";
408
+ description = "Error: Unauthorized";
409
+ break;
410
+ case 403:
411
+ message = "Error";
412
+ description = "Error: Forbidden";
413
+ break;
414
+ case 201:
415
+ message = "Created";
416
+ description = "Success: Created";
417
+ break;
418
+ case 500:
419
+ message = "Error";
420
+ description = "Error: InternalError";
421
+ break;
422
+ }
423
+ return {
424
+ description,
425
+ content: { "application/json": { schema: {
426
+ type: "object",
427
+ properties: {
428
+ code: {
429
+ type: "number",
430
+ example: code
431
+ },
432
+ status: {
433
+ type: "string",
434
+ example: message
435
+ },
436
+ data: dataSchema
437
+ }
438
+ } } }
439
+ };
440
+ }
441
+ function inferSchemaFromExample(obj) {
442
+ if (Array.isArray(obj)) return {
443
+ type: "array",
444
+ items: inferSchemaFromExample(obj[0] ?? {})
445
+ };
446
+ if (obj && typeof obj === "object") {
447
+ const properties = {};
448
+ for (const [key, value] of Object.entries(obj)) properties[key] = inferType(value);
449
+ return {
450
+ type: "object",
451
+ properties
452
+ };
453
+ }
454
+ return inferType(obj);
455
+ }
456
+ function inferType(value) {
457
+ switch (typeof value) {
458
+ case "string": return {
459
+ type: "string",
460
+ example: value
461
+ };
462
+ case "number": return {
463
+ type: "number",
464
+ example: value
465
+ };
466
+ case "boolean": return {
467
+ type: "boolean",
468
+ example: value
469
+ };
470
+ case "object":
471
+ if (Array.isArray(value)) return inferSchemaFromExample(value);
472
+ if (value === null) return { type: "null" };
473
+ return inferSchemaFromExample(value);
474
+ default: return { type: "string" };
475
+ }
476
+ }
477
+ //#endregion
478
+ //#region src/controller.ts
479
+ /**
480
+ * @copyright 2024
481
+ * @author Tareq Hossain
482
+ * @email xtrinsic96@gmail.com
483
+ * @url https://github.com/xtareq
484
+ */
485
+ init_container();
486
+ const REQUEST_METADATA_KEY = Symbol("avleon:request");
487
+ function AvleonRequest() {
488
+ return (target, propertyKey, parameterIndex) => {
489
+ const existingParams = Reflect.getMetadata(REQUEST_METADATA_KEY, target, propertyKey) || [];
490
+ existingParams.push({
491
+ index: parameterIndex,
492
+ type: "request"
493
+ });
494
+ Reflect.defineMetadata(REQUEST_METADATA_KEY, existingParams, target, propertyKey);
495
+ };
496
+ }
497
+ function createControllerDecorator(type = "web") {
498
+ return function(pathOrOptions, maybeOptions) {
499
+ return function(target) {
500
+ let path = "/";
501
+ let options = {};
502
+ if (typeof pathOrOptions === "string") {
503
+ path = pathOrOptions;
504
+ options = maybeOptions || {};
505
+ } else if (typeof pathOrOptions === "object") {
506
+ options = pathOrOptions;
507
+ path = options.path || "/";
508
+ }
509
+ Reflect.defineMetadata(API_CONTROLLER_METADATA_KEY, true, target);
510
+ if (typeof typedi.Service === "function") {
511
+ registerController(target);
512
+ (0, typedi.Service)()(target);
513
+ Reflect.defineMetadata(CONTROLLER_META_KEY, {
514
+ type,
515
+ path,
516
+ options
517
+ }, target);
518
+ } else throw new Error("Service decorator is not a function");
519
+ };
520
+ };
521
+ }
522
+ function ApiController(pathOrOptions = "/", mayBeOptions) {
523
+ if (typeof pathOrOptions == "function") {
524
+ Reflect.defineMetadata(API_CONTROLLER_METADATA_KEY, true, pathOrOptions);
525
+ if (typeof typedi.Service === "function") {
526
+ registerController(pathOrOptions);
527
+ (0, typedi.Service)()(pathOrOptions);
528
+ Reflect.defineMetadata(CONTROLLER_META_KEY, {
529
+ type: "api",
530
+ path: "/",
531
+ options: {}
532
+ }, pathOrOptions);
533
+ } else throw new Error("Service decorator is not a function");
534
+ } else {
535
+ if (mayBeOptions) return createControllerDecorator("api")(pathOrOptions, mayBeOptions);
536
+ return createControllerDecorator("api")(pathOrOptions);
537
+ }
538
+ }
539
+ //#endregion
540
+ //#region src/route-methods.ts
541
+ init_container();
542
+ /**
543
+ * Generic Route decorator factory
544
+ */
545
+ function Route(method, pathOrOptions, maybeOptions) {
546
+ return function(target, propertyKey, descriptor) {
547
+ let path = "/";
548
+ let options = {};
549
+ if (typeof pathOrOptions === "string") {
550
+ path = pathOrOptions || "/";
551
+ options = maybeOptions || {};
552
+ } else if (typeof pathOrOptions === "object" && pathOrOptions !== null) {
553
+ options = pathOrOptions;
554
+ path = options.path || options.name || "/";
555
+ } else {
556
+ options = maybeOptions || {};
557
+ path = "/";
558
+ }
559
+ path = typeof path === "string" ? path : "/";
560
+ Reflect.defineMetadata("route:path", path, target, propertyKey);
561
+ Reflect.defineMetadata("route:method", method, target, propertyKey);
562
+ Reflect.defineMetadata(ROUTE_META_KEY, {
563
+ ...options,
564
+ method,
565
+ path,
566
+ controller: target.constructor.name
567
+ }, target, propertyKey);
568
+ if (options) Reflect.defineMetadata("route:options", options, target, propertyKey);
569
+ };
570
+ }
571
+ const Get = (pathOrOptions, maybeOptions) => Route("GET", pathOrOptions, maybeOptions);
572
+ const Post = (pathOrOptions, maybeOptions) => Route("POST", pathOrOptions, maybeOptions);
573
+ const Put = (pathOrOptions, maybeOptions) => Route("PUT", pathOrOptions, maybeOptions);
574
+ const Delete = (pathOrOptions, maybeOptions) => Route("DELETE", pathOrOptions, maybeOptions);
575
+ const Patch = (pathOrOptions, maybeOptions) => Route("PATCH", pathOrOptions, maybeOptions);
576
+ const Options = (pathOrOptions, maybeOptions) => Route("OPTIONS", pathOrOptions, maybeOptions);
577
+ const All = (pathOrOptions, maybeOptions) => Route("ALL", pathOrOptions, maybeOptions);
578
+ //#endregion
579
+ //#region src/openapi.ts
580
+ /**
581
+ * Normalize a flat ParamsSchemaMap into a valid JSON Schema object
582
+ * that Fastify/AJV can validate against.
583
+ *
584
+ * Input: { id: { type: "string", example: "abc-123" } }
585
+ * Output: { type: "object", properties: { id: { type: "string", example: "abc-123" } } }
586
+ */
587
+ function normalizeParamsToJsonSchema(params, requiredKeys = []) {
588
+ const properties = {};
589
+ for (const [key, val] of Object.entries(params)) properties[key] = {
590
+ type: "string",
591
+ ...val
592
+ };
593
+ const schema = {
594
+ type: "object",
595
+ properties
596
+ };
597
+ if (requiredKeys.length > 0) schema.required = requiredKeys;
598
+ return schema;
599
+ }
600
+ function OpenApiSchema() {
601
+ return function(target) {
602
+ Reflect.defineMetadata("openapi:schema", true, target);
603
+ };
604
+ }
605
+ function OpenApi(options) {
606
+ return function(target, propertyKey, descriptor) {
607
+ if (typeof target === "function" && !propertyKey) Reflect.defineMetadata("controller:openapi", options, target);
608
+ else if (descriptor) Reflect.defineMetadata("route:openapi", options, target, propertyKey);
609
+ else if (propertyKey) Reflect.defineMetadata("property:openapi", options, target, propertyKey);
610
+ };
611
+ }
612
+ //#endregion
613
+ //#region src/utils/common-utils.ts
614
+ /**
615
+ * @copyright 2024
616
+ * @author Tareq Hossain
617
+ * @email xtrinsic96@gmail.com
618
+ * @url https://github.com/xtareq
619
+ */
620
+ function isConstructor(func) {
621
+ if (typeof func !== "function") return false;
622
+ if (func === Function.prototype.bind || func instanceof RegExp) return false;
623
+ if (func.prototype && typeof func.prototype === "object") return true;
624
+ try {
625
+ return typeof new func() === "object";
626
+ } catch (e) {
627
+ return false;
628
+ }
629
+ }
630
+ function formatUrl(path) {
631
+ if (typeof path !== "string") throw new Error("The path must be a string");
632
+ path = path.trim();
633
+ if (!path.startsWith("/")) path = "/" + path;
634
+ path = path.replace(/\/\/+/g, "/");
635
+ if (path.endsWith("/")) path = path.slice(0, -1);
636
+ return path;
637
+ }
638
+ function parsedPath(ipath) {
639
+ return !ipath.startsWith("/") ? "/" + ipath : ipath;
640
+ }
641
+ function normalizePath(base = "/", subPath = "/") {
642
+ return `/${base}/${subPath}`.replace(/\/+/g, "/").replace(/\/$/, "");
643
+ }
644
+ function extrctParamFromUrl(url) {
645
+ return url.split("/").filter((x) => x.startsWith(":") || x.startsWith("?:")).map((f) => ({
646
+ key: f.replace(/(\?|:)/g, ""),
647
+ required: !f.startsWith("?:")
648
+ }));
649
+ }
650
+ function findDuplicates(arr) {
651
+ const seen = /* @__PURE__ */ new Set();
652
+ const duplicates = /* @__PURE__ */ new Set();
653
+ for (const str of arr) if (seen.has(str)) duplicates.add(str);
654
+ else seen.add(str);
655
+ return Array.from(duplicates);
656
+ }
657
+ function sleep(ms) {
658
+ return new Promise((resolve) => setTimeout(resolve, ms));
659
+ }
660
+ var uuid, getLineNumber;
661
+ var init_common_utils = require_chunk.__esmMin((() => {
662
+ uuid = node_crypto.default.randomUUID();
663
+ getLineNumber = (filePath, rpath) => {
664
+ let numbers = [];
665
+ try {
666
+ const lines = node_fs.default.readFileSync(filePath, "utf8").split("\n");
667
+ for (let i = 0; i < lines.length; i++) {
668
+ const match = lines[i].match(rpath);
669
+ if (match) {
670
+ console.log(match);
671
+ numbers.push({
672
+ line: i + 1,
673
+ column: match.index ?? 0
674
+ });
675
+ }
676
+ }
677
+ return numbers;
678
+ } catch (error) {
679
+ return numbers;
680
+ }
681
+ };
682
+ }));
683
+ //#endregion
684
+ //#region src/utils/object-utils.ts
685
+ /**
686
+ * @copyright 2024
687
+ * @author Tareq Hossain
688
+ * @email xtrinsic96@gmail.com
689
+ * @url https://github.com/xtareq
690
+ */
691
+ function pick(obj, paths) {
692
+ const result = {};
693
+ for (const path of paths) {
694
+ const keys = path.split(".");
695
+ let source = obj;
696
+ let target = result;
697
+ for (let i = 0; i < keys.length; i++) {
698
+ const key = keys[i];
699
+ if (!(key in source)) break;
700
+ if (i === keys.length - 1) target[key] = source[key];
701
+ else {
702
+ source = source[key];
703
+ target[key] = target[key] || {};
704
+ target = target[key];
705
+ }
706
+ }
707
+ }
708
+ return result;
709
+ }
710
+ function exclude(obj, paths) {
711
+ if (Array.isArray(obj)) return obj.map((item) => exclude(item, paths));
712
+ const clone = structuredClone(obj);
713
+ for (const path of paths) {
714
+ const keys = path.split(".");
715
+ let target = clone;
716
+ for (let i = 0; i < keys.length - 1; i++) {
717
+ if (!(keys[i] in target)) break;
718
+ target = target[keys[i]];
719
+ }
720
+ delete target?.[keys[keys.length - 1]];
721
+ }
722
+ return clone;
723
+ }
724
+ function autoCast(value, typeHint, schema) {
725
+ if (value === null || value === void 0) return value;
726
+ if (Array.isArray(value)) {
727
+ const elementType = Array.isArray(typeHint) ? typeHint[0] : void 0;
728
+ return value.map((v) => autoCast(v, elementType));
729
+ }
730
+ if (typeof value === "object" && !(value instanceof Date)) {
731
+ const result = {};
732
+ for (const [key, val] of Object.entries(value)) {
733
+ let fieldType = void 0;
734
+ if (schema?.properties?.[key]?.type) {
735
+ const t = schema.properties[key].type;
736
+ fieldType = t === "integer" || t === "number" ? Number : t === "boolean" ? Boolean : t === "array" ? Array : t === "object" ? Object : String;
737
+ }
738
+ result[key] = autoCast(val, fieldType);
739
+ }
740
+ return result;
741
+ }
742
+ if (typeof value !== "string") return value;
743
+ const trimmed = value.trim();
744
+ if (typeHint === Boolean || trimmed.toLowerCase() === "true") return true;
745
+ if (trimmed.toLowerCase() === "false") return false;
746
+ if (typeHint === Number || !isNaN(Number(trimmed)) && trimmed !== "") {
747
+ const n = Number(trimmed);
748
+ if (!isNaN(n)) return n;
749
+ }
750
+ if (trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]")) try {
751
+ return autoCast(JSON.parse(trimmed), typeHint, schema);
752
+ } catch {
753
+ return trimmed;
754
+ }
755
+ if (typeHint === Date || /^\d{4}-\d{2}-\d{2}([Tt]\d{2}:\d{2})?/.test(trimmed)) {
756
+ const d = new Date(trimmed);
757
+ if (!isNaN(d.getTime())) return d;
758
+ }
759
+ return trimmed;
760
+ }
761
+ /**
762
+ * Deeply normalizes query strings into nested JS objects.
763
+ */
764
+ function normalizeQueryDeep(query) {
765
+ const result = {};
766
+ const setDeep = (obj, path, value) => {
767
+ let current = obj;
768
+ for (let i = 0; i < path.length; i++) {
769
+ const key = path[i];
770
+ const nextKey = path[i + 1];
771
+ if (i === path.length - 1) if (key === "") {
772
+ if (!Array.isArray(current)) current = [];
773
+ current.push(value);
774
+ } else if (Array.isArray(current[key])) current[key].push(value);
775
+ else if (current[key] !== void 0) current[key] = [current[key], value];
776
+ else current[key] = value;
777
+ else {
778
+ if (!current[key]) current[key] = nextKey === "" || /^\d+$/.test(nextKey) ? [] : {};
779
+ current = current[key];
780
+ }
781
+ }
782
+ };
783
+ for (const [rawKey, rawValue] of Object.entries(query)) {
784
+ const path = [];
785
+ const regex = /([^\[\]]+)|(\[\])/g;
786
+ let match;
787
+ while ((match = regex.exec(rawKey)) !== null) if (match[1]) path.push(match[1]);
788
+ else if (match[2]) path.push("");
789
+ if (path.length === 0) if (result[rawKey]) if (Array.isArray(result[rawKey])) result[rawKey].push(rawValue);
790
+ else result[rawKey] = [result[rawKey], rawValue];
791
+ else result[rawKey] = rawValue;
792
+ else setDeep(result, path, rawValue);
793
+ }
794
+ return result;
795
+ }
796
+ function transformObjectByInstanceToObject(instance, value) {
797
+ return (0, class_transformer.instanceToPlain)((0, class_transformer.plainToInstance)(instance, value), {
798
+ excludeExtraneousValues: true,
799
+ exposeUnsetFields: true
800
+ });
801
+ }
802
+ function jsonToJs(value) {
803
+ try {
804
+ return JSON.parse(value);
805
+ } catch (err) {
806
+ return false;
807
+ }
808
+ }
809
+ function jsonToInstance(value, instance) {
810
+ try {
811
+ return (0, class_transformer.plainToInstance)(instance, JSON.parse(value));
812
+ } catch (err) {
813
+ return false;
814
+ }
815
+ }
816
+ var init_object_utils = require_chunk.__esmMin((() => {}));
817
+ //#endregion
818
+ //#region src/exceptions/http-exceptions.ts
819
+ var BaseHttpException, BadRequestException, ValidationErrorException, InternalErrorException, NotFoundException, UnauthorizedException, ForbiddenException, HttpExceptions;
820
+ var init_http_exceptions = require_chunk.__esmMin((() => {
821
+ BaseHttpException = class extends Error {
822
+ code = 500;
823
+ name = "HttpException";
824
+ payload;
825
+ constructor(message) {
826
+ const stringMessage = typeof message === "string" ? message : JSON.stringify(message);
827
+ super(stringMessage);
828
+ this.payload = typeof message === "string" ? { message } : message;
829
+ }
830
+ isCustomException() {
831
+ return true;
832
+ }
833
+ };
834
+ BadRequestException = class extends BaseHttpException {
835
+ name = "BadRequest";
836
+ code = 400;
837
+ constructor(message) {
838
+ super(message);
839
+ }
840
+ };
841
+ ValidationErrorException = class extends BadRequestException {
842
+ name = "ValidationError";
843
+ };
844
+ InternalErrorException = class extends BaseHttpException {
845
+ name = "InternalError";
846
+ code = 500;
847
+ constructor(message = "Something going wrong") {
848
+ super(message);
849
+ }
850
+ };
851
+ NotFoundException = class extends BaseHttpException {
852
+ name = "NotFound";
853
+ code = 404;
854
+ constructor(message) {
855
+ super(message);
856
+ }
857
+ };
858
+ UnauthorizedException = class extends BaseHttpException {
859
+ name = "Unauthorized";
860
+ code = 401;
861
+ constructor(message) {
862
+ super(message);
863
+ }
864
+ };
865
+ ForbiddenException = class extends BaseHttpException {
866
+ name = "Forbidden";
867
+ code = 403;
868
+ constructor(message) {
869
+ super(message);
870
+ }
871
+ };
872
+ HttpExceptions = {
873
+ notFound: (message = "") => new NotFoundException(message),
874
+ validationError: (message = "") => new ValidationErrorException(message),
875
+ badRequest: (message = "") => new BadRequestException(message),
876
+ unauthorized: (message = "") => new UnauthorizedException(message),
877
+ forbidden: (message = "") => new ForbiddenException(message),
878
+ internalError: (message = "") => new InternalErrorException(message)
879
+ };
880
+ }));
881
+ //#endregion
882
+ //#region src/exceptions/index.ts
883
+ var init_exceptions = require_chunk.__esmMin((() => {
884
+ init_http_exceptions();
885
+ }));
886
+ //#endregion
887
+ //#region src/utils/validation-utils.ts
888
+ /**
889
+ * @copyright 2024
890
+ * @author Tareq Hossain
891
+ * @email xtrinsic96@gmail.com
892
+ * @url https://github.com/xtareq
893
+ */
894
+ function getDataType(expectedType) {
895
+ switch (expectedType.name) {
896
+ case "Object":
897
+ if (Array.isArray(expectedType)) return "array";
898
+ return "object";
899
+ case "String": return "string";
900
+ case "Number": return "number";
901
+ case "Boolean": return "boolean";
902
+ default: return expectedType;
903
+ }
904
+ }
905
+ function isValidType(value, expectedType) {
906
+ if (value === void 0 || value === null) return true;
907
+ switch (expectedType.name) {
908
+ case "String": return typeof value === "string";
909
+ case "Number": return typeof value === "number" || !isNaN(Number(value));
910
+ case "Boolean": return typeof value === "boolean";
911
+ default: return value instanceof expectedType;
912
+ }
913
+ }
914
+ function isValidJsonString(value) {
915
+ try {
916
+ return JSON.parse(value);
917
+ } catch (err) {
918
+ return false;
919
+ }
920
+ }
921
+ async function validateObjectByInstance(target, value = {}, options = "array") {
922
+ try {
923
+ const { validateOrReject } = require("class-validator");
924
+ const { plainToInstance } = require("class-transformer");
925
+ await validateOrReject(plainToInstance(target, value));
926
+ } catch (error) {
927
+ if (typeof error == "object" && Array.isArray(error)) return options == "object" ? error.reduce((acc, x) => {
928
+ acc[x.property] = x.constraints;
929
+ return acc;
930
+ }, {}) : error.map((x) => ({
931
+ path: x.property,
932
+ constraints: x.constraints
933
+ }));
934
+ else throw new InternalErrorException("Can't validate object");
935
+ }
936
+ }
937
+ function validateRequestBody(target, value, options = "array") {
938
+ if (!isClassValidatorClass(target)) return {
939
+ count: 0,
940
+ errors: {}
941
+ };
942
+ const error = (0, class_validator.validateSync)((0, class_transformer.plainToInstance)(target, value ? value : {}));
943
+ const errors = options == "object" ? error.reduce((acc, x) => {
944
+ acc[x.property] = x.constraints;
945
+ return acc;
946
+ }, {}) : error.map((x) => ({
947
+ path: x.property,
948
+ constraints: x.constraints
949
+ }));
950
+ return {
951
+ count: error.length,
952
+ errors
953
+ };
954
+ }
955
+ var isClassValidator, isClassValidatorClass;
956
+ var init_validation_utils = require_chunk.__esmMin((() => {
957
+ init_exceptions();
958
+ isClassValidator = (target) => {
959
+ try {
960
+ require("class-validator");
961
+ return (0, class_validator.getMetadataStorage)().getTargetValidationMetadatas(target, "", false, false).length > 0;
962
+ } catch (err) {
963
+ console.log(err);
964
+ return false;
965
+ }
966
+ };
967
+ isClassValidatorClass = (target) => {
968
+ try {
969
+ return require("class-validator").getMetadataStorage().getTargetValidationMetadatas(target, void 0, false, false).length > 0;
970
+ } catch (err) {
971
+ return false;
972
+ }
973
+ };
974
+ }));
975
+ //#endregion
976
+ //#region src/exceptions/system-exception.ts
977
+ var SystemUseError, EnvironmentVariableNotFound;
978
+ var init_system_exception = require_chunk.__esmMin((() => {
979
+ SystemUseError = class extends Error {
980
+ constructor(message) {
981
+ super(message);
982
+ }
983
+ };
984
+ EnvironmentVariableNotFound = class extends Error {
985
+ constructor(key) {
986
+ super(`${key} not found in environment variables.`);
987
+ }
988
+ };
989
+ }));
990
+ //#endregion
991
+ //#region src/utils/di-utils.ts
992
+ function inject(cls) {
993
+ try {
994
+ return Container.get(cls);
995
+ } catch (error) {
996
+ throw new SystemUseError("Not a project class. Maybe you wanna register it first.");
997
+ }
998
+ }
999
+ var init_di_utils = require_chunk.__esmMin((() => {
1000
+ init_container();
1001
+ init_system_exception();
1002
+ }));
1003
+ //#endregion
1004
+ //#region src/validation.ts
1005
+ function validateOrThrow(obj, rules, options) {
1006
+ const errors = new Validator(rules, options).validate(obj);
1007
+ if (errors[0].length > 0) throw new BadRequestException(errors[0]);
1008
+ return errors[1];
1009
+ }
1010
+ var PValidationRule, Validator, isBool, parseBoolean;
1011
+ var init_validation = require_chunk.__esmMin((() => {
1012
+ init_exceptions();
1013
+ PValidationRule = class {
1014
+ name;
1015
+ type;
1016
+ message;
1017
+ constructor(name, type, message) {
1018
+ this.name = name;
1019
+ this.type = type;
1020
+ this.message = message;
1021
+ }
1022
+ };
1023
+ Validator = class {
1024
+ rules = [];
1025
+ options = {};
1026
+ constructor(obj, options) {
1027
+ this.init(obj);
1028
+ if (options) this.options = options;
1029
+ }
1030
+ init(obj) {
1031
+ Object.keys(obj).forEach((key) => {
1032
+ const rule = obj[key];
1033
+ this.rules.push(new PValidationRule(key, rule.type, rule.message));
1034
+ });
1035
+ }
1036
+ validate(obj, options) {
1037
+ const erors = [];
1038
+ this.rules.forEach((k) => {
1039
+ const r = Object.keys(obj).find((key) => key == k.name);
1040
+ let messages = [];
1041
+ if (!r || obj[r] == void 0 || obj[r] == "") messages.push({
1042
+ constraint: "required",
1043
+ message: k.name + " is required"
1044
+ });
1045
+ if (k.type == "string" && typeof obj[k.name] != "string") messages.push({
1046
+ constraint: "type",
1047
+ message: `${k.name} must be type ${k.type}`
1048
+ });
1049
+ if (k.type == "number" && !parseInt(obj[k.name])) messages.push({
1050
+ constraint: "type",
1051
+ message: `${k.name} must be type ${k.type}`
1052
+ });
1053
+ if (k.type == "number") obj[k.name] = parseInt(obj[k.name]);
1054
+ if (k.type == "boolean" && !isBool(obj[k.name])) messages.push({
1055
+ constraint: "type",
1056
+ message: `${k.name} must be type ${k.type}`
1057
+ });
1058
+ if (k.type == "boolean") obj[k.name] = parseBoolean(obj[k.name]);
1059
+ if (messages.length > 0) erors.push({
1060
+ path: k.name,
1061
+ ...this.options.location ? { location: this.options.location } : {},
1062
+ constraints: messages
1063
+ });
1064
+ });
1065
+ return [erors, obj];
1066
+ }
1067
+ };
1068
+ isBool = (val) => {
1069
+ if (typeof val == "boolean") return true;
1070
+ if (parseInt(val) == 0 || parseInt(val) == 1) return true;
1071
+ if (val == "true" || val == "false") return true;
1072
+ return false;
1073
+ };
1074
+ parseBoolean = (val) => {
1075
+ if (typeof val === "boolean") return val;
1076
+ if (parseInt(val) == 1) return true;
1077
+ if (typeof val === "string") return val.trim().toLowerCase() === "true";
1078
+ return false;
1079
+ };
1080
+ }));
1081
+ //#endregion
1082
+ //#region src/helpers.ts
1083
+ var init_helpers = require_chunk.__esmMin((() => {
1084
+ init_common_utils();
1085
+ init_object_utils();
1086
+ init_validation_utils();
1087
+ init_di_utils();
1088
+ init_validation();
1089
+ }));
1090
+ //#endregion
1091
+ //#region src/params.ts
1092
+ init_container();
1093
+ init_helpers();
1094
+ function createParamDecorator(type) {
1095
+ return function(key, options = {}) {
1096
+ return function(target, propertyKey, parameterIndex) {
1097
+ let metaKey;
1098
+ switch (type) {
1099
+ case "route:param":
1100
+ metaKey = PARAM_META_KEY;
1101
+ break;
1102
+ case "route:query":
1103
+ metaKey = QUERY_META_KEY;
1104
+ break;
1105
+ case "route:body":
1106
+ metaKey = REQUEST_BODY_META_KEY;
1107
+ break;
1108
+ case "route:user":
1109
+ metaKey = REQUEST_USER_META_KEY;
1110
+ break;
1111
+ case "route:header":
1112
+ metaKey = REQUEST_HEADER_META_KEY;
1113
+ break;
1114
+ default: throw new Error(`Unknown param decorator type: ${String(type)}`);
1115
+ }
1116
+ const existingParams = Reflect.getMetadata(metaKey, target, propertyKey) || [];
1117
+ const paramNames = target[propertyKey].toString().match(/\(([^)]*)\)/)?.[1]?.split(",").map((n) => n.trim()) || [];
1118
+ const paramDataType = (Reflect.getMetadata("design:paramtypes", target, propertyKey) || [])[parameterIndex];
1119
+ existingParams.push({
1120
+ index: parameterIndex,
1121
+ key: typeof key === "string" ? key : "all",
1122
+ name: paramNames[parameterIndex],
1123
+ required: options.required ?? true,
1124
+ validate: options.validate ?? true,
1125
+ dataType: getDataType(paramDataType),
1126
+ validatorClass: isClassValidatorClass(paramDataType),
1127
+ schema: isClassValidatorClass(paramDataType) ? generateClassSchema(paramDataType) : null,
1128
+ type
1129
+ });
1130
+ Reflect.defineMetadata(metaKey, existingParams, target, propertyKey);
1131
+ };
1132
+ };
1133
+ }
1134
+ const Param = createParamDecorator("route:param");
1135
+ const Query = createParamDecorator("route:query");
1136
+ const Body = createParamDecorator("route:body");
1137
+ const Header = createParamDecorator("route:header");
1138
+ const AuthUser = createParamDecorator("route:user");
1139
+ //#endregion
1140
+ //#region src/decorators.ts
1141
+ /**
1142
+ * @copyright 2024
1143
+ * @author Tareq Hossain
1144
+ * @email xtrinsic96@gmail.com
1145
+ * @url https://github.com/xtareq
1146
+ */
1147
+ function AppService(target) {
1148
+ if (target) (0, typedi.Service)()(target);
1149
+ else return function(tg) {
1150
+ (0, typedi.Service)()(tg);
1151
+ };
1152
+ }
1153
+ const Utility = typedi.Service;
1154
+ const Helper = typedi.Service;
1155
+ //#endregion
1156
+ //#region src/core/router.ts
1157
+ init_helpers();
1158
+ init_container();
1159
+ init_exceptions();
1160
+ /**
1161
+ * Normalize a flat params/query map like:
1162
+ * { id: { type: "string", example: "abc-123" } }
1163
+ * into a valid AJV/JSON Schema object:
1164
+ * { type: "object", properties: { id: { type: "string", example: "abc-123" } } }
1165
+ */
1166
+ function normalizeParamsToJsonSchema$1(map, requiredKeys = []) {
1167
+ const properties = {};
1168
+ for (const [key, val] of Object.entries(map)) {
1169
+ const { required, ...rest } = val;
1170
+ properties[key] = {
1171
+ type: "string",
1172
+ ...rest
1173
+ };
1174
+ }
1175
+ const schema = {
1176
+ type: "object",
1177
+ properties
1178
+ };
1179
+ if (requiredKeys.length > 0) schema.required = requiredKeys;
1180
+ return schema;
1181
+ }
1182
+ /**
1183
+ * Take a raw @OpenApi schema object and return a Fastify-compatible
1184
+ * route schema — normalizing params, query → querystring, and headers.
1185
+ */
1186
+ function buildRouteSchema(raw) {
1187
+ const schema = { ...raw };
1188
+ if (raw.params && typeof raw.params === "object" && !raw.params.type) {
1189
+ const required = Object.entries(raw.params).filter(([, v]) => v.required !== false).map(([k]) => k);
1190
+ schema.params = normalizeParamsToJsonSchema$1(raw.params, required);
1191
+ }
1192
+ if (raw.query && typeof raw.query === "object" && !raw.query.type) {
1193
+ const required = Object.entries(raw.query).filter(([, v]) => v.required === true).map(([k]) => k);
1194
+ schema.querystring = normalizeParamsToJsonSchema$1(raw.query, required);
1195
+ delete schema.query;
1196
+ }
1197
+ if (raw.headers && typeof raw.headers === "object" && !raw.headers.type) schema.headers = normalizeParamsToJsonSchema$1(raw.headers);
1198
+ return schema;
1199
+ }
1200
+ var AvleonRouter = class {
1201
+ routeSet = /* @__PURE__ */ new Set();
1202
+ metaCache = /* @__PURE__ */ new Map();
1203
+ middlewares = /* @__PURE__ */ new Map();
1204
+ rMap = /* @__PURE__ */ new Map();
1205
+ app;
1206
+ authorizeMiddleware;
1207
+ constructor(app) {
1208
+ this.app = app;
1209
+ }
1210
+ setAuthorizeMiddleware(middleware) {
1211
+ this.authorizeMiddleware = middleware;
1212
+ }
1213
+ registerMiddleware(name, instance) {
1214
+ this.middlewares.set(name, instance);
1215
+ }
1216
+ _processMeta(prototype, method) {
1217
+ const cacheKey = `${prototype.constructor.name}_${method}`;
1218
+ if (this.metaCache.has(cacheKey)) return this.metaCache.get(cacheKey);
1219
+ const meta = {
1220
+ request: Reflect.getMetadata(REQUEST_METADATA_KEY, prototype, method) || [],
1221
+ params: Reflect.getMetadata(PARAM_META_KEY, prototype, method) || [],
1222
+ query: Reflect.getMetadata(QUERY_META_KEY, prototype, method) || [],
1223
+ body: Reflect.getMetadata(REQUEST_BODY_META_KEY, prototype, method) || [],
1224
+ file: Reflect.getMetadata(REQUEST_BODY_FILE_KEY, prototype, method) || [],
1225
+ files: Reflect.getMetadata(REQUEST_BODY_FILES_KEY, prototype, method) || [],
1226
+ headers: Reflect.getMetadata(REQUEST_HEADER_META_KEY, prototype, method) || [],
1227
+ currentUser: Reflect.getMetadata(REQUEST_USER_META_KEY, prototype, method) || []
1228
+ };
1229
+ this.metaCache.set(cacheKey, meta);
1230
+ return meta;
1231
+ }
1232
+ executeMiddlewares(target, propertyKey) {
1233
+ const classMiddlewares = Reflect.getMetadata("controller:middleware", target.constructor) || [];
1234
+ const methodMiddlewares = propertyKey ? Reflect.getMetadata("route:middleware", target, propertyKey) || [] : [];
1235
+ return [...classMiddlewares, ...methodMiddlewares];
1236
+ }
1237
+ async buildController(controller) {
1238
+ const ctrl = typedi.default.get(controller);
1239
+ const controllerMeta = Reflect.getMetadata(CONTROLLER_META_KEY, ctrl.constructor);
1240
+ if (!controllerMeta) return;
1241
+ const prototype = Object.getPrototypeOf(ctrl);
1242
+ const methods = Object.getOwnPropertyNames(prototype).filter((name) => name !== "constructor");
1243
+ const tag = ctrl.constructor.name.replace("Controller", "");
1244
+ const swaggerControllerMeta = Reflect.getMetadata("controller:openapi", ctrl.constructor) || {};
1245
+ const authClsMeata = Reflect.getMetadata(AUTHORIZATION_META_KEY, ctrl.constructor) || {
1246
+ authorize: false,
1247
+ options: void 0
1248
+ };
1249
+ for await (const method of methods) {
1250
+ const methodMeta = Reflect.getMetadata(ROUTE_META_KEY, prototype, method);
1251
+ if (!methodMeta) continue;
1252
+ const methodmetaOptions = {
1253
+ method: methodMeta.method.toLowerCase(),
1254
+ path: formatUrl(controllerMeta.path + methodMeta.path)
1255
+ };
1256
+ const routeKey = `${methodmetaOptions.method}:${methodmetaOptions.path}`;
1257
+ if (!this.routeSet.has(routeKey)) this.routeSet.add(routeKey);
1258
+ const classMiddlewares = this.executeMiddlewares(ctrl, method);
1259
+ const swaggerMeta = Reflect.getMetadata("route:openapi", prototype, method) || {};
1260
+ const authClsMethodMeata = Reflect.getMetadata(AUTHORIZATION_META_KEY, ctrl.constructor, method) || {
1261
+ authorize: false,
1262
+ options: void 0
1263
+ };
1264
+ const allMeta = this._processMeta(prototype, method);
1265
+ let bodySchema = null;
1266
+ allMeta.body.forEach((r) => {
1267
+ if (r.schema) bodySchema = { ...r.schema };
1268
+ });
1269
+ let schema = {
1270
+ ...swaggerControllerMeta,
1271
+ ...swaggerMeta,
1272
+ tags: [tag]
1273
+ };
1274
+ if (!swaggerMeta.body && bodySchema) schema = {
1275
+ ...schema,
1276
+ body: bodySchema
1277
+ };
1278
+ if (!swaggerMeta.query && !schema.querystring) {
1279
+ for (const queryMeta of allMeta.query) if (queryMeta.validatorClass && queryMeta.schema) {
1280
+ schema.querystring = queryMeta.schema;
1281
+ break;
1282
+ }
1283
+ }
1284
+ if (!swaggerMeta.body && !bodySchema) {
1285
+ for (const bodyMeta of allMeta.body) if (bodyMeta.validatorClass && bodyMeta.schema) {
1286
+ schema = {
1287
+ ...schema,
1288
+ body: bodyMeta.schema
1289
+ };
1290
+ break;
1291
+ }
1292
+ }
1293
+ const routePath = methodmetaOptions.path === "" ? "/" : methodmetaOptions.path;
1294
+ const isMultipart = schema?.consumes?.includes("multipart/form-data") || Object.values(schema?.body?.properties || {}).some((p) => p.format === "binary");
1295
+ if (isMultipart) {
1296
+ schema.consumes = ["multipart/form-data"];
1297
+ if (!schema.body) schema.body = {
1298
+ type: "object",
1299
+ properties: {}
1300
+ };
1301
+ for (const param of allMeta.body) if (param.type === "route:file") schema.body.properties[param.key] = {
1302
+ type: "string",
1303
+ format: "binary"
1304
+ };
1305
+ else schema.body.properties[param.key] = { type: param.dataType };
1306
+ }
1307
+ const routeSchema = buildRouteSchema(schema);
1308
+ this.app.route({
1309
+ url: routePath,
1310
+ method: methodmetaOptions.method.toUpperCase(),
1311
+ schema: routeSchema,
1312
+ attachValidation: isMultipart,
1313
+ handler: async (req, res) => {
1314
+ let reqClone = req;
1315
+ if (authClsMeata.authorize && this.authorizeMiddleware) {
1316
+ await Container.get(this.authorizeMiddleware).authorize(reqClone, authClsMeata.options);
1317
+ if (res.sent) return;
1318
+ }
1319
+ if (authClsMethodMeata.authorize && this.authorizeMiddleware) {
1320
+ await Container.get(this.authorizeMiddleware).authorize(reqClone, authClsMethodMeata.options);
1321
+ if (res.sent) return;
1322
+ }
1323
+ if (classMiddlewares.length > 0) for (let m of classMiddlewares) {
1324
+ reqClone = await typedi.default.get(m.constructor).invoke(reqClone, res);
1325
+ if (res.sent) return;
1326
+ }
1327
+ const args = await this._mapArgs(reqClone, allMeta);
1328
+ for (let paramMeta of allMeta.params) if (paramMeta.required) validateOrThrow({ [paramMeta.key]: args[paramMeta.index] }, { [paramMeta.key]: { type: paramMeta.dataType } }, { location: "param" });
1329
+ for (let queryMeta of allMeta.query) {
1330
+ if (queryMeta.validatorClass) {
1331
+ const err = await validateObjectByInstance(queryMeta.dataType, args[queryMeta.index]);
1332
+ if (err) return await res.code(400).send({
1333
+ code: 400,
1334
+ error: "ValidationError",
1335
+ errors: err,
1336
+ message: err.message
1337
+ });
1338
+ }
1339
+ if (queryMeta.required) validateOrThrow({ [queryMeta.key]: args[queryMeta.index] }, { [queryMeta.key]: { type: queryMeta.dataType } }, { location: "queryparam" });
1340
+ }
1341
+ if (!isMultipart) {
1342
+ for (let bodyMeta of allMeta.body) if (bodyMeta.validatorClass) {
1343
+ const err = await validateObjectByInstance(bodyMeta.dataType, args[bodyMeta.index]);
1344
+ if (err) return await res.code(400).send({
1345
+ code: 400,
1346
+ error: "ValidationError",
1347
+ errors: err,
1348
+ message: err.message
1349
+ });
1350
+ }
1351
+ }
1352
+ const result = await prototype[method].apply(ctrl, args);
1353
+ if (result?.download) {
1354
+ const { stream, filename } = result;
1355
+ if (!stream || typeof stream.pipe !== "function") return res.code(500).send({
1356
+ code: 500,
1357
+ error: "INTERNAL_ERROR",
1358
+ message: "Invalid stream object"
1359
+ });
1360
+ const contentType = result.contentType || mime.default.getType(filename) || "application/octet-stream";
1361
+ res.header("Content-Type", contentType);
1362
+ res.header("Content-Disposition", `attachment; filename="${filename}"`);
1363
+ stream.on("error", (err) => {
1364
+ console.error("Stream error:", err);
1365
+ if (!res.sent) res.code(500).send({
1366
+ code: 500,
1367
+ error: "StreamError",
1368
+ message: "Error while streaming file."
1369
+ });
1370
+ });
1371
+ return res.send(stream);
1372
+ }
1373
+ if (result instanceof node_stream.default || typeof result?.pipe === "function") {
1374
+ result.on("error", (err) => {
1375
+ console.error("Stream error:", err);
1376
+ if (!res.sent) res.code(500).send({
1377
+ code: 500,
1378
+ error: "StreamError",
1379
+ message: "Error while streaming file."
1380
+ });
1381
+ });
1382
+ res.header("Content-Type", "application/octet-stream");
1383
+ return res.send(result);
1384
+ }
1385
+ return res.send(result);
1386
+ }
1387
+ });
1388
+ }
1389
+ }
1390
+ async _mapArgs(req, meta) {
1391
+ if (!req.hasOwnProperty("_argsCache")) Object.defineProperty(req, "_argsCache", {
1392
+ value: /* @__PURE__ */ new Map(),
1393
+ enumerable: false,
1394
+ writable: false,
1395
+ configurable: false
1396
+ });
1397
+ const cache = req._argsCache;
1398
+ const cacheKey = JSON.stringify(meta);
1399
+ if (cache.has(cacheKey)) return cache.get(cacheKey);
1400
+ const maxIndex = Math.max(...meta.params.map((p) => p.index || 0), ...meta.query.map((q) => q.index), ...meta.body.map((b) => b.index), ...meta.currentUser.map((u) => u.index), ...meta.headers.map((h) => h.index), ...meta.request?.map((r) => r.index) || [], ...meta.file?.map((f) => f.index) || [], ...meta.files?.map((f) => f.index) || [], -1) + 1;
1401
+ const args = new Array(maxIndex).fill(void 0);
1402
+ meta.params.forEach((p) => {
1403
+ const raw = p.key === "all" ? { ...req.params } : req.params[p.key] ?? null;
1404
+ args[p.index] = autoCast(raw, p.dataType, p.schema);
1405
+ });
1406
+ meta.query.forEach((q) => {
1407
+ const raw = q.key === "all" ? normalizeQueryDeep({ ...req.query }) : req.query[q.key];
1408
+ args[q.index] = autoCast(raw, q.dataType, q.schema);
1409
+ });
1410
+ meta.body.forEach((body) => {
1411
+ args[body.index] = {
1412
+ ...req.body,
1413
+ ...req.formData
1414
+ };
1415
+ });
1416
+ meta.currentUser.forEach((user) => {
1417
+ args[user.index] = req.user;
1418
+ });
1419
+ meta.headers.forEach((header) => {
1420
+ args[header.index] = header.key === "all" ? { ...req.headers } : req.headers[header.key];
1421
+ });
1422
+ if (meta.request && meta.request.length > 0) meta.request.forEach((r) => {
1423
+ args[r.index] = req;
1424
+ });
1425
+ const needsFiles = meta.file && meta.file.length > 0 || meta.files && meta.files.length > 0;
1426
+ if (needsFiles && req.headers["content-type"]?.startsWith("multipart/form-data") && req.saveRequestFiles) {
1427
+ const files = await req.saveRequestFiles();
1428
+ if (!files || files.length === 0) {
1429
+ if (meta.files && meta.files.length > 0) throw new BadRequestException({ error: "No files uploaded" });
1430
+ if (meta.file && meta.file.length > 0) meta.file.forEach((f) => {
1431
+ args[f.index] = null;
1432
+ });
1433
+ } else {
1434
+ const fileInfo = files.map((file) => ({
1435
+ type: file.type,
1436
+ filepath: file.filepath,
1437
+ fieldname: file.fieldname,
1438
+ filename: file.filename,
1439
+ encoding: file.encoding,
1440
+ mimetype: file.mimetype,
1441
+ fields: file.fields,
1442
+ toBuffer: file.toBuffer
1443
+ }));
1444
+ if (meta.file && meta.file.length > 0) meta.file.forEach((f) => {
1445
+ if (f.fieldName === "all") args[f.index] = fileInfo[0] || null;
1446
+ else {
1447
+ const file = fileInfo.find((x) => x.fieldname === f.fieldName);
1448
+ if (!file) throw new BadRequestException(`File field "${f.fieldName}" not found in uploaded files`);
1449
+ args[f.index] = file;
1450
+ }
1451
+ });
1452
+ if (meta.files && meta.files.length > 0) meta.files.forEach((f) => {
1453
+ if (f.fieldName === "all") args[f.index] = fileInfo;
1454
+ else {
1455
+ const matchingFiles = fileInfo.filter((x) => x.fieldname === f.fieldName);
1456
+ if (matchingFiles.length === 0) throw new BadRequestException(`No files found for field "${f.fieldName}"`);
1457
+ args[f.index] = matchingFiles;
1458
+ }
1459
+ });
1460
+ }
1461
+ } else if (needsFiles) throw new BadRequestException({ error: "Invalid content type. Expected multipart/form-data for file uploads" });
1462
+ cache.set(cacheKey, args);
1463
+ return args;
1464
+ }
1465
+ _routeHandler(routePath, method, fn) {
1466
+ const routeKey = method + ":" + routePath;
1467
+ this.rMap.set(routeKey, {
1468
+ handler: fn,
1469
+ middlewares: [],
1470
+ schema: {}
1471
+ });
1472
+ const route = {
1473
+ useMiddleware: (middlewares) => {
1474
+ const ms = (Array.isArray(middlewares) ? middlewares : [middlewares]).map((mclass) => {
1475
+ const cls = typedi.default.get(mclass);
1476
+ this.middlewares.set(mclass.name, cls);
1477
+ return cls.invoke;
1478
+ });
1479
+ const r = this.rMap.get(routeKey);
1480
+ if (r) r.middlewares = ms;
1481
+ return route;
1482
+ },
1483
+ useOpenApi: (options) => {
1484
+ const r = this.rMap.get(routeKey);
1485
+ if (r) r.schema = options;
1486
+ return route;
1487
+ }
1488
+ };
1489
+ return route;
1490
+ }
1491
+ mapGet(path = "", fn) {
1492
+ return this._routeHandler(path, "GET", fn);
1493
+ }
1494
+ mapPost(path = "", fn) {
1495
+ return this._routeHandler(path, "POST", fn);
1496
+ }
1497
+ mapPut(path = "", fn) {
1498
+ return this._routeHandler(path, "PUT", fn);
1499
+ }
1500
+ mapDelete(path = "", fn) {
1501
+ return this._routeHandler(path, "DELETE", fn);
1502
+ }
1503
+ async mapRoute(method, path = "", fn) {
1504
+ this.app[method](path, async (req, res) => {
1505
+ try {
1506
+ const result = await fn(req, res);
1507
+ if (typeof result === "object" && result !== null) res.json(result);
1508
+ else res.send(result);
1509
+ } catch (error) {
1510
+ console.error(`Error in ${method} route handler:`, error);
1511
+ res.status(500).send({ error: "Internal Server Error" });
1512
+ }
1513
+ });
1514
+ }
1515
+ processFunctionalRoutes() {
1516
+ this.rMap.forEach((value, key) => {
1517
+ const colonIdx = key.indexOf(":");
1518
+ const m = key.slice(0, colonIdx);
1519
+ const r = key.slice(colonIdx + 1);
1520
+ const routeSchema = buildRouteSchema(value.schema || {});
1521
+ this.app.route({
1522
+ method: m.toUpperCase(),
1523
+ url: r,
1524
+ schema: routeSchema,
1525
+ preHandler: value.middlewares ?? [],
1526
+ handler: async (req, res) => {
1527
+ return value.handler(req, res);
1528
+ }
1529
+ });
1530
+ });
1531
+ }
1532
+ };
1533
+ //#endregion
1534
+ //#region \0@oxc-project+runtime@0.121.0/helpers/decorateMetadata.js
1535
+ function __decorateMetadata(k, v) {
1536
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1537
+ }
1538
+ var init_decorateMetadata = require_chunk.__esmMin((() => {}));
1539
+ //#endregion
1540
+ //#region \0@oxc-project+runtime@0.121.0/helpers/decorate.js
1541
+ function __decorate(decorators, target, key, desc) {
1542
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1543
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1544
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1545
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1546
+ }
1547
+ var init_decorate = require_chunk.__esmMin((() => {}));
1548
+ //#endregion
1549
+ //#region src/kenx-provider.ts
1550
+ var kenx_provider_exports = /* @__PURE__ */ require_chunk.__exportAll({ DB: () => DB });
1551
+ var DB;
1552
+ var init_kenx_provider = require_chunk.__esmMin((() => {
1553
+ init_decorateMetadata();
1554
+ init_decorate();
1555
+ DB = class DB {
1556
+ connection;
1557
+ constructor() {
1558
+ const existing = typedi.Container.has("KnexConnection") ? typedi.Container.get("KnexConnection") : null;
1559
+ if (existing) this.connection = existing;
1560
+ }
1561
+ init(config) {
1562
+ if (!this.connection) {
1563
+ this.connection = require("knex")(config);
1564
+ typedi.Container.set("KnexConnection", this.connection);
1565
+ }
1566
+ return this.connection;
1567
+ }
1568
+ get client() {
1569
+ if (!this.connection) throw new Error("Knex is not initialized. Call DB.init(config) first.");
1570
+ return this.connection;
1571
+ }
1572
+ };
1573
+ DB = __decorate([(0, typedi.Service)(), __decorateMetadata("design:paramtypes", [])], DB);
1574
+ }));
1575
+ //#endregion
1576
+ //#region src/websocket.ts
1577
+ var websocket_exports = /* @__PURE__ */ require_chunk.__exportAll({
1578
+ AvleonSocketIo: () => AvleonSocketIo,
1579
+ SocketIoServer: () => SocketIoServer
1580
+ });
1581
+ var SocketIoServer, AvleonSocketIo;
1582
+ var init_websocket = require_chunk.__esmMin((() => {
1583
+ init_decorate();
1584
+ SocketIoServer = new typedi.Token("SocketIoServer");
1585
+ AvleonSocketIo = class AvleonSocketIo {
1586
+ io;
1587
+ sendToAll() {}
1588
+ sendOnly() {}
1589
+ sendRoom() {}
1590
+ receive(channel) {}
1591
+ };
1592
+ AvleonSocketIo = __decorate([(0, typedi.Service)()], AvleonSocketIo);
1593
+ }));
1594
+ //#endregion
1595
+ //#region src/event-dispatcher.ts
1596
+ var event_dispatcher_exports = /* @__PURE__ */ require_chunk.__exportAll({
1597
+ Dispatch: () => Dispatch,
1598
+ EventDispatcher: () => EventDispatcher,
1599
+ SocketContextService: () => SocketContextService
1600
+ });
1601
+ function Dispatch(event, options) {
1602
+ return function(target, propertyKey, descriptor) {
1603
+ const original = descriptor.value;
1604
+ descriptor.value = async function(...args) {
1605
+ const result = await original.apply(this, args);
1606
+ await typedi.Container.get(EventDispatcher).dispatch(event, result, options);
1607
+ return result;
1608
+ };
1609
+ };
1610
+ }
1611
+ var _ref$1, SocketContextService, EventDispatcher;
1612
+ var init_event_dispatcher = require_chunk.__esmMin((() => {
1613
+ init_websocket();
1614
+ init_helpers();
1615
+ init_decorate();
1616
+ init_decorateMetadata();
1617
+ SocketContextService = class SocketContextService {
1618
+ storage = new node_async_hooks.AsyncLocalStorage();
1619
+ run(socket, fn) {
1620
+ this.storage.run({ socket }, fn);
1621
+ }
1622
+ getSocket() {
1623
+ return this.storage.getStore()?.socket;
1624
+ }
1625
+ };
1626
+ SocketContextService = __decorate([(0, typedi.Service)()], SocketContextService);
1627
+ EventDispatcher = class EventDispatcher {
1628
+ constructor(_context) {
1629
+ this._context = _context;
1630
+ }
1631
+ async dispatch(event, data, options = {}) {
1632
+ const retryCount = options.retry ?? 0;
1633
+ const delay = options.retryDelay ?? 300;
1634
+ for (let attempt = 0; attempt <= retryCount; attempt++) try {
1635
+ await this.dispatchToTransports(event, data, options);
1636
+ break;
1637
+ } catch (err) {
1638
+ if (attempt === retryCount) throw err;
1639
+ await sleep(delay * (attempt + 1));
1640
+ }
1641
+ }
1642
+ async dispatchToTransports(event, data, options) {
1643
+ const transports = options.transports ?? ["socket"];
1644
+ for (const transport of transports) if (transport === "socket") {
1645
+ const io = typedi.Container.get(SocketIoServer);
1646
+ const socket = typedi.Container.get(SocketContextService).getSocket();
1647
+ if (options.broadcast && socket) if (options.room) socket.broadcast.to(options.room).emit(event, data);
1648
+ else socket.broadcast.emit(event, data);
1649
+ else if (options.room) io.to(options.room).emit(event, data);
1650
+ else io.emit(event, data);
1651
+ }
1652
+ }
1653
+ };
1654
+ EventDispatcher = __decorate([(0, typedi.Service)(), __decorateMetadata("design:paramtypes", [typeof (_ref$1 = typeof SocketContextService !== "undefined" && SocketContextService) === "function" ? _ref$1 : Object])], EventDispatcher);
1655
+ }));
1656
+ //#endregion
1657
+ //#region src/event-subscriber.ts
1658
+ var event_subscriber_exports = /* @__PURE__ */ require_chunk.__exportAll({
1659
+ EventSubscriberRegistry: () => EventSubscriberRegistry,
1660
+ Private: () => Private,
1661
+ Subscribe: () => Subscribe,
1662
+ getPrivateChannelResolver: () => getPrivateChannelResolver,
1663
+ getSocketSubscribers: () => getSocketSubscribers,
1664
+ isPrivate: () => isPrivate,
1665
+ registerSocketSubscriber: () => registerSocketSubscriber
1666
+ });
1667
+ function Private(channelResolver) {
1668
+ return function(target, propertyKey) {
1669
+ Reflect.defineMetadata(PRIVATE_META_KEY, true, target, propertyKey);
1670
+ Reflect.defineMetadata(`private:channel:${propertyKey}`, channelResolver, target);
1671
+ };
1672
+ }
1673
+ function isPrivate(target, propertyKey) {
1674
+ return Reflect.getMetadata(PRIVATE_META_KEY, target, propertyKey) || false;
1675
+ }
1676
+ function getPrivateChannelResolver(target, propertyKey) {
1677
+ return Reflect.getMetadata(`private:channel:${propertyKey}`, target);
1678
+ }
1679
+ function registerSocketSubscriber(target) {
1680
+ socketSubscriberClasses.add(target);
1681
+ }
1682
+ function getSocketSubscribers() {
1683
+ return Array.from(socketSubscriberClasses);
1684
+ }
1685
+ function Subscribe(event) {
1686
+ return (target, propertyKey) => {
1687
+ Reflect.defineMetadata("socket:event", event, target, propertyKey);
1688
+ registerSocketSubscriber(target.constructor);
1689
+ };
1690
+ }
1691
+ var _ref, PRIVATE_META_KEY, socketSubscriberClasses, EventSubscriberRegistry;
1692
+ var init_event_subscriber = require_chunk.__esmMin((() => {
1693
+ init_event_dispatcher();
1694
+ init_decorateMetadata();
1695
+ init_decorate();
1696
+ PRIVATE_META_KEY = "avleon:private";
1697
+ socketSubscriberClasses = /* @__PURE__ */ new Set();
1698
+ EventSubscriberRegistry = class EventSubscriberRegistry {
1699
+ constructor(socketContext) {
1700
+ this.socketContext = socketContext;
1701
+ }
1702
+ register(socket) {
1703
+ const subscriberClasses = getSocketSubscribers();
1704
+ for (const SubscriberClass of subscriberClasses) {
1705
+ const instance = typedi.Container.get(SubscriberClass);
1706
+ const prototype = Object.getPrototypeOf(instance);
1707
+ const methodNames = Object.getOwnPropertyNames(prototype).filter((name) => typeof prototype[name] === "function");
1708
+ for (const methodName of methodNames) {
1709
+ const event = Reflect.getMetadata("socket:event", prototype, methodName);
1710
+ const isPrivateListener = isPrivate(instance, methodName);
1711
+ const channelResolver = getPrivateChannelResolver(instance, methodName);
1712
+ if (event) {
1713
+ const channel = isPrivateListener && channelResolver ? channelResolver(socket) : event;
1714
+ console.log("Channel", channel);
1715
+ socket.on(channel, (payload) => {
1716
+ this.socketContext.run(socket, async () => {
1717
+ if (isPrivateListener) {
1718
+ if (!socket.data.user) return;
1719
+ }
1720
+ await instance[methodName](payload, socket.data);
1721
+ });
1722
+ });
1723
+ }
1724
+ }
1725
+ }
1726
+ }
1727
+ };
1728
+ EventSubscriberRegistry = __decorate([(0, typedi.Service)(), __decorateMetadata("design:paramtypes", [typeof (_ref = typeof SocketContextService !== "undefined" && SocketContextService) === "function" ? _ref : Object])], EventSubscriberRegistry);
1729
+ }));
1730
+ //#endregion
1731
+ //#region src/core/application.ts
1732
+ /**
1733
+ * @copyright 2024
1734
+ * @author Tareq Hossain
1735
+ * @email xtrinsic96@gmail.com
1736
+ * @url https://github.com/xtareq
1737
+ */
1738
+ init_exceptions();
1739
+ init_system_exception();
1740
+ init_container();
1741
+ function requireTypeorm() {
1742
+ try {
1743
+ return require("typeorm");
1744
+ } catch {
1745
+ throw new Error("[Avleon] typeorm is not installed.\nRun: npm install typeorm\nThen install a driver: npm install pg (or mysql2, sqlite3, etc.)");
1746
+ }
1747
+ }
1748
+ function requireSocketIo() {
1749
+ try {
1750
+ return require("fastify-socket.io");
1751
+ } catch {
1752
+ throw new Error("[Avleon] fastify-socket.io is not installed.\nRun: npm install fastify-socket.io socket.io");
1753
+ }
1754
+ }
1755
+ function requireSwagger() {
1756
+ try {
1757
+ return require("@fastify/swagger");
1758
+ } catch {
1759
+ throw new Error("[Avleon] @fastify/swagger is not installed.\nRun: npm install @fastify/swagger @fastify/swagger-ui");
1760
+ }
1761
+ }
1762
+ function requireSwaggerUi() {
1763
+ try {
1764
+ return require("@fastify/swagger-ui");
1765
+ } catch {
1766
+ throw new Error("[Avleon] @fastify/swagger-ui is not installed.\nRun: npm install @fastify/swagger-ui");
1767
+ }
1768
+ }
1769
+ function requireScalar() {
1770
+ try {
1771
+ return require("@scalar/fastify-api-reference");
1772
+ } catch {
1773
+ throw new Error("[Avleon] @scalar/fastify-api-reference is not installed.\nRun: npm install @scalar/fastify-api-reference");
1774
+ }
1775
+ }
1776
+ function requireCors() {
1777
+ try {
1778
+ return require("@fastify/cors");
1779
+ } catch {
1780
+ throw new Error("[Avleon] @fastify/cors is not installed.\nRun: npm install @fastify/cors");
1781
+ }
1782
+ }
1783
+ function requireMultipart() {
1784
+ try {
1785
+ return require("@fastify/multipart");
1786
+ } catch {
1787
+ throw new Error("[Avleon] @fastify/multipart is not installed.\nRun: npm install @fastify/multipart");
1788
+ }
1789
+ }
1790
+ function requireStatic() {
1791
+ try {
1792
+ return require("@fastify/static");
1793
+ } catch {
1794
+ throw new Error("[Avleon] @fastify/static is not installed.\nRun: npm install @fastify/static");
1795
+ }
1796
+ }
1797
+ var AvleonApplication = class AvleonApplication {
1798
+ app;
1799
+ router;
1800
+ static instance;
1801
+ alreadyRun = false;
1802
+ hasSwagger = false;
1803
+ globalSwaggerOptions;
1804
+ dataSourceOptions = null;
1805
+ dataSource = null;
1806
+ isMapFeatures = false;
1807
+ registerControllerAuto = false;
1808
+ registerControllerPath = "src/controllers";
1809
+ controllers = [];
1810
+ _hasWebsocket = false;
1811
+ io;
1812
+ constructor(options) {
1813
+ this.app = (0, fastify.default)({
1814
+ ...options?.server,
1815
+ ajv: { customOptions: {
1816
+ strict: false,
1817
+ ...options?.server?.ajv?.customOptions
1818
+ } }
1819
+ });
1820
+ this.router = new AvleonRouter(this.app);
1821
+ if (options?.dataSourceOptions) {
1822
+ this.dataSourceOptions = options.dataSourceOptions;
1823
+ if (this.dataSourceOptions) {
1824
+ const { DataSource } = requireTypeorm();
1825
+ this.dataSource = new DataSource(this.dataSourceOptions);
1826
+ typedi.default.set(DataSource, this.dataSource);
1827
+ }
1828
+ }
1829
+ }
1830
+ static getApp(options) {
1831
+ if (!AvleonApplication.instance) AvleonApplication.instance = new AvleonApplication(options);
1832
+ return AvleonApplication.instance;
1833
+ }
1834
+ /** @deprecated Use `getApp` instead. This is internal. */
1835
+ static getInternalApp(options) {
1836
+ return new AvleonApplication(options);
1837
+ }
1838
+ useCors(options) {
1839
+ this.app.register(requireCors(), options);
1840
+ return this;
1841
+ }
1842
+ useDatasource(dataSource) {
1843
+ const { DataSource } = requireTypeorm();
1844
+ this.dataSource = dataSource;
1845
+ typedi.default.set(DataSource, this.dataSource);
1846
+ return this;
1847
+ }
1848
+ useMultipart(options) {
1849
+ this.app.register(requireMultipart(), {
1850
+ attachFieldsToBody: true,
1851
+ limits: { fileSize: 10 * 1024 * 1024 },
1852
+ ...options
1853
+ });
1854
+ return this;
1855
+ }
1856
+ useOpenApi(options) {
1857
+ this.hasSwagger = true;
1858
+ this.globalSwaggerOptions = options;
1859
+ return this;
1860
+ }
1861
+ async initSwagger(options) {
1862
+ const baseSchema = generateSwaggerSchema((this.controllers ?? []).filter((c) => c != null && typeof c === "function"));
1863
+ await this.app.register(requireSwagger(), { openapi: {
1864
+ ...baseSchema,
1865
+ info: options?.info || {
1866
+ title: "API",
1867
+ version: "1.0.0"
1868
+ },
1869
+ servers: options?.servers,
1870
+ tags: options?.tags,
1871
+ components: {
1872
+ ...baseSchema?.components,
1873
+ ...options?.components,
1874
+ schemas: {
1875
+ ...baseSchema?.components?.schemas,
1876
+ ...options?.components?.schemas
1877
+ }
1878
+ },
1879
+ security: options?.security,
1880
+ externalDocs: options?.externalDocs
1881
+ } });
1882
+ const routePrefix = options?.routePrefix || "/swagger";
1883
+ if (options?.provider === "scalar") await this.app.register(requireScalar(), {
1884
+ routePrefix,
1885
+ configuration: {
1886
+ spec: { content: () => requireSwagger() },
1887
+ ...options?.uiConfig
1888
+ }
1889
+ });
1890
+ else await this.app.register(requireSwaggerUi(), {
1891
+ routePrefix,
1892
+ uiConfig: {
1893
+ docExpansion: "full",
1894
+ deepLinking: false,
1895
+ ...options?.uiConfig
1896
+ },
1897
+ uiHooks: {
1898
+ onRequest: function(request, reply, next) {
1899
+ next();
1900
+ },
1901
+ preHandler: function(request, reply, next) {
1902
+ next();
1903
+ }
1904
+ },
1905
+ staticCSP: true,
1906
+ transformSpecificationClone: true
1907
+ });
1908
+ }
1909
+ useMiddlewares(middlewares) {
1910
+ middlewares.forEach((m) => {
1911
+ const cls = typedi.default.get(m);
1912
+ this.app.addHook("preHandler", async (req, res) => {
1913
+ await cls.invoke(req, res);
1914
+ });
1915
+ });
1916
+ return this;
1917
+ }
1918
+ useAuthorization(authorization) {
1919
+ this.router.setAuthorizeMiddleware(authorization);
1920
+ return this;
1921
+ }
1922
+ useSerialization() {
1923
+ return this;
1924
+ }
1925
+ useControllers(controllers) {
1926
+ if (Array.isArray(controllers)) {
1927
+ this.controllers = controllers;
1928
+ controllers.forEach((controller) => {
1929
+ if (!this.controllers.includes(controller)) this.controllers.push(controller);
1930
+ });
1931
+ } else {
1932
+ this.registerControllerAuto = true;
1933
+ if (controllers.path) this.registerControllerPath = controllers.path;
1934
+ }
1935
+ return this;
1936
+ }
1937
+ useStaticFiles(options) {
1938
+ this.app.register(requireStatic(), options);
1939
+ return this;
1940
+ }
1941
+ useHttps(options) {
1942
+ return this;
1943
+ }
1944
+ useGlobal(options) {
1945
+ if (options.cors) this.useCors(options.cors);
1946
+ if (options.openApi) this.useOpenApi(options.openApi);
1947
+ if (options.controllers) this.useControllers(options.controllers);
1948
+ if (options.middlewares) this.useMiddlewares(options.middlewares);
1949
+ if (options.authorization) this.useAuthorization(options.authorization);
1950
+ if (options.multipart) this.useMultipart(options.multipart);
1951
+ if (options.staticFiles) this.useStaticFiles(options.staticFiles);
1952
+ return this;
1953
+ }
1954
+ useSocketIo(options) {
1955
+ this._hasWebsocket = true;
1956
+ this.app.register(requireSocketIo(), options);
1957
+ return this;
1958
+ }
1959
+ useKnex(options) {
1960
+ try {
1961
+ const { DB } = (init_kenx_provider(), require_chunk.__toCommonJS(kenx_provider_exports));
1962
+ typedi.default.get(DB).init(options.config ?? options);
1963
+ } catch (e) {
1964
+ if (e.message?.includes("knex")) throw e;
1965
+ throw new Error("[Avleon] Failed to initialize Knex. Make sure knex and a database driver are installed.\nRun: npm install knex pg (or mysql2, sqlite3, etc.)");
1966
+ }
1967
+ return this;
1968
+ }
1969
+ mapFeatures() {
1970
+ this.isMapFeatures = true;
1971
+ return this;
1972
+ }
1973
+ isDevelopment() {
1974
+ return process.env.NODE_ENV === "development" || !process.env.NODE_ENV;
1975
+ }
1976
+ async _mapControllers() {
1977
+ const safeControllers = (this.controllers ?? []).filter((c) => c != null && typeof c === "function");
1978
+ if (safeControllers.length > 0) for (const controller of safeControllers) if (isApiController(controller)) await this.router.buildController(controller);
1979
+ else throw new SystemUseError("Not an API controller.");
1980
+ }
1981
+ _resolveControllerDir(dir) {
1982
+ const isTsNode = process.env.TS_NODE_DEV || process.env.TS_NODE_PROJECT || process[Symbol.for("ts-node.register.instance")];
1983
+ const controllerDir = node_path.default.join(process.cwd(), this.registerControllerPath);
1984
+ return isTsNode ? controllerDir : controllerDir.replace("src", "dist");
1985
+ }
1986
+ async autoControllers(controllersPath) {
1987
+ const conDir = this._resolveControllerDir(controllersPath);
1988
+ const isTsNode = process.env.TS_NODE_DEV || process.env.TS_NODE_PROJECT || process[Symbol.for("ts-node.register.instance")];
1989
+ try {
1990
+ const files = node_fs.default.readdirSync(conDir, {
1991
+ recursive: true,
1992
+ encoding: "utf-8"
1993
+ });
1994
+ for (const file of files) {
1995
+ if (/\.(test|spec|e2e-spec)\.(ts|js)$/.test(file)) continue;
1996
+ if (isTsNode ? file.endsWith(".ts") : file.endsWith(".js")) {
1997
+ const module = await import(node_path.default.join(conDir, file));
1998
+ for (const exported of Object.values(module)) if (typeof exported === "function" && isApiController(exported)) {
1999
+ if (!this.controllers.some((con) => exported.name === con.name)) this.controllers.push(exported);
2000
+ }
2001
+ }
2002
+ }
2003
+ } catch (e) {
2004
+ console.warn("Could not auto-register controllers from " + conDir, e);
2005
+ }
2006
+ }
2007
+ _mapFeatures() {
2008
+ try {
2009
+ typedi.default.get("features");
2010
+ } catch {}
2011
+ }
2012
+ async initializeDatabase() {
2013
+ if (this.dataSourceOptions && this.dataSource) await this.dataSource.initialize();
2014
+ }
2015
+ handleSocket(socket) {
2016
+ try {
2017
+ const { SocketContextService } = (init_event_dispatcher(), require_chunk.__toCommonJS(event_dispatcher_exports));
2018
+ const { EventSubscriberRegistry } = (init_event_subscriber(), require_chunk.__toCommonJS(event_subscriber_exports));
2019
+ const { SocketIoServer } = (init_websocket(), require_chunk.__toCommonJS(websocket_exports));
2020
+ const contextService = typedi.default.get(SocketContextService);
2021
+ typedi.default.get(EventSubscriberRegistry).register(socket);
2022
+ const originalOn = socket.on.bind(socket);
2023
+ socket.on = (event, handler) => {
2024
+ return originalOn(event, (...args) => {
2025
+ contextService.run(socket, () => handler(...args));
2026
+ });
2027
+ };
2028
+ } catch (e) {
2029
+ console.warn("[Avleon] Socket handler error:", e);
2030
+ }
2031
+ }
2032
+ mapGet(path = "", fn) {
2033
+ return this.router.mapGet(path, fn);
2034
+ }
2035
+ mapPost(path = "", fn) {
2036
+ return this.router.mapPost(path, fn);
2037
+ }
2038
+ mapPut(path = "", fn) {
2039
+ return this.router.mapPut(path, fn);
2040
+ }
2041
+ mapDelete(path = "", fn) {
2042
+ return this.router.mapDelete(path, fn);
2043
+ }
2044
+ async run(port = 4e3, fn) {
2045
+ if (this.alreadyRun) throw new SystemUseError("App already running");
2046
+ this.alreadyRun = true;
2047
+ if (this.hasSwagger) await this.initSwagger(this.globalSwaggerOptions);
2048
+ await this.initializeDatabase();
2049
+ if (this.isMapFeatures) this._mapFeatures();
2050
+ if (this.registerControllerAuto) await this.autoControllers();
2051
+ await this._mapControllers();
2052
+ this.router.processFunctionalRoutes();
2053
+ this.app.setErrorHandler((error, request, reply) => {
2054
+ const isDev = process.env.NODE_ENV === "development";
2055
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
2056
+ const requestInfo = `${request.method} ${request.url}`;
2057
+ if (error.statusCode === 400 || error.validation) {
2058
+ console.warn(`[${timestamp}] HTTP 400 ${requestInfo} — ${error.message}`);
2059
+ return reply.status(400).send({
2060
+ code: 400,
2061
+ status: "Error",
2062
+ message: error.message,
2063
+ errors: error.validation ?? void 0
2064
+ });
2065
+ }
2066
+ if (error instanceof BaseHttpException) {
2067
+ console.warn(`[${timestamp}] HTTP ${error.code} ${requestInfo} — ${error.message}`);
2068
+ return reply.status(error.code || 500).type("application/json").serializer((payload) => JSON.stringify(payload)).send({
2069
+ code: error.code,
2070
+ status: "Error",
2071
+ message: error.message,
2072
+ data: error.payload
2073
+ });
2074
+ }
2075
+ console.error(`\n❌ UNHANDLED ERROR @ ${timestamp}`);
2076
+ console.error(` ${requestInfo}`);
2077
+ console.error(` ${error.name}: ${error.message}`);
2078
+ if (error.stack) console.error(` Stack:\n${error.stack.split("\n").slice(1).map((l) => ` ${l.trim()}`).join("\n")}`);
2079
+ if (isDev) {
2080
+ console.error(` Params:`, JSON.stringify(request.params));
2081
+ console.error(` Query: `, JSON.stringify(request.query));
2082
+ console.error(` Body: `, JSON.stringify(request.body));
2083
+ }
2084
+ console.error("");
2085
+ return reply.status(500).send({
2086
+ code: 500,
2087
+ status: "Error",
2088
+ message: isDev ? error.message : "Internal Server Error",
2089
+ ...isDev && {
2090
+ error: error.name,
2091
+ stack: error.stack?.split("\n").slice(0, 5)
2092
+ }
2093
+ });
2094
+ });
2095
+ await this.app.ready();
2096
+ if (this._hasWebsocket) {
2097
+ if (!this.app.io) throw new Error("Socket.IO not initialized. Make sure fastify-socket.io is registered correctly.");
2098
+ try {
2099
+ const { SocketIoServer } = (init_websocket(), require_chunk.__toCommonJS(websocket_exports));
2100
+ typedi.default.set(SocketIoServer, this.app.io);
2101
+ await this.app.io.on("connection", this.handleSocket.bind(this));
2102
+ } catch (e) {
2103
+ console.warn("[Avleon] WebSocket setup error:", e);
2104
+ }
2105
+ }
2106
+ await this.app.listen({ port });
2107
+ console.log(`Application running on http://127.0.0.1:${port}`);
2108
+ if (fn) fn();
2109
+ }
2110
+ };
2111
+ //#endregion
2112
+ //#region src/core/testing.ts
2113
+ /**
2114
+ * @copyright 2024
2115
+ * @author Tareq Hossain
2116
+ * @email xtrinsic96@gmail.com
2117
+ * @url https://github.com/xtareq
2118
+ */
2119
+ init_exceptions();
2120
+ init_system_exception();
2121
+ var AvleonTest = class AvleonTest {
2122
+ constructor() {
2123
+ process.env.NODE_ENV = "test";
2124
+ }
2125
+ static getController(controller, deps = []) {
2126
+ const paramTypes = Reflect.getMetadata("design:paramtypes", controller) || [];
2127
+ deps.forEach((dep, i) => {
2128
+ typedi.default.set(paramTypes[i], dep);
2129
+ });
2130
+ return typedi.default.get(controller);
2131
+ }
2132
+ static getProvider(service, deps = []) {
2133
+ const paramTypes = Reflect.getMetadata("design:paramtypes", service) || [];
2134
+ deps.forEach((dep, i) => {
2135
+ typedi.default.set(paramTypes[i], dep);
2136
+ });
2137
+ return typedi.default.get(service);
2138
+ }
2139
+ static createTestApplication(options) {
2140
+ const app = AvleonApplication.getInternalApp({ dataSourceOptions: options.dataSource ? options.dataSource : void 0 });
2141
+ if (options.controllers) app.useControllers(options.controllers);
2142
+ return AvleonTest.from(app);
2143
+ }
2144
+ static from(app) {
2145
+ try {
2146
+ app._mapControllers().catch((e) => console.error(e));
2147
+ app.app.setErrorHandler(async (error, req, res) => {
2148
+ if (error instanceof ValidationErrorException) return res.status(400).send({
2149
+ code: 400,
2150
+ error: "ValidationError",
2151
+ errors: error.message
2152
+ });
2153
+ return res.status(500).send(error);
2154
+ });
2155
+ return {
2156
+ get: async (url, options) => app.app.inject({
2157
+ method: "GET",
2158
+ url,
2159
+ ...options
2160
+ }),
2161
+ post: async (url, options) => app.app.inject({
2162
+ method: "POST",
2163
+ url,
2164
+ ...options
2165
+ }),
2166
+ put: async (url, options) => app.app.inject({
2167
+ method: "PUT",
2168
+ url,
2169
+ ...options
2170
+ }),
2171
+ patch: async (url, options) => app.app.inject({
2172
+ method: "PATCH",
2173
+ url,
2174
+ ...options
2175
+ }),
2176
+ delete: async (url, options) => app.app.inject({
2177
+ method: "DELETE",
2178
+ url,
2179
+ ...options
2180
+ }),
2181
+ options: async (url, options) => app.app.inject({
2182
+ method: "OPTIONS",
2183
+ url,
2184
+ ...options
2185
+ }),
2186
+ getController: (controller, deps = []) => {
2187
+ return AvleonTest.getController(controller, deps);
2188
+ }
2189
+ };
2190
+ } catch (error) {
2191
+ throw new SystemUseError("Can't get test appliction");
2192
+ }
2193
+ }
2194
+ static clean() {
2195
+ typedi.default.reset();
2196
+ }
2197
+ };
2198
+ var Avleon = class {
2199
+ static createApplication() {
2200
+ return AvleonApplication.getApp();
2201
+ }
2202
+ static createTestApplication(options) {
2203
+ return AvleonTest.createTestApplication(options);
2204
+ }
2205
+ };
2206
+ //#endregion
2207
+ //#region src/response.ts
2208
+ /**
2209
+ * @copyright 2024
2210
+ * @author Tareq Hossain
2211
+ * @email xtrinsic96@gmail.com
2212
+ * @url https://github.com/xtareq
2213
+ */
2214
+ var HttpResponse = class {
2215
+ static Ok(obj, s) {
2216
+ if (s) {
2217
+ const isPaginated = obj?.hasOwnProperty("total");
2218
+ const transformedData = (0, class_transformer.plainToInstance)(s, isPaginated ? obj.data : obj, {
2219
+ enableImplicitConversion: true,
2220
+ excludeExtraneousValues: true
2221
+ });
2222
+ return {
2223
+ message: "success",
2224
+ ...isPaginated ? {
2225
+ ...obj,
2226
+ data: (0, class_transformer.instanceToPlain)(transformedData)
2227
+ } : { data: (0, class_transformer.instanceToPlain)(transformedData) }
2228
+ };
2229
+ }
2230
+ return {
2231
+ message: "success",
2232
+ data: obj
2233
+ };
2234
+ }
2235
+ static Created(obj, s) {
2236
+ if (s) return {
2237
+ message: "created",
2238
+ data: (0, class_transformer.instanceToPlain)((0, class_transformer.plainToInstance)(s, obj, {
2239
+ enableImplicitConversion: true,
2240
+ excludeExtraneousValues: true
2241
+ }))
2242
+ };
2243
+ return {
2244
+ message: "created",
2245
+ data: obj
2246
+ };
2247
+ }
2248
+ static NoContent() {
2249
+ return {
2250
+ message: "no content",
2251
+ data: null
2252
+ };
2253
+ }
2254
+ };
2255
+ //#endregion
2256
+ //#region src/middleware.ts
2257
+ /**
2258
+ * @copyright 2024
2259
+ * @author Tareq Hossain
2260
+ * @email xtrinsic96@gmail.com
2261
+ * @url https://github.com/xtareq
2262
+ */
2263
+ init_container();
2264
+ var AvleonMiddleware = class {};
2265
+ var AuthorizeMiddleware = class {};
2266
+ function CanAuthorize(target) {
2267
+ if (typeof target.prototype.authorize !== "function") throw new Error(`Class "${target.name}" must implement an "authorize" method.`);
2268
+ (0, typedi.Service)()(target);
2269
+ }
2270
+ function AppAuthorization(target) {
2271
+ if (typeof target.prototype.authorize !== "function") throw new Error(`Class "${target.name}" must implement an "authorize" method.`);
2272
+ (0, typedi.Service)()(target);
2273
+ }
2274
+ function Authorized(options = {}) {
2275
+ return function(target, propertyKey, descriptor) {
2276
+ if (propertyKey && descriptor) Reflect.defineMetadata(AUTHORIZATION_META_KEY, {
2277
+ authorize: true,
2278
+ options
2279
+ }, target.constructor, propertyKey);
2280
+ else Reflect.defineMetadata(AUTHORIZATION_META_KEY, {
2281
+ authorize: true,
2282
+ options
2283
+ }, target);
2284
+ };
2285
+ }
2286
+ function AppMiddleware(target) {
2287
+ if (typeof target.prototype.invoke !== "function") throw new Error(`Class "${target.name}" must implement an "invoke" method.`);
2288
+ (0, typedi.Service)()(target);
2289
+ }
2290
+ /**
2291
+ * A decorator function that applies one or more middleware to a class or a method.
2292
+ *
2293
+ * When applied to a class, the middleware are registered for the entire controller.
2294
+ * When applied to a method, the middleware are registered for that specific route.
2295
+ *
2296
+ * @param options - A single middleware instance/class or an array of middleware instances/classes to be applied.
2297
+ * @returns A decorator that registers the middleware metadata.
2298
+ */
2299
+ function UseMiddleware(options) {
2300
+ return function(target, propertyKey, descriptor) {
2301
+ const normalizeMiddleware = (middleware) => typeof middleware === "function" ? new middleware() : middleware;
2302
+ const middlewareList = (Array.isArray(options) ? options : [options]).map(normalizeMiddleware);
2303
+ if (typeof target === "function" && !propertyKey) {
2304
+ const existingMiddlewares = Reflect.getMetadata("controller:middleware", target) || [];
2305
+ Reflect.defineMetadata("controller:middleware", [...existingMiddlewares, ...middlewareList], target);
2306
+ } else if (descriptor) {
2307
+ const existingMiddlewares = Reflect.getMetadata("route:middleware", target, propertyKey) || [];
2308
+ Reflect.defineMetadata("route:middleware", [...existingMiddlewares, ...middlewareList], target, propertyKey);
2309
+ }
2310
+ };
2311
+ }
2312
+ //#endregion
2313
+ //#region src/collection.ts
2314
+ /**
2315
+ * @copyright 2024
2316
+ * @author Tareq Hossain
2317
+ * @email xtrinsic96@gmail.com
2318
+ * @url https://github.com/xtareq
2319
+ */
2320
+ init_exceptions();
2321
+ var BasicCollectionImpl = class BasicCollectionImpl {
2322
+ items;
2323
+ constructor(items) {
2324
+ this.items = items;
2325
+ }
2326
+ static from(items) {
2327
+ return new BasicCollectionImpl(items);
2328
+ }
2329
+ clear() {
2330
+ this.items = [];
2331
+ }
2332
+ find(predicate) {
2333
+ if (this.isFunction(predicate)) return this.items.filter(predicate);
2334
+ return Array.from(this.items);
2335
+ }
2336
+ async findAsync(predicate) {
2337
+ return Array.from(this.items);
2338
+ }
2339
+ _matches(item, where) {
2340
+ if ("$or" in where) return where.$or.some((cond) => this._matches(item, cond));
2341
+ if ("$and" in where) return where.$and.every((cond) => this._matches(item, cond));
2342
+ if ("$not" in where) return !this._matches(item, where.$not);
2343
+ return Object.entries(where).every(([key, condition]) => {
2344
+ const itemValue = item[key];
2345
+ if (condition && typeof condition === "object" && !Array.isArray(condition)) {
2346
+ const op = condition;
2347
+ if ("$in" in op && Array.isArray(op.$in)) return op.$in.includes(itemValue);
2348
+ }
2349
+ return itemValue === condition;
2350
+ });
2351
+ }
2352
+ findOne(predicate) {
2353
+ if (this.isFunction(predicate)) return this.items.find(predicate);
2354
+ const result = this.items.filter((item) => this._matches(item, predicate.where));
2355
+ if (result.length > 0) return result[0];
2356
+ }
2357
+ async findOneAsync(predicate) {
2358
+ if (this.isFunction(predicate)) return this.items.find(predicate);
2359
+ return this.items.find((item) => this._matches(item, predicate.where));
2360
+ }
2361
+ isFunction(value) {
2362
+ return typeof value === "function";
2363
+ }
2364
+ add(item) {
2365
+ this.items.push(item);
2366
+ return this.items[this.items.length - 1];
2367
+ }
2368
+ addAll(items) {
2369
+ this.items.push(...items);
2370
+ }
2371
+ update(predicate, updater) {
2372
+ const item = this.items.find(predicate);
2373
+ if (item) {
2374
+ const index = this.items.indexOf(item);
2375
+ this.items[index] = {
2376
+ ...item,
2377
+ ...updater
2378
+ };
2379
+ } else throw new NotFoundException("Item not found");
2380
+ }
2381
+ updateAll(predicate, updater) {
2382
+ for (let i = 0; i < this.items.length; i++) if (predicate(this.items[i])) this.items[i] = updater(this.items[i]);
2383
+ }
2384
+ delete(predicate) {
2385
+ const index = this.items.findIndex(predicate);
2386
+ if (index !== -1) this.items.splice(index, 1);
2387
+ }
2388
+ deleteAll(predicate) {
2389
+ this.items = this.items.filter((item) => !predicate(item));
2390
+ }
2391
+ max(key) {
2392
+ return Math.max(...this.items.map((item) => item[key]));
2393
+ }
2394
+ min(key) {
2395
+ return Math.max(...this.items.map((item) => item[key]));
2396
+ }
2397
+ sum(key) {
2398
+ return this.items.flatMap((x) => x[key]).reduce((sum, num) => sum + num, 0);
2399
+ }
2400
+ avg(key) {
2401
+ const nums = this.items.flatMap((x) => x[key]);
2402
+ return nums.reduce((sum, num) => sum + num, 0) / nums.length;
2403
+ }
2404
+ paginate(options) {
2405
+ const take = options?.take || 10;
2406
+ const skip = options?.skip || 0;
2407
+ const total = this.items.length;
2408
+ const data = this.items.slice(skip, take);
2409
+ return {
2410
+ total,
2411
+ totalPage: Math.ceil(total / take),
2412
+ next: skip + take < total ? skip + take : null,
2413
+ data
2414
+ };
2415
+ }
2416
+ getDeepValue(item, path) {
2417
+ if (typeof path !== "string") return item[path];
2418
+ return path.split(".").reduce((acc, key) => acc?.[key], item);
2419
+ }
2420
+ };
2421
+ var AsynchronousCollection = class AsynchronousCollection {
2422
+ model;
2423
+ repo;
2424
+ constructor(model) {
2425
+ this.model = model;
2426
+ }
2427
+ static fromRepository(model) {
2428
+ return new AsynchronousCollection(model);
2429
+ }
2430
+ getRepository() {
2431
+ if (!this.repo) {
2432
+ const dataSource = typedi.default.get("idatasource");
2433
+ console.log("datasource", dataSource);
2434
+ const repository = dataSource.getRepository(this.model);
2435
+ this.repo = repository;
2436
+ return repository;
2437
+ }
2438
+ return this.repo;
2439
+ }
2440
+ async paginate(options) {
2441
+ const take = options?.take || 10;
2442
+ const skip = options?.skip || 0;
2443
+ const [data, total] = await this.getRepository().findAndCount({
2444
+ take,
2445
+ skip
2446
+ });
2447
+ return {
2448
+ total,
2449
+ totalPage: Math.ceil(total / take),
2450
+ next: skip + take < total ? skip + take : null,
2451
+ prev: skip + take < total ? skip + take : null,
2452
+ data
2453
+ };
2454
+ }
2455
+ };
2456
+ var Collection = class {
2457
+ constructor() {}
2458
+ static from(items) {
2459
+ return BasicCollectionImpl.from(items);
2460
+ }
2461
+ static fromRepository(entity) {
2462
+ return AsynchronousCollection.fromRepository(entity).getRepository();
2463
+ }
2464
+ };
2465
+ function InjectRepository(model) {
2466
+ return function(object, propertyName, index) {
2467
+ let repo;
2468
+ try {
2469
+ typedi.default.registerHandler({
2470
+ object,
2471
+ propertyName,
2472
+ index,
2473
+ value: (containerInstance) => {
2474
+ repo = containerInstance.get("idatasource").getRepository(model).extend({ paginate: () => {} });
2475
+ repo.paginate = async function(options = {
2476
+ take: 10,
2477
+ skip: 0
2478
+ }) {
2479
+ const [data, total] = await this.findAndCount({
2480
+ take: options.take || 10,
2481
+ skip: options.skip || 0
2482
+ });
2483
+ return {
2484
+ total,
2485
+ totalPage: Math.ceil(total / (options.take || 10)),
2486
+ next: options.skip + options.take < total ? options.skip + options.take : null,
2487
+ data
2488
+ };
2489
+ };
2490
+ return repo;
2491
+ }
2492
+ });
2493
+ } catch (error) {
2494
+ if (error.name && error.name == "ServiceNotFoundError") console.log("Database didn't initialized.");
2495
+ }
2496
+ };
2497
+ }
2498
+ //#endregion
2499
+ //#region src/queue.ts
2500
+ var AvleonQueue = class {
2501
+ queue;
2502
+ handlerFn;
2503
+ constructor(name, adapter, handler) {
2504
+ this.name = name;
2505
+ this.adapter = adapter;
2506
+ this.queue = new bull.default(name || "default", adapter);
2507
+ this.handlerFn = handler;
2508
+ if (typeof this.handler === "function" && !this.handlerFn) this.handlerFn = (job) => this.handler(job);
2509
+ if (this.handlerFn) this.queue.process(this.handlerFn);
2510
+ }
2511
+ add(data, options) {
2512
+ return this.queue.add(data, options);
2513
+ }
2514
+ delay(data, delayMs, options) {
2515
+ return this.queue.add(data, {
2516
+ ...options,
2517
+ delay: delayMs
2518
+ });
2519
+ }
2520
+ process(handler) {
2521
+ this.handlerFn = handler;
2522
+ this.queue.process(handler);
2523
+ }
2524
+ processConcurrent(concurrency, handler) {
2525
+ this.handlerFn = handler;
2526
+ this.queue.process(concurrency, handler);
2527
+ }
2528
+ getQueue() {
2529
+ return this.queue;
2530
+ }
2531
+ async clean(grace, status) {
2532
+ return this.queue.clean(grace, status);
2533
+ }
2534
+ async close() {
2535
+ await this.queue.close();
2536
+ }
2537
+ async pause() {
2538
+ await this.queue.pause();
2539
+ }
2540
+ async resume() {
2541
+ await this.queue.resume();
2542
+ }
2543
+ async getJob(jobId) {
2544
+ return this.queue.getJob(jobId);
2545
+ }
2546
+ async getJobs(types, start, end) {
2547
+ return this.queue.getJobs(types, start, end);
2548
+ }
2549
+ };
2550
+ function Queue(config) {
2551
+ return function(target) {
2552
+ const DecoratedClass = class extends target {
2553
+ constructor(...args) {
2554
+ super(config.name, config.adapter, config.handler);
2555
+ }
2556
+ };
2557
+ Object.defineProperty(DecoratedClass, "name", {
2558
+ value: target.name,
2559
+ writable: false
2560
+ });
2561
+ (0, typedi.Service)()(DecoratedClass);
2562
+ return DecoratedClass;
2563
+ };
2564
+ }
2565
+ //#endregion
2566
+ //#region src/file-storage.ts
2567
+ init_system_exception();
2568
+ init_http_exceptions();
2569
+ init_decorateMetadata();
2570
+ init_decorate();
2571
+ let FileStorage = class FileStorage {
2572
+ transformOptions = null;
2573
+ baseDir;
2574
+ maxFileSize = 50 * 1024 * 1024;
2575
+ constructor() {
2576
+ this.baseDir = node_path.default.join(process.cwd(), "public");
2577
+ this.ensureDirectoryExists(this.baseDir);
2578
+ }
2579
+ /**
2580
+ * Set transformation options for the next save operation
2581
+ */
2582
+ transform(options) {
2583
+ this.transformOptions = options;
2584
+ return this;
2585
+ }
2586
+ async getUploadFile(fliePath) {
2587
+ return await node_fs.default.promises.readFile(node_path.default.join(this.baseDir, fliePath));
2588
+ }
2589
+ async download(filepath) {
2590
+ const filename = filepath.toString().split(/[\/\\]/).pop() || "file";
2591
+ return {
2592
+ download: true,
2593
+ stream: (0, node_fs.createReadStream)(filepath),
2594
+ filename
2595
+ };
2596
+ }
2597
+ async downloadAs(filepath, filename) {
2598
+ return {
2599
+ download: true,
2600
+ stream: (0, node_fs.createReadStream)(filepath),
2601
+ filename
2602
+ };
2603
+ }
2604
+ /**
2605
+ * Save a single file with optional transformations
2606
+ */
2607
+ async save(f, options) {
2608
+ const opts = {
2609
+ overwrite: options?.overwrite ?? true,
2610
+ to: options?.to,
2611
+ saveAs: options?.saveAs
2612
+ };
2613
+ if (f.type !== "file") throw new SystemUseError("Invalid file type");
2614
+ try {
2615
+ const filename = opts.saveAs || f.filename;
2616
+ this.validateFilename(filename);
2617
+ const uploadDir = opts.to ? node_path.default.join(this.baseDir, opts.to) : this.baseDir;
2618
+ const fullPath = node_path.default.join(uploadDir, filename);
2619
+ if (!fullPath.startsWith(this.baseDir)) throw new SystemUseError("Invalid file path");
2620
+ if (!opts.overwrite && this.isFileExists(fullPath)) throw new SystemUseError("File already exists");
2621
+ await this.ensureDirectoryExists(uploadDir);
2622
+ let sourceStream;
2623
+ const savedFile = f;
2624
+ if (savedFile.filepath && !f.file) sourceStream = node_fs.default.createReadStream(savedFile.filepath);
2625
+ else if (f.file) sourceStream = f.file;
2626
+ else throw new SystemUseError("No file stream or filepath available");
2627
+ if (this.transformOptions && this.isImageFile(filename)) await this.processImage(sourceStream, fullPath);
2628
+ else await (0, node_stream_promises.pipeline)(sourceStream, node_fs.default.createWriteStream(fullPath));
2629
+ if (savedFile.filepath && node_fs.default.existsSync(savedFile.filepath)) this.removeFileSync(savedFile.filepath);
2630
+ if (opts.saveAs) f.filename = opts.saveAs;
2631
+ return {
2632
+ uploadPath: options?.to ? "/uploads/" + options.to + "/" + f.filename : "/uploads/" + f.filename,
2633
+ staticPath: options?.to ? "/static/" + options.to + "/" + f.filename : "/static/" + f.filename
2634
+ };
2635
+ } catch (err) {
2636
+ if (err instanceof SystemUseError || err instanceof InternalErrorException) throw err;
2637
+ console.error("File save error:", err);
2638
+ throw new SystemUseError("Failed to upload file");
2639
+ }
2640
+ }
2641
+ /**
2642
+ * Save multiple files
2643
+ */
2644
+ async saveAll(files, options) {
2645
+ if (!files || files.length === 0) return [];
2646
+ const opts = {
2647
+ overwrite: options?.overwrite ?? true,
2648
+ to: options?.to
2649
+ };
2650
+ const uploadDir = opts.to ? node_path.default.join(this.baseDir, opts.to) : this.baseDir;
2651
+ await this.ensureDirectoryExists(uploadDir);
2652
+ const results = [];
2653
+ for (const f of files) try {
2654
+ this.validateFilename(f.filename);
2655
+ const fullPath = node_path.default.join(uploadDir, f.filename);
2656
+ if (!fullPath.startsWith(this.baseDir)) throw new SystemUseError(`Invalid file path for ${f.filename}`);
2657
+ if (!opts.overwrite && this.isFileExists(fullPath)) throw new SystemUseError(`File ${f.filename} already exists`);
2658
+ if (f.file) if (this.transformOptions && this.isImageFile(f.filename)) await this.processImage(f.file, fullPath);
2659
+ else await (0, node_stream_promises.pipeline)(f.file, node_fs.default.createWriteStream(fullPath));
2660
+ else {
2661
+ const fp = f;
2662
+ if (!fp.filepath) throw new SystemUseError(`No filepath for ${f.filename}`);
2663
+ if (this.transformOptions && this.isImageFile(f.filename)) await this.processImage(node_fs.default.createReadStream(fp.filepath), fullPath);
2664
+ else await (0, node_stream_promises.pipeline)(node_fs.default.createReadStream(fp.filepath), node_fs.default.createWriteStream(fullPath));
2665
+ this.removeFileSync(fp.filepath);
2666
+ }
2667
+ results.push({
2668
+ uploadPath: options?.to ? "/uploads/" + options.to + "/" + f.filename : "/uploads/" + f.filename,
2669
+ staticPath: options?.to ? "/static/" + options.to + "/" + f.filename : "/static/" + f.filename
2670
+ });
2671
+ } catch (error) {
2672
+ console.error(`Failed to save file ${f.filename}:`, error);
2673
+ throw new SystemUseError(`Failed to upload file ${f.filename}`);
2674
+ }
2675
+ return results;
2676
+ }
2677
+ /**
2678
+ * Remove a file from storage
2679
+ */
2680
+ async remove(filepath) {
2681
+ const fullPath = node_path.default.join(this.baseDir, filepath);
2682
+ if (!fullPath.startsWith(this.baseDir)) throw new SystemUseError("Invalid file path");
2683
+ if (!this.isFileExists(fullPath)) throw new SystemUseError("File doesn't exist");
2684
+ try {
2685
+ node_fs.default.unlinkSync(fullPath);
2686
+ } catch (error) {
2687
+ console.error("File removal error:", error);
2688
+ throw new SystemUseError("Failed to remove file");
2689
+ }
2690
+ }
2691
+ /**
2692
+ * Process image with transformations using sharp
2693
+ */
2694
+ async processImage(fileStream, outputPath) {
2695
+ try {
2696
+ let sharpPipeline = (await Promise.resolve().then(() => /* @__PURE__ */ require_chunk.__toESM(require("./lib-Bk8hUm06.cjs").default, 1))).default();
2697
+ if (this.transformOptions?.resize) sharpPipeline = sharpPipeline.resize(this.transformOptions.resize.width, this.transformOptions.resize.height, {
2698
+ fit: "inside",
2699
+ withoutEnlargement: true
2700
+ });
2701
+ if (this.transformOptions?.format) {
2702
+ const quality = this.transformOptions.quality || 80;
2703
+ switch (this.transformOptions.format) {
2704
+ case "jpeg":
2705
+ sharpPipeline = sharpPipeline.jpeg({ quality });
2706
+ break;
2707
+ case "png":
2708
+ sharpPipeline = sharpPipeline.png({ quality });
2709
+ break;
2710
+ case "webp":
2711
+ sharpPipeline = sharpPipeline.webp({ quality });
2712
+ break;
2713
+ case "avif":
2714
+ sharpPipeline = sharpPipeline.avif({ quality });
2715
+ break;
2716
+ }
2717
+ }
2718
+ await (0, node_stream_promises.pipeline)(fileStream, sharpPipeline, node_fs.default.createWriteStream(outputPath));
2719
+ } catch (error) {
2720
+ if (error.code === "MODULE_NOT_FOUND" && error.message.includes("sharp")) throw new InternalErrorException("sharp module not found. Please install sharp to use image transformations.");
2721
+ console.error("Image processing failed:", error);
2722
+ throw new InternalErrorException("Image processing failed");
2723
+ } finally {
2724
+ this.transformOptions = null;
2725
+ }
2726
+ }
2727
+ /**
2728
+ * Helper methods
2729
+ */
2730
+ isFileExists(fpath) {
2731
+ return node_fs.default.existsSync(fpath);
2732
+ }
2733
+ async ensureDirectoryExists(dirPath) {
2734
+ if (!node_fs.default.existsSync(dirPath)) node_fs.default.mkdirSync(dirPath, { recursive: true });
2735
+ }
2736
+ removeFileSync(filepath) {
2737
+ try {
2738
+ if (node_fs.default.existsSync(filepath)) node_fs.default.unlinkSync(filepath);
2739
+ } catch (error) {
2740
+ console.error("Failed to remove temp file:", error);
2741
+ }
2742
+ }
2743
+ isImageFile(filename) {
2744
+ const ext = node_path.default.extname(filename).toLowerCase();
2745
+ return [
2746
+ ".jpg",
2747
+ ".jpeg",
2748
+ ".png",
2749
+ ".webp",
2750
+ ".avif",
2751
+ ".gif",
2752
+ ".bmp"
2753
+ ].includes(ext);
2754
+ }
2755
+ validateFilename(filename) {
2756
+ if (!filename || filename.trim() === "") throw new SystemUseError("Invalid filename");
2757
+ if (filename.includes("..") || filename.includes("/") || filename.includes("\\")) throw new SystemUseError("Invalid filename: path traversal detected");
2758
+ if (filename.includes("\0")) throw new SystemUseError("Invalid filename: null byte detected");
2759
+ }
2760
+ };
2761
+ FileStorage = __decorate([AppService, __decorateMetadata("design:paramtypes", [])], FileStorage);
2762
+ //#endregion
2763
+ //#region src/environment-variables.ts
2764
+ /**
2765
+ * @copyright 2024
2766
+ * @author Tareq Hossain
2767
+ * @email xtrinsic96@gmail.com
2768
+ * @url https://github.com/xtareq
2769
+ */
2770
+ init_system_exception();
2771
+ init_decorate();
2772
+ dotenv.default.config({
2773
+ path: node_path.default.join(process.cwd(), ".env"),
2774
+ quiet: true
2775
+ });
2776
+ let Environment = class Environment {
2777
+ /**
2778
+ * Parses the given `.env` file and merges it with `process.env`.
2779
+ * Values from `process.env` take precedence.
2780
+ *
2781
+ * @private
2782
+ * @param filePath - Absolute path to the `.env` file.
2783
+ * @returns A dictionary of merged environment variables.
2784
+ */
2785
+ parseEnvFile(filePath) {
2786
+ try {
2787
+ if (!(0, node_fs.existsSync)(filePath)) return { ...process.env };
2788
+ const fileContent = node_fs.default.readFileSync(filePath, "utf8");
2789
+ return {
2790
+ ...dotenv.default.parse(fileContent),
2791
+ ...process.env
2792
+ };
2793
+ } catch (error) {
2794
+ console.error(`Error parsing .env file: ${error}`);
2795
+ return {};
2796
+ }
2797
+ }
2798
+ /**
2799
+ * Retrieves the value of the specified environment variable.
2800
+ *
2801
+ * @template T
2802
+ * @param key - The name of the environment variable.
2803
+ * @returns The value of the variable, or `undefined` if not found.
2804
+ */
2805
+ get(key) {
2806
+ return this.parseEnvFile(node_path.default.join(process.cwd(), ".env"))[key];
2807
+ }
2808
+ /**
2809
+ * Retrieves the value of the specified environment variable.
2810
+ * Throws an error if the variable is not found.
2811
+ *
2812
+ * @template T
2813
+ * @param key - The name of the environment variable.
2814
+ * @throws {EnvironmentVariableNotFound} If the variable does not exist.
2815
+ * @returns The value of the variable.
2816
+ */
2817
+ getOrThrow(key) {
2818
+ const parsedEnv = this.parseEnvFile(node_path.default.join(process.cwd(), ".env"));
2819
+ if (!Object(parsedEnv).hasOwnProperty(key)) throw new EnvironmentVariableNotFound(key);
2820
+ return parsedEnv[key];
2821
+ }
2822
+ /**
2823
+ * Retrieves all available environment variables,
2824
+ * with `process.env` values taking precedence over `.env` values.
2825
+ *
2826
+ * @template T
2827
+ * @returns An object containing all environment variables.
2828
+ */
2829
+ getAll() {
2830
+ return this.parseEnvFile(node_path.default.join(process.cwd(), ".env"));
2831
+ }
2832
+ };
2833
+ Environment = __decorate([(0, typedi.Service)()], Environment);
2834
+ //#endregion
2835
+ //#region src/config.ts
2836
+ /**
2837
+ * @copyright 2024
2838
+ * @author Tareq Hossain
2839
+ * @email xtrinsic96@gmail.com
2840
+ * @url https://github.com/xtareq
2841
+ */
2842
+ init_helpers();
2843
+ function AppConfig(target) {
2844
+ typedi.Container.set({
2845
+ id: target,
2846
+ type: target
2847
+ });
2848
+ }
2849
+ var AvleonConfig = class {
2850
+ get(configClass) {
2851
+ const instance = typedi.Container.get(configClass);
2852
+ if (!instance) throw new Error(`Configuration for ${configClass.name} not found.`);
2853
+ return instance.config(new Environment());
2854
+ }
2855
+ };
2856
+ function GetConfig(token) {
2857
+ if (typeof token === "function" && token.prototype != null && typeof token.prototype.config === "function") {
2858
+ const instance = typedi.Container.get(token);
2859
+ if (!instance) throw new Error(`Class "${token.name}" is not registered as a config.`);
2860
+ return instance.config(inject(Environment));
2861
+ }
2862
+ const stored = typedi.Container.get(token);
2863
+ if (!stored) throw new Error("Config object is not registered.");
2864
+ return stored;
2865
+ }
2866
+ function CreateConfig(token, callback) {
2867
+ let env;
2868
+ try {
2869
+ env = typedi.Container.get(Environment);
2870
+ } catch (error) {
2871
+ env = new Environment();
2872
+ }
2873
+ let config = callback(env);
2874
+ typedi.Container.set(token, config);
2875
+ }
2876
+ //#endregion
2877
+ //#region src/logger.ts
2878
+ init_decorateMetadata();
2879
+ init_decorate();
2880
+ let LoggerService = class LoggerService {
2881
+ logger;
2882
+ constructor() {
2883
+ this.logger = (0, pino.default)({
2884
+ level: process.env.LOG_LEVEL || "info",
2885
+ transport: {
2886
+ target: "pino-pretty",
2887
+ options: {
2888
+ translateTime: "SYS:standard",
2889
+ ignore: "pid,hostname"
2890
+ }
2891
+ }
2892
+ });
2893
+ }
2894
+ getLogger() {
2895
+ return this.logger;
2896
+ }
2897
+ info(message, obj) {
2898
+ if (obj) this.logger.info(obj, message);
2899
+ else this.logger.info(message);
2900
+ }
2901
+ error(message, obj) {
2902
+ if (obj) this.logger.error(obj, message);
2903
+ else this.logger.error(message);
2904
+ }
2905
+ warn(message, obj) {
2906
+ if (obj) this.logger.warn(obj, message);
2907
+ else this.logger.warn(message);
2908
+ }
2909
+ debug(message, obj) {
2910
+ if (obj) this.logger.debug(obj, message);
2911
+ else this.logger.debug(message);
2912
+ }
2913
+ fatal(message, obj) {
2914
+ if (obj) this.logger.fatal(obj, message);
2915
+ else this.logger.fatal(message);
2916
+ }
2917
+ trace(message, obj) {
2918
+ if (obj) this.logger.trace(obj, message);
2919
+ else this.logger.trace(message);
2920
+ }
2921
+ };
2922
+ LoggerService = __decorate([AppService, __decorateMetadata("design:paramtypes", [])], LoggerService);
2923
+ //#endregion
2924
+ //#region src/cache.ts
2925
+ var CacheManager = class {
2926
+ store = /* @__PURE__ */ new Map();
2927
+ tagsMap = /* @__PURE__ */ new Map();
2928
+ redis = null;
2929
+ constructor(redisInstance) {
2930
+ this.redis = redisInstance || null;
2931
+ }
2932
+ redisTagKey(tag) {
2933
+ return `cache-tags:${tag}`;
2934
+ }
2935
+ async get(key) {
2936
+ if (this.redis) {
2937
+ const val = await this.redis.get(key);
2938
+ return val ? JSON.parse(val) : null;
2939
+ }
2940
+ const cached = this.store.get(key);
2941
+ return cached ? cached.data : null;
2942
+ }
2943
+ async set(key, value, tags = [], ttl = 3600) {
2944
+ const entry = {
2945
+ data: value,
2946
+ timestamp: Date.now()
2947
+ };
2948
+ if (this.redis) {
2949
+ await this.redis.set(key, JSON.stringify(entry.data), "EX", ttl);
2950
+ for (const tag of tags) await this.redis.sadd(this.redisTagKey(tag), key);
2951
+ } else {
2952
+ this.store.set(key, entry);
2953
+ for (const tag of tags) {
2954
+ if (!this.tagsMap.has(tag)) this.tagsMap.set(tag, /* @__PURE__ */ new Set());
2955
+ this.tagsMap.get(tag).add(key);
2956
+ }
2957
+ }
2958
+ }
2959
+ async delete(key) {
2960
+ if (this.redis) {
2961
+ await this.redis.del(key);
2962
+ const tagKeys = await this.redis.keys("cache-tags:*");
2963
+ for (const tagKey of tagKeys) await this.redis.srem(tagKey, key);
2964
+ } else {
2965
+ this.store.delete(key);
2966
+ for (const keys of this.tagsMap.values()) keys.delete(key);
2967
+ }
2968
+ }
2969
+ async invalidateTag(tag) {
2970
+ if (this.redis) {
2971
+ const tagKey = this.redisTagKey(tag);
2972
+ const keys = await this.redis.smembers(tagKey);
2973
+ if (keys.length) {
2974
+ await this.redis.del(...keys);
2975
+ await this.redis.del(tagKey);
2976
+ }
2977
+ } else {
2978
+ const keys = this.tagsMap.get(tag);
2979
+ if (keys) {
2980
+ for (const key of keys) this.store.delete(key);
2981
+ this.tagsMap.delete(tag);
2982
+ }
2983
+ }
2984
+ }
2985
+ };
2986
+ //#endregion
2987
+ //#region src/results.ts
2988
+ var Results = class {
2989
+ static code = 500;
2990
+ message = "Something going wrong";
2991
+ static Ok(data) {
2992
+ return new Ok(data);
2993
+ }
2994
+ static NoContent() {
2995
+ this.code = 204;
2996
+ }
2997
+ static OkStream() {}
2998
+ static NotFound(message) {
2999
+ return new NotFound(message);
3000
+ }
3001
+ };
3002
+ var Ok = class {
3003
+ constructor(data) {
3004
+ this.data = data;
3005
+ }
3006
+ };
3007
+ var NotFound = class {
3008
+ constructor(message) {
3009
+ this.message = message;
3010
+ }
3011
+ };
3012
+ //#endregion
3013
+ //#region src/index.ts
3014
+ /**
3015
+ * @copyright 2024
3016
+ * @author Tareq Hossain
3017
+ * @email xtrinsic96@gmail.com
3018
+ * @url https://github.com/xtareq
3019
+ */
3020
+ init_helpers();
3021
+ init_exceptions();
3022
+ init_container();
3023
+ init_kenx_provider();
3024
+ init_event_dispatcher();
3025
+ init_event_subscriber();
3026
+ init_container();
3027
+ const GetSchema = generateSwaggerSchema;
3028
+ const GetObjectSchema = CreateSwaggerObjectSchema;
3029
+ const OpenApiOk = (args1) => {
3030
+ return OpenApiResponse$1(200, args1, "Success");
3031
+ };
3032
+ const OpenApiResponse = OpenApiResponse$1;
3033
+ const OpenApiProperty = OpenApiProperty$1;
3034
+ //#endregion
3035
+ exports.API_CONTROLLER_METADATA_KEY = API_CONTROLLER_METADATA_KEY;
3036
+ exports.AUTHORIZATION_META_KEY = AUTHORIZATION_META_KEY;
3037
+ exports.All = All;
3038
+ exports.ApiController = ApiController;
3039
+ exports.AppAuthorization = AppAuthorization;
3040
+ exports.AppConfig = AppConfig;
3041
+ exports.AppMiddleware = AppMiddleware;
3042
+ exports.AppService = AppService;
3043
+ exports.AuthUser = AuthUser;
3044
+ exports.AuthorizeMiddleware = AuthorizeMiddleware;
3045
+ exports.Authorized = Authorized;
3046
+ exports.Avleon = Avleon;
3047
+ exports.AvleonApplication = AvleonApplication;
3048
+ exports.AvleonConfig = AvleonConfig;
3049
+ exports.AvleonContainer = Container;
3050
+ exports.AvleonMiddleware = AvleonMiddleware;
3051
+ exports.AvleonQueue = AvleonQueue;
3052
+ exports.AvleonRequest = AvleonRequest;
3053
+ exports.AvleonTest = AvleonTest;
3054
+ exports.BadRequestException = BadRequestException;
3055
+ exports.BaseHttpException = BaseHttpException;
3056
+ exports.Body = Body;
3057
+ exports.CONTROLLER_META_KEY = CONTROLLER_META_KEY;
3058
+ exports.CacheManager = CacheManager;
3059
+ exports.CanAuthorize = CanAuthorize;
3060
+ exports.Collection = Collection;
3061
+ exports.CreateConfig = CreateConfig;
3062
+ exports.CreateSwaggerObjectSchema = CreateSwaggerObjectSchema;
3063
+ exports.DATASOURCE_META_KEY = DATASOURCE_META_KEY;
3064
+ Object.defineProperty(exports, "DB", {
3065
+ enumerable: true,
3066
+ get: function() {
3067
+ return DB;
3068
+ }
3069
+ });
3070
+ exports.Delete = Delete;
3071
+ exports.Dispatch = Dispatch;
3072
+ Object.defineProperty(exports, "Environment", {
3073
+ enumerable: true,
3074
+ get: function() {
3075
+ return Environment;
3076
+ }
3077
+ });
3078
+ Object.defineProperty(exports, "EventDispatcher", {
3079
+ enumerable: true,
3080
+ get: function() {
3081
+ return EventDispatcher;
3082
+ }
3083
+ });
3084
+ Object.defineProperty(exports, "EventSubscriberRegistry", {
3085
+ enumerable: true,
3086
+ get: function() {
3087
+ return EventSubscriberRegistry;
3088
+ }
3089
+ });
3090
+ exports.FEATURE_KEY = FEATURE_KEY;
3091
+ Object.defineProperty(exports, "FileStorage", {
3092
+ enumerable: true,
3093
+ get: function() {
3094
+ return FileStorage;
3095
+ }
3096
+ });
3097
+ exports.ForbiddenException = ForbiddenException;
3098
+ exports.Get = Get;
3099
+ exports.GetConfig = GetConfig;
3100
+ exports.GetObjectSchema = GetObjectSchema;
3101
+ exports.GetSchema = GetSchema;
3102
+ exports.Header = Header;
3103
+ exports.Helper = Helper;
3104
+ exports.HttpExceptions = HttpExceptions;
3105
+ exports.HttpResponse = HttpResponse;
3106
+ exports.InjectRepository = InjectRepository;
3107
+ exports.InternalErrorException = InternalErrorException;
3108
+ Object.defineProperty(exports, "LoggerService", {
3109
+ enumerable: true,
3110
+ get: function() {
3111
+ return LoggerService;
3112
+ }
3113
+ });
3114
+ exports.NotFound = NotFound;
3115
+ exports.NotFoundException = NotFoundException;
3116
+ exports.Ok = Ok;
3117
+ exports.OpenApi = OpenApi;
3118
+ exports.OpenApiOk = OpenApiOk;
3119
+ exports.OpenApiProperty = OpenApiProperty;
3120
+ exports.OpenApiResponse = OpenApiResponse;
3121
+ exports.OpenApiSchema = OpenApiSchema;
3122
+ exports.Options = Options;
3123
+ exports.PARAM_META_KEY = PARAM_META_KEY;
3124
+ exports.Param = Param;
3125
+ exports.Patch = Patch;
3126
+ exports.Post = Post;
3127
+ exports.Private = Private;
3128
+ exports.Put = Put;
3129
+ exports.QUERY_META_KEY = QUERY_META_KEY;
3130
+ exports.Query = Query;
3131
+ exports.Queue = Queue;
3132
+ exports.REQUEST_BODY_FILES_KEY = REQUEST_BODY_FILES_KEY;
3133
+ exports.REQUEST_BODY_FILE_KEY = REQUEST_BODY_FILE_KEY;
3134
+ exports.REQUEST_BODY_META_KEY = REQUEST_BODY_META_KEY;
3135
+ exports.REQUEST_HEADER_META_KEY = REQUEST_HEADER_META_KEY;
3136
+ exports.REQUEST_METADATA_KEY = REQUEST_METADATA_KEY;
3137
+ exports.REQUEST_USER_META_KEY = REQUEST_USER_META_KEY;
3138
+ exports.ROUTE_META_KEY = ROUTE_META_KEY;
3139
+ exports.Results = Results;
3140
+ exports.Route = Route;
3141
+ Object.defineProperty(exports, "SocketContextService", {
3142
+ enumerable: true,
3143
+ get: function() {
3144
+ return SocketContextService;
3145
+ }
3146
+ });
3147
+ exports.Subscribe = Subscribe;
3148
+ exports.UnauthorizedException = UnauthorizedException;
3149
+ exports.UseMiddleware = UseMiddleware;
3150
+ exports.Utility = Utility;
3151
+ exports.ValidationErrorException = ValidationErrorException;
3152
+ exports.Validator = Validator;
3153
+ exports.autoCast = autoCast;
3154
+ exports.createControllerDecorator = createControllerDecorator;
3155
+ exports.exclude = exclude;
3156
+ exports.extrctParamFromUrl = extrctParamFromUrl;
3157
+ exports.findDuplicates = findDuplicates;
3158
+ exports.formatUrl = formatUrl;
3159
+ exports.generateClassSchema = generateClassSchema;
3160
+ exports.generateSwaggerSchema = generateSwaggerSchema;
3161
+ exports.getDataType = getDataType;
3162
+ exports.getLineNumber = getLineNumber;
3163
+ exports.getPrivateChannelResolver = getPrivateChannelResolver;
3164
+ exports.getRegisteredControllers = getRegisteredControllers;
3165
+ exports.getRegisteredServices = getRegisteredServices;
3166
+ exports.getSocketSubscribers = getSocketSubscribers;
3167
+ exports.inject = inject;
3168
+ exports.isApiController = isApiController;
3169
+ exports.isClassValidator = isClassValidator;
3170
+ exports.isClassValidatorClass = isClassValidatorClass;
3171
+ exports.isConstructor = isConstructor;
3172
+ exports.isPrivate = isPrivate;
3173
+ exports.isValidJsonString = isValidJsonString;
3174
+ exports.isValidType = isValidType;
3175
+ exports.jsonToInstance = jsonToInstance;
3176
+ exports.jsonToJs = jsonToJs;
3177
+ exports.normalizeParamsToJsonSchema = normalizeParamsToJsonSchema;
3178
+ exports.normalizePath = normalizePath;
3179
+ exports.normalizeQueryDeep = normalizeQueryDeep;
3180
+ exports.parsedPath = parsedPath;
3181
+ exports.pick = pick;
3182
+ exports.registerController = registerController;
3183
+ exports.registerDataSource = registerDataSource;
3184
+ exports.registerKnex = registerKnex;
3185
+ exports.registerService = registerService;
3186
+ exports.registerSocketSubscriber = registerSocketSubscriber;
3187
+ exports.sleep = sleep;
3188
+ exports.transformObjectByInstanceToObject = transformObjectByInstanceToObject;
3189
+ exports.uuid = uuid;
3190
+ exports.validateObjectByInstance = validateObjectByInstance;
3191
+ exports.validateOrThrow = validateOrThrow;
3192
+ exports.validateRequestBody = validateRequestBody;
3193
+
3194
+ //# sourceMappingURL=index.cjs.map