@avleon/core 0.0.19 → 0.0.24

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 (72) hide show
  1. package/README.md +559 -2
  2. package/dist/application.d.ts +26 -0
  3. package/dist/application.js +50 -0
  4. package/dist/collection.js +3 -2
  5. package/dist/container.d.ts +1 -0
  6. package/dist/container.js +2 -1
  7. package/dist/environment-variables.js +1 -1
  8. package/dist/file-storage.js +0 -128
  9. package/dist/helpers.d.ts +2 -0
  10. package/dist/helpers.js +41 -4
  11. package/dist/icore.d.ts +68 -26
  12. package/dist/icore.js +235 -212
  13. package/dist/index.d.ts +2 -2
  14. package/dist/index.js +4 -2
  15. package/dist/middleware.js +0 -8
  16. package/dist/multipart.js +4 -1
  17. package/dist/openapi.d.ts +37 -37
  18. package/dist/params.js +2 -2
  19. package/dist/response.js +6 -2
  20. package/dist/route-methods.js +1 -1
  21. package/dist/swagger-schema.js +4 -1
  22. package/dist/testing.js +5 -2
  23. package/dist/utils/index.d.ts +2 -0
  24. package/dist/utils/index.js +18 -0
  25. package/dist/utils/optional-require.d.ts +8 -0
  26. package/dist/utils/optional-require.js +70 -0
  27. package/dist/validation.d.ts +4 -1
  28. package/dist/validation.js +10 -5
  29. package/package.json +19 -11
  30. package/src/application.ts +96 -0
  31. package/src/authentication.ts +16 -0
  32. package/src/collection.ts +254 -0
  33. package/src/config.ts +39 -0
  34. package/src/constants.ts +1 -0
  35. package/src/container.ts +54 -0
  36. package/src/controller.ts +128 -0
  37. package/src/decorators.ts +27 -0
  38. package/src/environment-variables.ts +46 -0
  39. package/src/exceptions/http-exceptions.ts +86 -0
  40. package/src/exceptions/index.ts +1 -0
  41. package/src/exceptions/system-exception.ts +34 -0
  42. package/src/file-storage.ts +206 -0
  43. package/src/helpers.ts +328 -0
  44. package/src/icore.ts +1064 -0
  45. package/src/index.ts +30 -0
  46. package/src/logger.ts +72 -0
  47. package/src/map-types.ts +159 -0
  48. package/src/middleware.ts +98 -0
  49. package/src/multipart.ts +116 -0
  50. package/src/openapi.ts +372 -0
  51. package/src/params.ts +111 -0
  52. package/src/queue.ts +126 -0
  53. package/src/response.ts +117 -0
  54. package/src/results.ts +30 -0
  55. package/src/route-methods.ts +186 -0
  56. package/src/swagger-schema.ts +213 -0
  57. package/src/testing.ts +220 -0
  58. package/src/types/app-builder.interface.ts +19 -0
  59. package/src/types/application.interface.ts +9 -0
  60. package/src/utils/hash.ts +5 -0
  61. package/src/utils/index.ts +2 -0
  62. package/src/utils/optional-require.ts +50 -0
  63. package/src/validation.ts +156 -0
  64. package/src/validator-extend.ts +25 -0
  65. package/dist/classToOpenapi.d.ts +0 -0
  66. package/dist/classToOpenapi.js +0 -1
  67. package/dist/render.d.ts +0 -1
  68. package/dist/render.js +0 -8
  69. package/jest.config.ts +0 -9
  70. package/tsconfig.json +0 -25
  71. /package/dist/{security.d.ts → utils/hash.d.ts} +0 -0
  72. /package/dist/{security.js → utils/hash.js} +0 -0
package/dist/icore.js CHANGED
@@ -32,24 +32,6 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __rest = (this && this.__rest) || function (s, e) {
36
- var t = {};
37
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
38
- t[p] = s[p];
39
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
40
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
41
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
42
- t[p[i]] = s[p[i]];
43
- }
44
- return t;
45
- };
46
- var __asyncValues = (this && this.__asyncValues) || function (o) {
47
- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
48
- var m = o[Symbol.asyncIterator], i;
49
- return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
50
- function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
51
- function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
52
- };
53
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
54
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
55
37
  };
@@ -75,6 +57,8 @@ const config_1 = require("./config");
75
57
  const environment_variables_1 = require("./environment-variables");
