@avleon/core 0.0.20 → 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.
- package/README.md +559 -2
- package/dist/application.d.ts +26 -0
- package/dist/application.js +50 -0
- package/dist/collection.js +3 -2
- package/dist/container.d.ts +1 -0
- package/dist/container.js +2 -1
- package/dist/environment-variables.js +1 -1
- package/dist/file-storage.js +0 -128
- package/dist/helpers.d.ts +2 -0
- package/dist/helpers.js +41 -4
- package/dist/icore.d.ts +68 -26
- package/dist/icore.js +235 -212
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -2
- package/dist/middleware.js +0 -8
- package/dist/multipart.js +4 -1
- package/dist/openapi.d.ts +37 -37
- package/dist/params.js +2 -2
- package/dist/response.js +6 -2
- package/dist/route-methods.js +1 -1
- package/dist/swagger-schema.js +4 -1
- package/dist/testing.js +5 -2
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/optional-require.d.ts +8 -0
- package/dist/utils/optional-require.js +70 -0
- package/dist/validation.d.ts +4 -1
- package/dist/validation.js +10 -5
- package/package.json +19 -11
- package/src/application.ts +96 -0
- package/src/authentication.ts +16 -0
- package/src/collection.ts +254 -0
- package/src/config.ts +39 -0
- package/src/constants.ts +1 -0
- package/src/container.ts +54 -0
- package/src/controller.ts +128 -0
- package/src/decorators.ts +27 -0
- package/src/environment-variables.ts +46 -0
- package/src/exceptions/http-exceptions.ts +86 -0
- package/src/exceptions/index.ts +1 -0
- package/src/exceptions/system-exception.ts +34 -0
- package/src/file-storage.ts +206 -0
- package/src/helpers.ts +328 -0
- package/src/icore.ts +1064 -0
- package/src/index.ts +30 -0
- package/src/logger.ts +72 -0
- package/src/map-types.ts +159 -0
- package/src/middleware.ts +98 -0
- package/src/multipart.ts +116 -0
- package/src/openapi.ts +372 -0
- package/src/params.ts +111 -0
- package/src/queue.ts +126 -0
- package/src/response.ts +117 -0
- package/src/results.ts +30 -0
- package/src/route-methods.ts +186 -0
- package/src/swagger-schema.ts +213 -0
- package/src/testing.ts +220 -0
- package/src/types/app-builder.interface.ts +19 -0
- package/src/types/application.interface.ts +9 -0
- package/src/utils/hash.ts +5 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/optional-require.ts +50 -0
- package/src/validation.ts +156 -0
- package/src/validator-extend.ts +25 -0
- package/dist/classToOpenapi.d.ts +0 -0
- package/dist/classToOpenapi.js +0 -1
- package/dist/render.d.ts +0 -1
- package/dist/render.js +0 -8
- package/jest.config.ts +0 -9
- package/tsconfig.json +0 -25
- /package/dist/{security.d.ts → utils/hash.d.ts} +0 -0
- /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(
|
|
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
|
|
114
|
+
const { routePrefix, logo, ui, theme, configuration, ...restOptions } = options;
|
|
124
115
|
this.app.register(swagger_1.default, {
|
|
125
|
-
openapi:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
175
|
-
*
|
|
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,
|
|
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
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
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
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
|
|
287
|
-
|
|
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
|
|
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] =
|
|
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
|
-
|
|
328
|
-
|
|
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
|
-
((
|
|
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
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
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
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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
|
-
|
|
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
|
-
|
|
542
|
-
|
|
543
|
-
|
|
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(
|
|
622
|
-
post: async (url, options) => this.app.inject(
|
|
623
|
-
put: async (url, options) => this.app.inject(
|
|
624
|
-
patch: async (url, options) => this.app.inject(
|
|
625
|
-
delete: async (url, options) => this.app.inject(
|
|
626
|
-
options: async (url, options) => this.app.inject(
|
|
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
|
-
|
|
676
|
-
|
|
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 "./
|
|
23
|
+
export * from "./utils/hash";
|
|
24
24
|
export * from "./multipart";
|
|
25
25
|
export * from "./file-storage";
|
|
26
26
|
export * from "./logger";
|