76
58
  const cors_1 = __importDefault(require("@fastify/cors"));
77
59
  const multipart_1 = __importDefault(require("@fastify/multipart"));
60
+ const validation_1 = require("./validation");
61
+ const utils_1 = require("./utils");
78
62
  const isTsNode = process.env.TS_NODE_DEV ||
79
63
  process.env.TS_NODE_PROJECT ||
80
64
  process[Symbol.for("ts-node.register.instance")];
@@ -93,12 +77,19 @@ class AvleonApplication {
93
77
  this.controllers = [];
94
78
  this.authorizeMiddleware = undefined;
95
79
  this.dataSource = undefined;
80
+ this.isMapFeatures = false;
96
81
  this.metaCache = new Map();
97
82
  this.app = (0, fastify_1.default)();
98
83
  this.appConfig = new config_1.AppConfig();
99
- // this.app.setValidatorCompiler(() => () => true);
100
84
  }
101
85
  isTest() { }
86
+ static getApp() {
87
+ let isTestEnv = process.env.NODE_ENV == "test";
88
+ if (!AvleonApplication.instance) {
89
+ AvleonApplication.instance = new AvleonApplication();
90
+ }
91
+ return AvleonApplication.instance;
92
+ }
102
93
  static getInternalApp(buildOptions) {
103
94
  let isTestEnv = process.env.NODE_ENV == "test";
104
95
  if (!AvleonApplication.instance) {
@@ -110,7 +101,7 @@ class AvleonApplication {
110
101
  buildOptions.dataSourceOptions;
111
102
  const typeorm = require("typeorm");
112
103
  const datasource = new typeorm.DataSource(buildOptions.dataSourceOptions);
113
- typedi_1.default.set(isTestEnv ? "itestdatasource" : "idatasource", datasource);
104
+ typedi_1.default.set("idatasource", datasource);
114
105
  AvleonApplication.instance.dataSource = datasource;
115
106
  }
116
107
  return AvleonApplication.instance;
@@ -120,13 +111,20 @@ class AvleonApplication {
120
111
  return env.get("NODE_ENV") == "development";
121
112
  }
122
113
  async initSwagger(options) {
123
- const { routePrefix, logo, ui, theme, configuration } = options, restOptions = __rest(options, ["routePrefix", "logo", "ui", "theme", "configuration"]);
114
+ const { routePrefix, logo, ui, theme, configuration, ...restOptions } = options;
124
115
  this.app.register(swagger_1.default, {
125
- openapi: Object.assign({ openapi: "3.0.0" }, restOptions),
116
+ openapi: {
117
+ openapi: "3.0.0",
118
+ ...restOptions,
119
+ },
126
120
  });
127
121
  const rPrefix = routePrefix ? routePrefix : "/docs";
128
122
  if (options.ui && options.ui == "scalar") {
129
- await this.app.register(require("@scalar/fastify-api-reference"), {
123
+ const scalarPlugin = (0, utils_1.optionalRequire)("@scalar/fastify-api-reference", {
124
+ failOnMissing: true,
125
+ customMessage: 'Install "@scalar/fastify-api-reference" to enable API docs.\n\n npm install @scalar/fastify-api-reference',
126
+ });
127
+ await this.app.register(scalarPlugin, {
130
128
  routePrefix: rPrefix,
131
129
  configuration: configuration
132
130
  ? configuration
@@ -141,18 +139,14 @@ class AvleonApplication {
141
139
  });
142
140
  }
143
141
  else {
144
- await this.app.register(require("@fastify/swagger-ui"), {
142
+ const fastifySwaggerUi = (0, utils_1.optionalRequire)("@fastify/swagger-ui", {
143
+ failOnMissing: true,
144
+ customMessage: 'Install "@fastify/swagger-ui" to enable API docs.\n\n npm install @fastify/swagger-ui',
145
+ });
146
+ await this.app.register(fastifySwaggerUi, {
145
147
  logo: logo ? logo : null,
146
148
  theme: theme ? theme : {},
147
149
  routePrefix: rPrefix,
148
- configuration: {
149
- metaData: {
150
- title: "Avleon Api",
151
- ogTitle: "Avleon",
152
- },
153
- theme: "kepler",
154
- favicon: "/static/favicon.png",
155
- },
156
150
  });
157
151
  }
158
152
  }
@@ -171,16 +165,94 @@ class AvleonApplication {
171
165
  this.hasSwagger = true;
172
166
  }
173
167
  /**
174
- * @deprecated
175
- * Will remove in next major version
168
+ * Registers the fastify-multipart plugin with the Fastify instance.
169
+ * This enables handling of multipart/form-data requests, typically used for file uploads.
170
+ *
171
+ * @param {MultipartOptions} options - Options to configure the fastify-multipart plugin.
172
+ * @param {FastifyInstance} this.app - The Fastify instance to register the plugin with.
173
+ * @property {MultipartOptions} this.multipartOptions - Stores the provided multipart options.
174
+ * @see {@link https://github.com/fastify/fastify-multipart} for more details on available options.
176
175
  */
177
- async useSwagger(options) {
178
- this.hasSwagger = true;
179
- this.globalSwaggerOptions = options;
180
- }
181
176
  useMultipart(options) {
182
177
  this.multipartOptions = options;
183
- this.app.register(multipart_1.default, Object.assign(Object.assign({}, this.multipartOptions), { attachFieldsToBody: true }));
178
+ this.app.register(multipart_1.default, {
179
+ ...this.multipartOptions,
180
+ attachFieldsToBody: true,
181
+ });
182
+ }
183
+ /**
184
+ * Configures and initializes a TypeORM DataSource based on the provided configuration class.
185
+ * It retrieves the configuration from the application's configuration service and allows for optional modification.
186
+ * The initialized DataSource is then stored and registered within a dependency injection container.
187
+ *
188
+ * @template T - A generic type extending the `IConfig` interface, representing the configuration class.
189
+ * @template R - A generic type representing the return type of the configuration method of the `ConfigClass`.
190
+ * @param {Constructable<T>} ConfigClass - The constructor of the configuration class to be used for creating the DataSource.
191
+ * @param {(config: R) => R} [modifyConfig] - An optional function that takes the initial configuration and returns a modified configuration.
192
+ * @returns {void}
193
+ * @property {DataSourceOptions} this.dataSourceOptions - Stores the final DataSource options after potential modification.
194
+ * @property {DataSource} this.dataSource - Stores the initialized TypeORM DataSource instance.
195
+ * @see {@link https://typeorm.io/} for more information about TypeORM.
196
+ */
197
+ useDataSource(ConfigClass, modifyConfig) {
198
+ const dsConfig = this.appConfig.get(ConfigClass);
199
+ if (modifyConfig) {
200
+ const modifiedConfig = modifyConfig(dsConfig);
201
+ this.dataSourceOptions = modifiedConfig;
202
+ }
203
+ else {
204
+ this.dataSourceOptions = dsConfig;
205
+ }
206
+ const typeorm = require("typeorm");
207
+ const datasource = new typeorm.DataSource(dsConfig);
208
+ this.dataSource = datasource;
209
+ typedi_1.default.set("idatasource", datasource);
210
+ }
211
+ /**
212
+ * Registers an array of middleware classes to be executed before request handlers.
213
+ * It retrieves instances of the middleware classes from the dependency injection container
214
+ * and adds them as 'preHandler' hooks to the Fastify application.
215
+ *
216
+ * @template T - A generic type extending the `AppMiddleware` interface, representing the middleware class.
217
+ * @param {Constructor<T>[]} mclasses - An array of middleware class constructors to be registered.
218
+ * @returns {void}
219
+ * @property {Map<string, T>} this.middlewares - Stores the registered middleware instances, keyed by their class names.
220
+ * @see {@link https://www.fastify.io/docs/latest/Reference/Hooks/#prehandler} for more information about Fastify preHandler hooks.
221
+ */
222
+ useMiddlewares(mclasses) {
223
+ for (const mclass of mclasses) {
224
+ const cls = typedi_1.default.get(mclass);
225
+ this.middlewares.set(mclass.name, cls);
226
+ this.app.addHook("preHandler", cls.invoke);
227
+ }
228
+ }
229
+ /**
230
+ * Registers a middleware constructor to be used for authorization purposes.
231
+ * The specific implementation and usage of this middleware will depend on the application's authorization logic.
232
+ *
233
+ * @template T - A generic type representing the constructor of the authorization middleware.
234
+ * @param {Constructor<T>} middleware - The constructor of the middleware to be used for authorization.
235
+ * @returns {void}
236
+ * @property {any} this.authorizeMiddleware - Stores the constructor of the authorization middleware.
237
+ */
238
+ useAuthoriztion(middleware) {
239
+ this.authorizeMiddleware = middleware;
240
+ }
241
+ /**
242
+ * Registers the `@fastify/static` plugin to serve static files.
243
+ * It configures the root directory and URL prefix for serving static assets.
244
+ *
245
+ * @param {StaticFileOptions} [options={ path: undefined, prefix: undefined }] - Optional configuration for serving static files.
246
+ * @param {string} [options.path] - The absolute path to the static files directory. Defaults to 'process.cwd()/public'.
247
+ * @param {string} [options.prefix] - The URL prefix for serving static files. Defaults to '/static/'.
248
+ * @returns {void}
249
+ * @see {@link https://github.com/fastify/fastify-static} for more details on available options.
250
+ */
251
+ useStaticFiles(options = { path: undefined, prefix: undefined }) {
252
+ this.app.register(require("@fastify/static"), {
253
+ root: options.path ? options.path : path_1.default.join(process.cwd(), "public"),
254
+ prefix: options.prefix ? options.prefix : "/static/",
255
+ });
184
256
  }
185
257
  handleMiddlewares(mclasses) {
186
258
  for (const mclass of mclasses) {
@@ -202,7 +274,6 @@ class AvleonApplication {
202
274
  * @returns void
203
275
  */
204
276
  async buildController(controller) {
205
- var _a, e_1, _b, _c;
206
277
  const ctrl = typedi_1.default.get(controller);
207
278
  const controllerMeta = Reflect.getMetadata(container_1.CONTROLLER_META_KEY, ctrl.constructor);
208
279
  if (!controllerMeta)
@@ -212,89 +283,101 @@ class AvleonApplication {
212
283
  const tag = ctrl.constructor.name.replace("Controller", "");
213
284
  const swaggerControllerMeta = Reflect.getMetadata("controller:openapi", ctrl.constructor) || {};
214
285
  const authClsMeata = Reflect.getMetadata(container_1.AUTHORIZATION_META_KEY, ctrl.constructor) || { authorize: false, options: undefined };
215
- if (authClsMeata.authorize && this.authorizeMiddleware) {
216
- this.app.addHook("preHandler", (req, res) => {
217
- return this.authorizeMiddleware.authorize(req);
218
- });
219
- }
220
- try {
221
- for (var _d = true, methods_1 = __asyncValues(methods), methods_1_1; methods_1_1 = await methods_1.next(), _a = methods_1_1.done, !_a; _d = true) {
222
- _c = methods_1_1.value;
223
- _d = false;
224
- const method = _c;
225
- const methodMeta = Reflect.getMetadata(container_1.ROUTE_META_KEY, prototype, method);
226
- if (!methodMeta)
227
- continue;
228
- const methodmetaOptions = {
229
- method: methodMeta.method.toLowerCase(),
230
- path: (0, helpers_1.formatUrl)(controllerMeta.path + methodMeta.path),
231
- };
232
- const routeKey = `${methodmetaOptions.method}:${methodmetaOptions.path}`;
233
- if (!this.routeSet.has(routeKey)) {
234
- this.routeSet.add(routeKey);
286
+ for await (const method of methods) {
287
+ const methodMeta = Reflect.getMetadata(container_1.ROUTE_META_KEY, prototype, method);
288
+ if (!methodMeta)
289
+ continue;
290
+ const methodmetaOptions = {
291
+ method: methodMeta.method.toLowerCase(),
292
+ path: (0, helpers_1.formatUrl)(controllerMeta.path + methodMeta.path),
293
+ };
294
+ const routeKey = `${methodmetaOptions.method}:${methodmetaOptions.path}`;
295
+ if (!this.routeSet.has(routeKey)) {
296
+ this.routeSet.add(routeKey);
297
+ }
298
+ const classMiddlewares = this.executeMiddlewares(ctrl, method);
299
+ // handle openapi data
300
+ const swaggerMeta = Reflect.getMetadata("route:openapi", prototype, method) || {};
301
+ const authClsMethodMeata = Reflect.getMetadata(container_1.AUTHORIZATION_META_KEY, ctrl.constructor, method) || { authorize: false, options: undefined };
302
+ const allMeta = this._processMeta(prototype, method);
303
+ let bodySchema = null;
304
+ allMeta.body.forEach((r) => {
305
+ if (r.schema) {
306
+ bodySchema = { ...r.schema };
235
307
  }
236
- const classMiddlewares = this.executeMiddlewares(ctrl, method);
237
- // handle openapi data
238
- const swaggerMeta = Reflect.getMetadata("route:openapi", prototype, method) || {};
239
- const authClsMethodMeata = Reflect.getMetadata(container_1.AUTHORIZATION_META_KEY, ctrl.constructor, method) || { authorize: false, options: undefined };
240
- const allMeta = this._processMeta(prototype, method);
241
- let bodySchema = null;
242
- allMeta.body.forEach((r) => {
243
- if (r.schema) {
244
- bodySchema = Object.assign({}, r.schema);
308
+ });
309
+ const routePath = methodmetaOptions.path == "" ? "/" : methodmetaOptions.path;
310
+ let schema = { ...swaggerControllerMeta, ...swaggerMeta, tags: [tag] };
311
+ if (!swaggerMeta.body && bodySchema) {
312
+ schema = { ...schema, body: bodySchema };
313
+ }
314
+ this.app.route({
315
+ url: routePath,
316
+ method: methodmetaOptions.method.toUpperCase(),
317
+ schema: { ...schema },
318
+ handler: async (req, res) => {
319
+ let reqClone = req;
320
+ // class level authrization
321
+ if (authClsMeata.authorize && this.authorizeMiddleware) {
322
+ const cls = container_1.default.get(this.authorizeMiddleware);
323
+ await cls.authorize(reqClone, authClsMeata.options);
324
+ if (res.sent)
325
+ return;
245
326
  }
246
- });
247
- const routePath = methodmetaOptions.path == "" ? "/" : methodmetaOptions.path;
248
- let schema = Object.assign(Object.assign(Object.assign({}, swaggerControllerMeta), swaggerMeta), { tags: [tag] });
249
- if (!swaggerMeta.body && bodySchema) {
250
- schema = Object.assign(Object.assign({}, schema), { body: bodySchema });
251
- }
252
- this.app.route({
253
- url: routePath,
254
- method: methodmetaOptions.method.toUpperCase(),
255
- schema: Object.assign({}, schema),
256
- handler: async (req, res) => {
257
- let reqClone = req;
258
- if (authClsMethodMeata.authorize && this.authorizeMiddleware) {
259
- const cls = container_1.default.get(this.authorizeMiddleware);
260
- await cls.authorize(reqClone, authClsMethodMeata.options);
327
+ // method level authorization
328
+ if (authClsMethodMeata.authorize && this.authorizeMiddleware) {
329
+ const cls = container_1.default.get(this.authorizeMiddleware);
330
+ await cls.authorize(reqClone, authClsMethodMeata.options);
331
+ if (res.sent)
332
+ return;
333
+ }
334
+ if (classMiddlewares.length > 0) {
335
+ for (let m of classMiddlewares) {
336
+ const cls = typedi_1.default.get(m.constructor);
337
+ reqClone = (await cls.invoke(reqClone, res));
261
338
  if (res.sent)
262
339
  return;
263
340
  }
264
- if (classMiddlewares.length > 0) {
265
- for (let m of classMiddlewares) {
266
- const cls = typedi_1.default.get(m.constructor);
267
- reqClone = (await cls.invoke(reqClone, res));
268
- if (res.sent)
269
- return;
341
+ }
342
+ const args = await this._mapArgs(reqClone, allMeta);
343
+ for (let paramMeta of allMeta.params) {
344
+ if (paramMeta.required) {
345
+ (0, validation_1.validateOrThrow)({ [paramMeta.key]: args[paramMeta.index] }, { [paramMeta.key]: { type: paramMeta.dataType } }, { location: 'param' });
346
+ }
347
+ }
348
+ for (let queryMeta of allMeta.query) {
349
+ if (queryMeta.validatorClass) {
350
+ const err = await (0, helpers_1.validateObjectByInstance)(queryMeta.dataType, args[queryMeta.index]);
351
+ if (err) {
352
+ return await res.code(400).send({
353
+ code: 400,
354
+ error: "ValidationError",
355
+ errors: err,
356
+ message: err.message,
357
+ });
270
358
  }
271
359
  }
272
- const args = await this._mapArgs(reqClone, allMeta);
273
- for (let bodyMeta of allMeta.body) {
274
- if (bodyMeta.validatorClass) {
275
- const err = await (0, helpers_1.validateObjectByInstance)(bodyMeta.dataType, args[bodyMeta.index]);
276
- if (err) {
277
- return await res.code(400).send({
278
- code: 400,
279
- error: "ValidationError",
280
- errors: err,
281
- message: err.message,
282
- });
283
- }
360
+ if (queryMeta.required) {
361
+ (0, validation_1.validateOrThrow)({ [queryMeta.key]: args[queryMeta.index] }, { [queryMeta.key]: { type: queryMeta.dataType } }, { location: 'queryparam' });
362
+ }
363
+ }
364
+ for (let bodyMeta of allMeta.body) {
365
+ if (bodyMeta.validatorClass) {
366
+ const err = await (0, helpers_1.validateObjectByInstance)(bodyMeta.dataType, args[bodyMeta.index]);
367
+ if (err) {
368
+ return await res.code(400).send({
369
+ code: 400,
370
+ error: "ValidationError",
371
+ errors: err,
372
+ message: err.message,
373
+ });
284
374
  }
285
375
  }
286
- const result = await prototype[method].apply(ctrl, args);
287
- return result;
288
- },
289
- });
290
- }
291
- }
292
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
293
- finally {
294
- try {
295
- if (!_d && !_a && (_b = methods_1.return)) await _b.call(methods_1);
296
- }
297
- finally { if (e_1) throw e_1.error; }
376
+ }
377
+ const result = await prototype[method].apply(ctrl, args);
378
+ return result;
379
+ },
380
+ });
298
381
  }
299
382
  }
300
383
  /**
@@ -304,8 +387,7 @@ class AvleonApplication {
304
387
  * @returns
305
388
  */
306
389
  async _mapArgs(req, meta) {
307
- var _a, e_2, _b, _c, _d, e_3, _e, _f;
308
- var _g;
390
+ var _a;
309
391
  if (!req.hasOwnProperty("_argsCache")) {
310
392
  Object.defineProperty(req, "_argsCache", {
311
393
  value: new Map(),
@@ -319,29 +401,17 @@ class AvleonApplication {
319
401
  }
320
402
  const args = meta.params.map((p) => req.params[p.key] || null);
321
403
  meta.query.forEach((q) => (args[q.index] = q.key === "all" ? req.query : req.query[q.key]));
322
- meta.body.forEach((body) => (args[body.index] = Object.assign(Object.assign({}, req.body), req.formData)));
404
+ meta.body.forEach((body) => (args[body.index] = { ...req.body, ...req.formData }));
323
405
  meta.currentUser.forEach((user) => (args[user.index] = req.user));
324
406
  meta.headers.forEach((header) => (args[header.index] =
325
407
  header.key === "all" ? req.headers : req.headers[header.key]));
326
408
  if (meta.file) {
327
- try {
328
- for (var _h = true, _j = __asyncValues(meta.file), _k; _k = await _j.next(), _a = _k.done, !_a; _h = true) {
329
- _c = _k.value;
330
- _h = false;
331
- let f = _c;
332
- args[f.index] = await req.file();
333
- }
334
- }
335
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
336
- finally {
337
- try {
338
- if (!_h && !_a && (_b = _j.return)) await _b.call(_j);
339
- }
340
- finally { if (e_2) throw e_2.error; }
409
+ for await (let f of meta.file) {
410
+ args[f.index] = await req.file();
341
411
  }
342
412
  }
343
413
  if (meta.files &&
344
- ((_g = req.headers["content-type"]) === null || _g === void 0 ? void 0 : _g.startsWith("multipart/form-data")) === true) {
414
+ ((_a = req.headers["content-type"]) === null || _a === void 0 ? void 0 : _a.startsWith("multipart/form-data")) === true) {
345
415
  const files = await req.saveRequestFiles();
346
416
  if (!files || files.length === 0) {
347
417
  throw new exceptions_1.BadRequestException({ error: "No files uploaded" });
@@ -355,27 +425,15 @@ class AvleonApplication {
355
425
  mimetype: file.mimetype,
356
426
  fields: file.fields,
357
427
  }));
358
- try {
359
- for (var _l = true, _m = __asyncValues(meta.files), _o; _o = await _m.next(), _d = _o.done, !_d; _l = true) {
360
- _f = _o.value;
361
- _l = false;
362
- let f = _f;
363
- const findex = fileInfo.findIndex((x) => x.fieldname == f.fieldName);
364
- if (f.fieldName != "all" && findex == -1) {
365
- throw new exceptions_1.BadRequestException(`${f.fieldName} doesn't exists in request files tree.`);
366
- }
367
- args[f.index] =
368
- f.fieldName == "all"
369
- ? fileInfo
370
- : fileInfo.filter((x) => x.fieldname == f.fieldName);
428
+ for await (let f of meta.files) {
429
+ const findex = fileInfo.findIndex((x) => x.fieldname == f.fieldName);
430
+ if (f.fieldName != "all" && findex == -1) {
431
+ throw new exceptions_1.BadRequestException(`${f.fieldName} doesn't exists in request files tree.`);
371
432
  }
372
- }
373
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
374
- finally {
375
- try {
376
- if (!_l && !_d && (_e = _m.return)) await _e.call(_m);
377
- }
378
- finally { if (e_3) throw e_3.error; }
433
+ args[f.index] =
434
+ f.fieldName == "all"
435
+ ? fileInfo
436
+ : fileInfo.filter((x) => x.fieldname == f.fieldName);
379
437
  }
380
438
  }
381
439
  cache.set(cacheKey, args);
@@ -414,7 +472,6 @@ class AvleonApplication {
414
472
  const module = await Promise.resolve(`${filePath}`).then(s => __importStar(require(s)));
415
473
  for (const exported of Object.values(module)) {
416
474
  if (typeof exported === "function" && (0, container_1.isApiController)(exported)) {
417
- //controllers.push(exported);
418
475
  this.buildController(exported);
419
476
  }
420
477
  }
@@ -424,6 +481,14 @@ class AvleonApplication {
424
481
  mapControllers(controllers) {
425
482
  this.controllers = controllers;
426
483
  }
484
+ // addFeature(feature:{controllers:Function[]}){
485
+ // feature.controllers.forEach(c=> this.controllers.push(c))
486
+ // }
487
+ mapFeature() {
488
+ if (!this.isMapFeatures) {
489
+ this.isMapFeatures = true;
490
+ }
491
+ }
427
492
  async _mapControllers() {
428
493
  if (this.controllers.length > 0) {
429
494
  for (let controller of this.controllers) {
@@ -448,16 +513,6 @@ class AvleonApplication {
448
513
  fn = function () { };
449
514
  return fn;
450
515
  }
451
- useMiddlewares(mclasses) {
452
- for (const mclass of mclasses) {
453
- const cls = typedi_1.default.get(mclass);
454
- this.middlewares.set(mclass.name, cls);
455
- this.app.addHook("preHandler", cls.invoke);
456
- }
457
- }
458
- useAuthoriztion(middleware) {
459
- this.authorizeMiddleware = middleware;
460
- }
461
516
  _handleError(error) {
462
517
  if (error instanceof exceptions_1.BaseHttpException) {
463
518
  return {
@@ -516,7 +571,7 @@ class AvleonApplication {
516
571
  }
517
572
  return route;
518
573
  },
519
- useSwagger: (options) => {
574
+ useOpenApi: (options) => {
520
575
  const r = this.rMap.get(routeKey);
521
576
  if (r) {
522
577
  r.schema = options;
@@ -538,18 +593,16 @@ class AvleonApplication {
538
593
  mapDelete(path = "", fn) {
539
594
  return this._routeHandler(path, "DELETE", fn);
540
595
  }
541
- useStaticFiles(options = { path: undefined, prefix: undefined }) {
542
- this.app.register(require("@fastify/static"), {
543
- root: options.path ? options.path : path_1.default.join(process.cwd(), "public"),
544
- prefix: options.prefix ? options.prefix : "/static/",
545
- });
596
+ _mapFeatures() {
597
+ const features = typedi_1.default.get('features');
598
+ console.log('Features', features);
546
599
  }
547
600
  async initializeDatabase() {
548
601
  if (this.dataSourceOptions && this.dataSource) {
549
602
  await this.dataSource.initialize();
550
603
  }
551
604
  }
552
- async run(port = 4000) {
605
+ async run(port = 4000, fn) {
553
606
  if (this.alreadyRun)
554
607
  throw new system_exception_1.SystemUseError("App already running");
555
608
  this.alreadyRun = true;
@@ -557,6 +610,9 @@ class AvleonApplication {
557
610
  await this.initSwagger(this.globalSwaggerOptions);
558
611
  }
559
612
  await this.initializeDatabase();
613
+ if (this.isMapFeatures) {
614
+ this._mapFeatures();
615
+ }
560
616
  await this._mapControllers();
561
617
  this.rMap.forEach((value, key) => {
562
618
  const [m, r] = key.split(":");
@@ -573,7 +629,7 @@ class AvleonApplication {
573
629
  });
574
630
  this.app.setErrorHandler(async (error, req, res) => {
575
631
  const handledErr = this._handleError(error);
576
- if (error instanceof exceptions_1.ValidationErrorException) {
632
+ if (error instanceof exceptions_1.ValidationErrorException || error instanceof exceptions_1.BadRequestException) {
577
633
  return res.status(handledErr.code).send({
578
634
  code: handledErr.code,
579
635
  error: handledErr.error,
@@ -618,12 +674,12 @@ class AvleonApplication {
618
674
  // return this.app as any;
619
675
  //
620
676
  return {
621
- get: async (url, options) => this.app.inject(Object.assign({ method: "GET", url }, options)),
622
- post: async (url, options) => this.app.inject(Object.assign({ method: "POST", url }, options)),
623
- put: async (url, options) => this.app.inject(Object.assign({ method: "PUT", url }, options)),
624
- patch: async (url, options) => this.app.inject(Object.assign({ method: "PATCH", url }, options)),
625
- delete: async (url, options) => this.app.inject(Object.assign({ method: "DELETE", url }, options)),
626
- options: async (url, options) => this.app.inject(Object.assign({ method: "OPTIONS", url }, options)),
677
+ get: async (url, options) => this.app.inject({ method: "GET", url, ...options }),
678
+ post: async (url, options) => this.app.inject({ method: "POST", url, ...options }),
679
+ put: async (url, options) => this.app.inject({ method: "PUT", url, ...options }),
680
+ patch: async (url, options) => this.app.inject({ method: "PATCH", url, ...options }),
681
+ delete: async (url, options) => this.app.inject({ method: "DELETE", url, ...options }),
682
+ options: async (url, options) => this.app.inject({ method: "OPTIONS", url, ...options }),
627
683
  getController: (controller) => {
628
684
  return typedi_1.default.get(controller);
629
685
  },
@@ -672,41 +728,8 @@ class TestBuilder {
672
728
  }
673
729
  exports.TestBuilder = TestBuilder;
674
730
  class Builder {
675
- constructor() {
676
- this.alreadyBuilt = false;
677
- this.database = false;
678
- this.testBuilder = false;
679
- this.appConfig = new config_1.AppConfig();
680
- }
681
- static createAppBuilder() {
682
- if (!Builder.instance) {
683
- Builder.instance = new Builder();
684
- }
685
- return Builder.instance;
686
- }
687
- async registerPlugin(plugin, options) {
688
- container_1.default.set(plugin, plugin.prototype);
689
- }
690
- addDataSource(ConfigClass, modifyConfig) {
691
- const openApiConfig = this.appConfig.get(ConfigClass);
692
- if (modifyConfig) {
693
- const modifiedConfig = modifyConfig(openApiConfig);
694
- this.dataSourceOptions = modifiedConfig;
695
- }
696
- else {
697
- this.dataSourceOptions = openApiConfig;
698
- }
699
- }
700
- build() {
701
- if (this.alreadyBuilt) {
702
- throw new Error("Already built");
703
- }
704
- this.alreadyBuilt = true;
705
- const app = AvleonApplication.getInternalApp({
706
- database: this.database,
707
- multipartOptions: this.multipartOptions,
708
- dataSourceOptions: this.dataSourceOptions,
709
- });
731
+ static createApplication() {
732
+ const app = AvleonApplication.getApp();
710
733
  return app;
711
734
  }
712
735
  }
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  import * as sw from "./swagger-schema";
8
8
  export * from "./icore";
9
9
  export * from "./testing";
10
- export { inject, validateRequestBody } from "./helpers";
10
+ export { inject, validateRequestBody, pick, exclude } from "./helpers";
11
11
  export * from "./decorators";
12
12
  export * from "./middleware";
13
13
  export * from "./config";
@@ -20,7 +20,7 @@ export * from "./validation";
20
20
  export * from "./environment-variables";
21
21
  export * from "./collection";
22
22
  export * from "./queue";
23
- export * from "./security";
23
+ export * from "./utils/hash";
24
24
  export * from "./multipart";
25
25
  export * from "./file-storage";
26
26
  export * from "./logger";