@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.
- package/README.md +355 -369
- package/dist/chunk-9hOWP6kD.cjs +64 -0
- package/dist/chunk-DORXReHP.js +37 -0
- package/dist/index-BxIMWhgy.d.ts +1284 -0
- package/dist/index-DPn7qtzq.d.cts +1283 -0
- package/dist/index.cjs +3194 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +3022 -83
- package/dist/index.js.map +1 -0
- package/dist/lib-Bk8hUm06.cjs +7847 -0
- package/dist/lib-Bk8hUm06.cjs.map +1 -0
- package/dist/lib-CvDxBMkR.js +7843 -0
- package/dist/lib-CvDxBMkR.js.map +1 -0
- package/package.json +67 -116
- package/dist/application.d.ts +0 -47
- package/dist/application.js +0 -50
- package/dist/authentication.d.ts +0 -13
- package/dist/authentication.js +0 -16
- package/dist/cache.d.ts +0 -12
- package/dist/cache.js +0 -78
- package/dist/cache.test.d.ts +0 -1
- package/dist/cache.test.js +0 -36
- package/dist/collection.d.ts +0 -43
- package/dist/collection.js +0 -231
- package/dist/collection.test.d.ts +0 -1
- package/dist/collection.test.js +0 -59
- package/dist/config.d.ts +0 -18
- package/dist/config.js +0 -58
- package/dist/config.test.d.ts +0 -1
- package/dist/config.test.js +0 -40
- package/dist/constants.d.ts +0 -1
- package/dist/constants.js +0 -4
- package/dist/container.d.ts +0 -30
- package/dist/container.js +0 -55
- package/dist/controller.d.ts +0 -50
- package/dist/controller.js +0 -71
- package/dist/controller.test.d.ts +0 -1
- package/dist/controller.test.js +0 -111
- package/dist/decorators.d.ts +0 -15
- package/dist/decorators.js +0 -41
- package/dist/environment-variables.d.ts +0 -49
- package/dist/environment-variables.js +0 -130
- package/dist/environment-variables.test.d.ts +0 -1
- package/dist/environment-variables.test.js +0 -70
- package/dist/event-dispatcher.d.ts +0 -23
- package/dist/event-dispatcher.js +0 -100
- package/dist/event-subscriber.d.ts +0 -14
- package/dist/event-subscriber.js +0 -87
- package/dist/exceptions/http-exceptions.d.ts +0 -50
- package/dist/exceptions/http-exceptions.js +0 -85
- package/dist/exceptions/index.d.ts +0 -1
- package/dist/exceptions/index.js +0 -17
- package/dist/exceptions/system-exception.d.ts +0 -22
- package/dist/exceptions/system-exception.js +0 -26
- package/dist/file-storage.d.ts +0 -69
- package/dist/file-storage.js +0 -323
- package/dist/file-storage.test.d.ts +0 -1
- package/dist/file-storage.test.js +0 -104
- package/dist/helpers.d.ts +0 -44
- package/dist/helpers.js +0 -419
- package/dist/helpers.test.d.ts +0 -1
- package/dist/helpers.test.js +0 -95
- package/dist/icore.d.ts +0 -226
- package/dist/icore.js +0 -968
- package/dist/icore.test.d.ts +0 -1
- package/dist/icore.test.js +0 -14
- package/dist/index.d.ts +0 -55
- package/dist/interfaces/avleon-application.d.ts +0 -27
- package/dist/interfaces/avleon-application.js +0 -1
- package/dist/kenx-provider.d.ts +0 -7
- package/dist/kenx-provider.js +0 -44
- package/dist/kenx-provider.test.d.ts +0 -1
- package/dist/kenx-provider.test.js +0 -36
- package/dist/logger.d.ts +0 -12
- package/dist/logger.js +0 -87
- package/dist/logger.test.d.ts +0 -1
- package/dist/logger.test.js +0 -42
- package/dist/map-types.d.ts +0 -17
- package/dist/map-types.js +0 -89
- package/dist/middleware.d.ts +0 -27
- package/dist/middleware.js +0 -64
- package/dist/middleware.test.d.ts +0 -1
- package/dist/middleware.test.js +0 -121
- package/dist/multipart.d.ts +0 -17
- package/dist/multipart.js +0 -70
- package/dist/multipart.test.d.ts +0 -1
- package/dist/multipart.test.js +0 -87
- package/dist/openapi.d.ts +0 -343
- package/dist/openapi.js +0 -27
- package/dist/openapi.test.d.ts +0 -1
- package/dist/openapi.test.js +0 -111
- package/dist/params.d.ts +0 -17
- package/dist/params.js +0 -64
- package/dist/params.test.d.ts +0 -1
- package/dist/params.test.js +0 -83
- package/dist/queue.d.ts +0 -29
- package/dist/queue.js +0 -84
- package/dist/response.d.ts +0 -16
- package/dist/response.js +0 -56
- package/dist/results.d.ts +0 -20
- package/dist/results.js +0 -32
- package/dist/route-methods.d.ts +0 -25
- package/dist/route-methods.js +0 -49
- package/dist/route-methods.test.d.ts +0 -1
- package/dist/route-methods.test.js +0 -129
- package/dist/swagger-schema.d.ts +0 -43
- package/dist/swagger-schema.js +0 -452
- package/dist/swagger-schema.test.d.ts +0 -1
- package/dist/swagger-schema.test.js +0 -105
- package/dist/testing.d.ts +0 -55
- package/dist/testing.js +0 -196
- package/dist/types/app-builder.interface.d.ts +0 -15
- package/dist/types/app-builder.interface.js +0 -8
- package/dist/types/application.interface.d.ts +0 -8
- package/dist/types/application.interface.js +0 -2
- package/dist/utils/hash.d.ts +0 -4
- package/dist/utils/hash.js +0 -15
- package/dist/utils/index.d.ts +0 -2
- package/dist/utils/index.js +0 -18
- package/dist/utils/optional-require.d.ts +0 -8
- package/dist/utils/optional-require.js +0 -70
- package/dist/validation.d.ts +0 -39
- package/dist/validation.js +0 -111
- package/dist/validation.test.d.ts +0 -1
- package/dist/validation.test.js +0 -61
- package/dist/validator-extend.d.ts +0 -7
- package/dist/validator-extend.js +0 -28
- package/dist/websocket.d.ts +0 -7
- package/dist/websocket.js +0 -20
- package/dist/websocket.test.d.ts +0 -1
- package/dist/websocket.test.js +0 -27
package/dist/icore.js
DELETED
|
@@ -1,968 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.Avleon = exports.AvleonTest = exports.AvleonApplication = void 0;
|
|
40
|
-
/**
|
|
41
|
-
* @copyright 2024
|
|
42
|
-
* @author Tareq Hossain
|
|
43
|
-
* @email xtrinsic96@gmail.com
|
|
44
|
-
* @url https://github.com/xtareq
|
|
45
|
-
*/
|
|
46
|
-
const fastify_1 = __importDefault(require("fastify"));
|
|
47
|
-
const typedi_1 = __importDefault(require("typedi"));
|
|
48
|
-
const promises_1 = __importDefault(require("fs/promises"));
|
|
49
|
-
const path_1 = __importDefault(require("path"));
|
|
50
|
-
const container_1 = __importStar(require("./container"));
|
|
51
|
-
const helpers_1 = require("./helpers");
|
|
52
|
-
const system_exception_1 = require("./exceptions/system-exception");
|
|
53
|
-
const exceptions_1 = require("./exceptions");
|
|
54
|
-
const swagger_1 = __importDefault(require("@fastify/swagger"));
|
|
55
|
-
const config_1 = require("./config");
|
|
56
|
-
const environment_variables_1 = require("./environment-variables");
|
|
57
|
-
const cors_1 = __importDefault(require("@fastify/cors"));
|
|
58
|
-
const multipart_1 = __importDefault(require("@fastify/multipart"));
|
|
59
|
-
const validation_1 = require("./validation");
|
|
60
|
-
const utils_1 = require("./utils");
|
|
61
|
-
const socket_io_1 = require("socket.io");
|
|
62
|
-
const event_dispatcher_1 = require("./event-dispatcher");
|
|
63
|
-
const event_subscriber_1 = require("./event-subscriber");
|
|
64
|
-
const stream_1 = __importDefault(require("stream"));
|
|
65
|
-
const kenx_provider_1 = require("./kenx-provider");
|
|
66
|
-
const controller_1 = require("./controller");
|
|
67
|
-
const mime_1 = __importDefault(require("mime"));
|
|
68
|
-
const isTsNode = process.env.TS_NODE_DEV ||
|
|
69
|
-
process.env.TS_NODE_PROJECT ||
|
|
70
|
-
process[Symbol.for("ts-node.register.instance")];
|
|
71
|
-
const controllerDir = path_1.default.join(process.cwd(), isTsNode ? "./src/controllers" : "./dist/cotrollers");
|
|
72
|
-
const subscriberRegistry = typedi_1.default.get(event_subscriber_1.EventSubscriberRegistry);
|
|
73
|
-
// InternalApplication
|
|
74
|
-
class AvleonApplication {
|
|
75
|
-
constructor() {
|
|
76
|
-
this.routeSet = new Set(); // Use Set for fast duplicate detection
|
|
77
|
-
this.alreadyRun = false;
|
|
78
|
-
this.routes = new Map();
|
|
79
|
-
this.middlewares = new Map();
|
|
80
|
-
this.rMap = new Map();
|
|
81
|
-
this.hasSwagger = false;
|
|
82
|
-
this._hasWebsocket = false;
|
|
83
|
-
this.globalSwaggerOptions = {};
|
|
84
|
-
this.dataSourceOptions = undefined;
|
|
85
|
-
this.controllers = [];
|
|
86
|
-
this.authorizeMiddleware = undefined;
|
|
87
|
-
this.dataSource = undefined;
|
|
88
|
-
this.isMapFeatures = false;
|
|
89
|
-
this.registerControllerAuto = false;
|
|
90
|
-
this.registerControllerPath = "./src";
|
|
91
|
-
this.metaCache = new Map();
|
|
92
|
-
this.app = (0, fastify_1.default)();
|
|
93
|
-
this.appConfig = new config_1.AvleonConfig();
|
|
94
|
-
}
|
|
95
|
-
static getApp() {
|
|
96
|
-
let isTestEnv = process.env.NODE_ENV == "test";
|
|
97
|
-
if (!AvleonApplication.instance) {
|
|
98
|
-
AvleonApplication.instance = new AvleonApplication();
|
|
99
|
-
}
|
|
100
|
-
return AvleonApplication.instance;
|
|
101
|
-
}
|
|
102
|
-
static getInternalApp(buildOptions) {
|
|
103
|
-
let isTestEnv = process.env.NODE_ENV == "test";
|
|
104
|
-
if (!AvleonApplication.instance) {
|
|
105
|
-
AvleonApplication.instance = new AvleonApplication();
|
|
106
|
-
}
|
|
107
|
-
AvleonApplication.buildOptions = buildOptions;
|
|
108
|
-
if (buildOptions.dataSourceOptions) {
|
|
109
|
-
AvleonApplication.instance.dataSourceOptions =
|
|
110
|
-
buildOptions.dataSourceOptions;
|
|
111
|
-
const typeorm = require("typeorm");
|
|
112
|
-
const datasource = new typeorm.DataSource(buildOptions.dataSourceOptions);
|
|
113
|
-
typedi_1.default.set("idatasource", datasource);
|
|
114
|
-
AvleonApplication.instance.dataSource = datasource;
|
|
115
|
-
}
|
|
116
|
-
return AvleonApplication.instance;
|
|
117
|
-
}
|
|
118
|
-
useLogger(corsOptions) {
|
|
119
|
-
let coptions = {};
|
|
120
|
-
if (corsOptions) {
|
|
121
|
-
if (this._isConfigClass(corsOptions)) {
|
|
122
|
-
coptions = this.appConfig.get(corsOptions);
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
coptions = corsOptions;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
isDevelopment() {
|
|
130
|
-
const env = container_1.default.get(environment_variables_1.Environment);
|
|
131
|
-
return env.get("NODE_ENV") == "development";
|
|
132
|
-
}
|
|
133
|
-
async initSwagger(options) {
|
|
134
|
-
const { routePrefix, logo, ui, theme, configuration, ...restOptions } = options;
|
|
135
|
-
this.app.register(swagger_1.default, {
|
|
136
|
-
openapi: {
|
|
137
|
-
openapi: "3.0.0",
|
|
138
|
-
...restOptions,
|
|
139
|
-
},
|
|
140
|
-
});
|
|
141
|
-
const rPrefix = routePrefix ? routePrefix : "/docs";
|
|
142
|
-
if (options.ui && options.ui == "scalar") {
|
|
143
|
-
const scalarPlugin = (0, utils_1.optionalRequire)("@scalar/fastify-api-reference", {
|
|
144
|
-
failOnMissing: true,
|
|
145
|
-
customMessage: 'Install "@scalar/fastify-api-reference" to enable API docs.\n\n npm install @scalar/fastify-api-reference',
|
|
146
|
-
});
|
|
147
|
-
await this.app.register(scalarPlugin, {
|
|
148
|
-
routePrefix: rPrefix,
|
|
149
|
-
configuration: configuration
|
|
150
|
-
? configuration
|
|
151
|
-
: {
|
|
152
|
-
metaData: {
|
|
153
|
-
title: "Avleon Api",
|
|
154
|
-
ogTitle: "Avleon",
|
|
155
|
-
},
|
|
156
|
-
theme: options.theme ? options.theme : "kepler",
|
|
157
|
-
favicon: "/static/favicon.png",
|
|
158
|
-
},
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
const fastifySwaggerUi = (0, utils_1.optionalRequire)("@fastify/swagger-ui", {
|
|
163
|
-
failOnMissing: true,
|
|
164
|
-
customMessage: 'Install "@fastify/swagger-ui" to enable API docs.\n\n npm install @fastify/swagger-ui',
|
|
165
|
-
});
|
|
166
|
-
await this.app.register(fastifySwaggerUi, {
|
|
167
|
-
logo: logo ? logo : null,
|
|
168
|
-
theme: theme ? theme : {},
|
|
169
|
-
routePrefix: rPrefix,
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
_isConfigClass(input) {
|
|
174
|
-
var _a;
|
|
175
|
-
return (typeof input === "function" &&
|
|
176
|
-
typeof input.prototype === "object" &&
|
|
177
|
-
((_a = input.prototype) === null || _a === void 0 ? void 0 : _a.constructor) === input);
|
|
178
|
-
}
|
|
179
|
-
useCors(corsOptions) {
|
|
180
|
-
let coptions = {};
|
|
181
|
-
if (corsOptions) {
|
|
182
|
-
if (this._isConfigClass(corsOptions)) {
|
|
183
|
-
coptions = this.appConfig.get(corsOptions);
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
coptions = corsOptions;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
this.app.register(cors_1.default, coptions);
|
|
190
|
-
}
|
|
191
|
-
useWebSocket(socketOptions) {
|
|
192
|
-
this._hasWebsocket = true;
|
|
193
|
-
this._initWebSocket(socketOptions);
|
|
194
|
-
}
|
|
195
|
-
useSocketIO(socketOptions) {
|
|
196
|
-
this._hasWebsocket = true;
|
|
197
|
-
this._initWebSocket(socketOptions);
|
|
198
|
-
}
|
|
199
|
-
async _initWebSocket(options) {
|
|
200
|
-
const fsSocketIO = (0, utils_1.optionalRequire)("fastify-socket.io", {
|
|
201
|
-
failOnMissing: true,
|
|
202
|
-
customMessage: 'Install "fastify-socket.io" to enable socket.io.\n\n run pnpm install fastify-socket.io',
|
|
203
|
-
});
|
|
204
|
-
this.app.register(fsSocketIO, options);
|
|
205
|
-
}
|
|
206
|
-
useOpenApi(configOrClass) {
|
|
207
|
-
let openApiConfig;
|
|
208
|
-
if (this._isConfigClass(configOrClass)) {
|
|
209
|
-
openApiConfig = this.appConfig.get(configOrClass);
|
|
210
|
-
}
|
|
211
|
-
else {
|
|
212
|
-
openApiConfig = configOrClass;
|
|
213
|
-
}
|
|
214
|
-
this.globalSwaggerOptions = openApiConfig;
|
|
215
|
-
this.hasSwagger = true;
|
|
216
|
-
}
|
|
217
|
-
useMultipart(options) {
|
|
218
|
-
let multipartOptions;
|
|
219
|
-
if (this._isConfigClass(options)) {
|
|
220
|
-
multipartOptions = this.appConfig.get(options);
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
223
|
-
multipartOptions = options;
|
|
224
|
-
}
|
|
225
|
-
if (multipartOptions) {
|
|
226
|
-
this.multipartOptions = multipartOptions;
|
|
227
|
-
this.app.register(multipart_1.default, {
|
|
228
|
-
attachFieldsToBody: true,
|
|
229
|
-
...this.multipartOptions,
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
useDataSource(options) {
|
|
234
|
-
let dataSourceOptions;
|
|
235
|
-
if (this._isConfigClass(options)) {
|
|
236
|
-
dataSourceOptions = this.appConfig.get(options);
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
dataSourceOptions = options;
|
|
240
|
-
}
|
|
241
|
-
if (!dataSourceOptions)
|
|
242
|
-
throw new system_exception_1.SystemUseError("Invlaid datasource options.");
|
|
243
|
-
this.dataSourceOptions = dataSourceOptions;
|
|
244
|
-
const typeorm = require("typeorm");
|
|
245
|
-
const datasource = new typeorm.DataSource(dataSourceOptions);
|
|
246
|
-
this.dataSource = datasource;
|
|
247
|
-
typedi_1.default.set("idatasource", datasource);
|
|
248
|
-
}
|
|
249
|
-
useKnex(options) {
|
|
250
|
-
let dataSourceOptions;
|
|
251
|
-
if (this._isConfigClass(options)) {
|
|
252
|
-
dataSourceOptions = this.appConfig.get(options);
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
dataSourceOptions = options;
|
|
256
|
-
}
|
|
257
|
-
if (!dataSourceOptions)
|
|
258
|
-
throw new system_exception_1.SystemUseError("Invlaid datasource options.");
|
|
259
|
-
//registerKnex(dataSourceOptions);
|
|
260
|
-
const db = typedi_1.default.get(kenx_provider_1.DB);
|
|
261
|
-
db.init(dataSourceOptions);
|
|
262
|
-
}
|
|
263
|
-
_useCache(options) { }
|
|
264
|
-
useMiddlewares(mclasses) {
|
|
265
|
-
for (const mclass of mclasses) {
|
|
266
|
-
const cls = typedi_1.default.get(mclass);
|
|
267
|
-
this.middlewares.set(mclass.name, cls);
|
|
268
|
-
this.app.addHook("preHandler", cls.invoke);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
useAuthoriztion(middleware) {
|
|
272
|
-
this.authorizeMiddleware = middleware;
|
|
273
|
-
}
|
|
274
|
-
useStaticFiles(options = { path: undefined, prefix: undefined }) {
|
|
275
|
-
this.app.register(require("@fastify/static"), {
|
|
276
|
-
root: options.path ? options.path : path_1.default.join(process.cwd(), "public"),
|
|
277
|
-
prefix: options.prefix ? options.prefix : "/static/",
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
handleMiddlewares(mclasses) {
|
|
281
|
-
for (const mclass of mclasses) {
|
|
282
|
-
const cls = typedi_1.default.get(mclass.constructor);
|
|
283
|
-
this.middlewares.set(mclass.name, cls);
|
|
284
|
-
this.app.addHook("preHandler", cls.invoke);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
executeMiddlewares(target, propertyKey) {
|
|
288
|
-
const classMiddlewares = Reflect.getMetadata("controller:middleware", target.constructor) || [];
|
|
289
|
-
const methodMiddlewares = propertyKey
|
|
290
|
-
? Reflect.getMetadata("route:middleware", target, propertyKey) || []
|
|
291
|
-
: [];
|
|
292
|
-
return [...classMiddlewares, ...methodMiddlewares];
|
|
293
|
-
}
|
|
294
|
-
/**
|
|
295
|
-
* build controller
|
|
296
|
-
* @param controller
|
|
297
|
-
* @returns void
|
|
298
|
-
*/
|
|
299
|
-
async buildController(controller) {
|
|
300
|
-
var _a, _b;
|
|
301
|
-
const ctrl = typedi_1.default.get(controller);
|
|
302
|
-
const controllerMeta = Reflect.getMetadata(container_1.CONTROLLER_META_KEY, ctrl.constructor);
|
|
303
|
-
if (!controllerMeta)
|
|
304
|
-
return;
|
|
305
|
-
const prototype = Object.getPrototypeOf(ctrl);
|
|
306
|
-
const methods = Object.getOwnPropertyNames(prototype).filter((name) => name !== "constructor");
|
|
307
|
-
const tag = ctrl.constructor.name.replace("Controller", "");
|
|
308
|
-
const swaggerControllerMeta = Reflect.getMetadata("controller:openapi", ctrl.constructor) || {};
|
|
309
|
-
const authClsMeata = Reflect.getMetadata(container_1.AUTHORIZATION_META_KEY, ctrl.constructor) || { authorize: false, options: undefined };
|
|
310
|
-
for await (const method of methods) {
|
|
311
|
-
const methodMeta = Reflect.getMetadata(container_1.ROUTE_META_KEY, prototype, method);
|
|
312
|
-
if (!methodMeta)
|
|
313
|
-
continue;
|
|
314
|
-
const methodmetaOptions = {
|
|
315
|
-
method: methodMeta.method.toLowerCase(),
|
|
316
|
-
path: (0, helpers_1.formatUrl)(controllerMeta.path + methodMeta.path),
|
|
317
|
-
};
|
|
318
|
-
const routeKey = `${methodmetaOptions.method}:${methodmetaOptions.path}`;
|
|
319
|
-
if (!this.routeSet.has(routeKey)) {
|
|
320
|
-
this.routeSet.add(routeKey);
|
|
321
|
-
}
|
|
322
|
-
const classMiddlewares = this.executeMiddlewares(ctrl, method);
|
|
323
|
-
// handle openapi data
|
|
324
|
-
const swaggerMeta = Reflect.getMetadata("route:openapi", prototype, method) || {};
|
|
325
|
-
const authClsMethodMeata = Reflect.getMetadata(container_1.AUTHORIZATION_META_KEY, ctrl.constructor, method) || { authorize: false, options: undefined };
|
|
326
|
-
const allMeta = this._processMeta(prototype, method);
|
|
327
|
-
let bodySchema = null;
|
|
328
|
-
allMeta.body.forEach((r) => {
|
|
329
|
-
if (r.schema) {
|
|
330
|
-
bodySchema = { ...r.schema };
|
|
331
|
-
}
|
|
332
|
-
});
|
|
333
|
-
const routePath = methodmetaOptions.path == "" ? "/" : methodmetaOptions.path;
|
|
334
|
-
let schema = { ...swaggerControllerMeta, ...swaggerMeta, tags: [tag] };
|
|
335
|
-
if (!swaggerMeta.body && bodySchema) {
|
|
336
|
-
schema = { ...schema, body: bodySchema };
|
|
337
|
-
}
|
|
338
|
-
// const isMultipart =
|
|
339
|
-
// schema.consumes?.includes('multipart/form-data') ||
|
|
340
|
-
// (schema.body && schema.body.type === 'object' &&
|
|
341
|
-
// Object.values(schema.body.properties || {}).some((p: any) => p.format === 'binary'));
|
|
342
|
-
const isMultipart = ((_a = schema === null || schema === void 0 ? void 0 : schema.consumes) === null || _a === void 0 ? void 0 : _a.includes("multipart/form-data")) ||
|
|
343
|
-
Object.values(((_b = schema === null || schema === void 0 ? void 0 : schema.body) === null || _b === void 0 ? void 0 : _b.properties) || {}).some((p) => p.format === "binary");
|
|
344
|
-
// Prepare the route schema
|
|
345
|
-
let routeSchema = schema;
|
|
346
|
-
if (isMultipart) {
|
|
347
|
-
schema.consumes = ["multipart/form-data"];
|
|
348
|
-
if (!schema.body) {
|
|
349
|
-
schema.body = {
|
|
350
|
-
type: "object",
|
|
351
|
-
properties: {},
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
for (const param of allMeta.body) {
|
|
355
|
-
if (param.type == "route:file") {
|
|
356
|
-
schema.body.properties[param.key] = {
|
|
357
|
-
type: "string",
|
|
358
|
-
format: "binary",
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
else {
|
|
362
|
-
schema.body.properties[param.key] = { type: param.dataType };
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
this.app.route({
|
|
367
|
-
url: routePath,
|
|
368
|
-
method: methodmetaOptions.method.toUpperCase(),
|
|
369
|
-
schema: routeSchema,
|
|
370
|
-
attachValidation: isMultipart,
|
|
371
|
-
handler: async (req, res) => {
|
|
372
|
-
let reqClone = req;
|
|
373
|
-
// class level authrization
|
|
374
|
-
if (authClsMeata.authorize && this.authorizeMiddleware) {
|
|
375
|
-
const cls = container_1.default.get(this.authorizeMiddleware);
|
|
376
|
-
await cls.authorize(reqClone, authClsMeata.options);
|
|
377
|
-
if (res.sent)
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
|
-
// method level authorization
|
|
381
|
-
if (authClsMethodMeata.authorize && this.authorizeMiddleware) {
|
|
382
|
-
const cls = container_1.default.get(this.authorizeMiddleware);
|
|
383
|
-
await cls.authorize(reqClone, authClsMethodMeata.options);
|
|
384
|
-
if (res.sent)
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
if (classMiddlewares.length > 0) {
|
|
388
|
-
for (let m of classMiddlewares) {
|
|
389
|
-
const cls = typedi_1.default.get(m.constructor);
|
|
390
|
-
reqClone = (await cls.invoke(reqClone, res));
|
|
391
|
-
if (res.sent)
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
const args = await this._mapArgs(reqClone, allMeta);
|
|
396
|
-
for (let paramMeta of allMeta.params) {
|
|
397
|
-
if (paramMeta.required) {
|
|
398
|
-
(0, validation_1.validateOrThrow)({ [paramMeta.key]: args[paramMeta.index] }, { [paramMeta.key]: { type: paramMeta.dataType } }, { location: "param" });
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
for (let queryMeta of allMeta.query) {
|
|
402
|
-
if (queryMeta.validatorClass) {
|
|
403
|
-
const err = await (0, helpers_1.validateObjectByInstance)(queryMeta.dataType, args[queryMeta.index]);
|
|
404
|
-
if (err) {
|
|
405
|
-
return await res.code(400).send({
|
|
406
|
-
code: 400,
|
|
407
|
-
error: "ValidationError",
|
|
408
|
-
errors: err,
|
|
409
|
-
message: err.message,
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
if (queryMeta.required) {
|
|
414
|
-
(0, validation_1.validateOrThrow)({ [queryMeta.key]: args[queryMeta.index] }, { [queryMeta.key]: { type: queryMeta.dataType } }, { location: "queryparam" });
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
if (!isMultipart) {
|
|
418
|
-
for (let bodyMeta of allMeta.body) {
|
|
419
|
-
if (bodyMeta.validatorClass) {
|
|
420
|
-
const err = await (0, helpers_1.validateObjectByInstance)(bodyMeta.dataType, args[bodyMeta.index]);
|
|
421
|
-
if (err) {
|
|
422
|
-
return await res.code(400).send({
|
|
423
|
-
code: 400,
|
|
424
|
-
error: "ValidationError",
|
|
425
|
-
errors: err,
|
|
426
|
-
message: err.message,
|
|
427
|
-
});
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
const result = await prototype[method].apply(ctrl, args);
|
|
433
|
-
// Custom wrapped file download
|
|
434
|
-
if (result === null || result === void 0 ? void 0 : result.download) {
|
|
435
|
-
const { stream, filename } = result;
|
|
436
|
-
if (!stream || typeof stream.pipe !== "function") {
|
|
437
|
-
return res.code(500).send({
|
|
438
|
-
code: 500,
|
|
439
|
-
error: "INTERNAL_ERROR",
|
|
440
|
-
message: "Invalid stream object",
|
|
441
|
-
});
|
|
442
|
-
}
|
|
443
|
-
const contentType = result.contentType ||
|
|
444
|
-
mime_1.default.getType(filename) ||
|
|
445
|
-
"application/octet-stream";
|
|
446
|
-
res.header("Content-Type", contentType);
|
|
447
|
-
res.header("Content-Disposition", `attachment; filename="${filename}"`);
|
|
448
|
-
stream.on("error", (err) => {
|
|
449
|
-
console.error("Stream error:", err);
|
|
450
|
-
if (!res.sent) {
|
|
451
|
-
res.code(500).send({
|
|
452
|
-
code: 500,
|
|
453
|
-
error: "StreamError",
|
|
454
|
-
message: "Error while streaming file.",
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
});
|
|
458
|
-
return res.send(stream);
|
|
459
|
-
}
|
|
460
|
-
// Native stream (not wrapped)
|
|
461
|
-
if (result instanceof stream_1.default || typeof (result === null || result === void 0 ? void 0 : result.pipe) === "function") {
|
|
462
|
-
result.on("error", (err) => {
|
|
463
|
-
console.error("Stream error:", err);
|
|
464
|
-
if (!res.sent) {
|
|
465
|
-
res.code(500).send({
|
|
466
|
-
code: 500,
|
|
467
|
-
error: "StreamError",
|
|
468
|
-
message: "Error while streaming file.",
|
|
469
|
-
});
|
|
470
|
-
}
|
|
471
|
-
});
|
|
472
|
-
res.header("Content-Type", "application/octet-stream");
|
|
473
|
-
return res.send(result);
|
|
474
|
-
}
|
|
475
|
-
return res.send(result);
|
|
476
|
-
},
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
/**
|
|
481
|
-
* Maps request data to controller method arguments based on decorators
|
|
482
|
-
* @param req - The incoming request object
|
|
483
|
-
* @param meta - Metadata about method parameters
|
|
484
|
-
* @returns Array of arguments to pass to the controller method
|
|
485
|
-
*/
|
|
486
|
-
async _mapArgs(req, meta) {
|
|
487
|
-
var _a, _b, _c, _d;
|
|
488
|
-
// Initialize args cache on request if not present
|
|
489
|
-
if (!req.hasOwnProperty("_argsCache")) {
|
|
490
|
-
Object.defineProperty(req, "_argsCache", {
|
|
491
|
-
value: new Map(),
|
|
492
|
-
enumerable: false,
|
|
493
|
-
writable: false,
|
|
494
|
-
configurable: false,
|
|
495
|
-
});
|
|
496
|
-
}
|
|
497
|
-
const cache = req._argsCache;
|
|
498
|
-
const cacheKey = JSON.stringify(meta);
|
|
499
|
-
// Return cached result if available
|
|
500
|
-
if (cache.has(cacheKey)) {
|
|
501
|
-
return cache.get(cacheKey);
|
|
502
|
-
}
|
|
503
|
-
// Initialize args array with correct length
|
|
504
|
-
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), ...(((_a = meta.request) === null || _a === void 0 ? void 0 : _a.map((r) => r.index)) || []), ...(((_b = meta.file) === null || _b === void 0 ? void 0 : _b.map((f) => f.index)) || []), ...(((_c = meta.files) === null || _c === void 0 ? void 0 : _c.map((f) => f.index)) || []), -1) + 1;
|
|
505
|
-
const args = new Array(maxIndex).fill(undefined);
|
|
506
|
-
meta.params.forEach((p) => {
|
|
507
|
-
var _a;
|
|
508
|
-
const raw = p.key === "all" ? { ...req.params } : ((_a = req.params[p.key]) !== null && _a !== void 0 ? _a : null);
|
|
509
|
-
args[p.index] = (0, helpers_1.autoCast)(raw, p.dataType, p.schema);
|
|
510
|
-
});
|
|
511
|
-
meta.query.forEach((q) => {
|
|
512
|
-
const raw = q.key === "all" ? (0, helpers_1.normalizeQueryDeep)({ ...req.query }) : req.query[q.key];
|
|
513
|
-
args[q.index] = (0, helpers_1.autoCast)(raw, q.dataType, q.schema);
|
|
514
|
-
});
|
|
515
|
-
meta.body.forEach((body) => {
|
|
516
|
-
args[body.index] = { ...req.body, ...req.formData };
|
|
517
|
-
});
|
|
518
|
-
meta.currentUser.forEach((user) => {
|
|
519
|
-
args[user.index] = req.user;
|
|
520
|
-
});
|
|
521
|
-
meta.headers.forEach((header) => {
|
|
522
|
-
args[header.index] =
|
|
523
|
-
header.key === "all" ? { ...req.headers } : req.headers[header.key];
|
|
524
|
-
});
|
|
525
|
-
if (meta.request && meta.request.length > 0) {
|
|
526
|
-
meta.request.forEach((r) => {
|
|
527
|
-
args[r.index] = req;
|
|
528
|
-
});
|
|
529
|
-
}
|
|
530
|
-
// Handle file uploads (single or multiple files)
|
|
531
|
-
const needsFiles = (meta.file && meta.file.length > 0) ||
|
|
532
|
-
(meta.files && meta.files.length > 0);
|
|
533
|
-
if (needsFiles &&
|
|
534
|
-
((_d = req.headers["content-type"]) === null || _d === void 0 ? void 0 : _d.startsWith("multipart/form-data"))) {
|
|
535
|
-
const files = await req.saveRequestFiles();
|
|
536
|
-
if (!files || files.length === 0) {
|
|
537
|
-
if (meta.files && meta.files.length > 0) {
|
|
538
|
-
throw new exceptions_1.BadRequestException({ error: "No files uploaded" });
|
|
539
|
-
}
|
|
540
|
-
if (meta.file && meta.file.length > 0) {
|
|
541
|
-
meta.file.forEach((f) => {
|
|
542
|
-
args[f.index] = null;
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
else {
|
|
547
|
-
const fileInfo = files.map((file) => ({
|
|
548
|
-
type: file.type,
|
|
549
|
-
filepath: file.filepath,
|
|
550
|
-
fieldname: file.fieldname,
|
|
551
|
-
filename: file.filename,
|
|
552
|
-
encoding: file.encoding,
|
|
553
|
-
mimetype: file.mimetype,
|
|
554
|
-
fields: file.fields,
|
|
555
|
-
toBuffer: file.toBuffer,
|
|
556
|
-
}));
|
|
557
|
-
if (meta.file && meta.file.length > 0) {
|
|
558
|
-
meta.file.forEach((f) => {
|
|
559
|
-
if (f.fieldName === "all") {
|
|
560
|
-
args[f.index] = fileInfo[0] || null;
|
|
561
|
-
}
|
|
562
|
-
else {
|
|
563
|
-
const file = fileInfo.find((x) => x.fieldname === f.fieldName);
|
|
564
|
-
if (!file) {
|
|
565
|
-
throw new exceptions_1.BadRequestException(`File field "${f.fieldName}" not found in uploaded files`);
|
|
566
|
-
}
|
|
567
|
-
args[f.index] = file;
|
|
568
|
-
}
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
if (meta.files && meta.files.length > 0) {
|
|
572
|
-
meta.files.forEach((f) => {
|
|
573
|
-
if (f.fieldName === "all") {
|
|
574
|
-
args[f.index] = fileInfo;
|
|
575
|
-
}
|
|
576
|
-
else {
|
|
577
|
-
const matchingFiles = fileInfo.filter((x) => x.fieldname === f.fieldName);
|
|
578
|
-
if (matchingFiles.length === 0) {
|
|
579
|
-
throw new exceptions_1.BadRequestException(`No files found for field "${f.fieldName}"`);
|
|
580
|
-
}
|
|
581
|
-
args[f.index] = matchingFiles;
|
|
582
|
-
}
|
|
583
|
-
});
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
else if (needsFiles) {
|
|
588
|
-
throw new exceptions_1.BadRequestException({
|
|
589
|
-
error: "Invalid content type. Expected multipart/form-data for file uploads",
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
cache.set(cacheKey, args);
|
|
593
|
-
return args;
|
|
594
|
-
}
|
|
595
|
-
/**
|
|
596
|
-
* Process Meta for controlelr class methods
|
|
597
|
-
* @param prototype
|
|
598
|
-
* @param method
|
|
599
|
-
* @returns
|
|
600
|
-
*/
|
|
601
|
-
_processMeta(prototype, method) {
|
|
602
|
-
const cacheKey = `${prototype.constructor.name}_${method}`;
|
|
603
|
-
if (this.metaCache.has(cacheKey)) {
|
|
604
|
-
return this.metaCache.get(cacheKey);
|
|
605
|
-
}
|
|
606
|
-
const meta = {
|
|
607
|
-
request: Reflect.getMetadata(controller_1.REQUEST_METADATA_KEY, prototype, method) || [],
|
|
608
|
-
params: Reflect.getMetadata(container_1.PARAM_META_KEY, prototype, method) || [],
|
|
609
|
-
query: Reflect.getMetadata(container_1.QUERY_META_KEY, prototype, method) || [],
|
|
610
|
-
body: Reflect.getMetadata(container_1.REQUEST_BODY_META_KEY, prototype, method) || [],
|
|
611
|
-
file: Reflect.getMetadata(container_1.REQUEST_BODY_FILE_KEY, prototype, method) || [],
|
|
612
|
-
files: Reflect.getMetadata(container_1.REQUEST_BODY_FILES_KEY, prototype, method) || [],
|
|
613
|
-
headers: Reflect.getMetadata(container_1.REQUEST_HEADER_META_KEY, prototype, method) || [],
|
|
614
|
-
currentUser: Reflect.getMetadata(container_1.REQUEST_USER_META_KEY, prototype, method) || [],
|
|
615
|
-
// swagger: Reflect.getMetadata("route:openapi", prototype, method) || {}
|
|
616
|
-
};
|
|
617
|
-
this.metaCache.set(cacheKey, meta);
|
|
618
|
-
return meta;
|
|
619
|
-
}
|
|
620
|
-
_resolveControllerDir(dir) {
|
|
621
|
-
const isTsNode = process.env.TS_NODE_DEV ||
|
|
622
|
-
process.env.TS_NODE_PROJECT ||
|
|
623
|
-
process[Symbol.for("ts-node.register.instance")];
|
|
624
|
-
const controllerDir = path_1.default.join(process.cwd(), this.registerControllerPath);
|
|
625
|
-
return isTsNode ? controllerDir : controllerDir.replace("src", "dist");
|
|
626
|
-
}
|
|
627
|
-
async autoControllers(controllersPath) {
|
|
628
|
-
const conDir = this._resolveControllerDir(controllersPath);
|
|
629
|
-
const files = await promises_1.default.readdir(conDir, { recursive: true });
|
|
630
|
-
for (const file of files) {
|
|
631
|
-
const isTestFile = /\.(test|spec|e2e-spec)\.ts$/.test(file);
|
|
632
|
-
if (isTestFile)
|
|
633
|
-
continue;
|
|
634
|
-
if (isTsNode ? file.endsWith(".ts") : file.endsWith(".js")) {
|
|
635
|
-
const filePath = path_1.default.join(conDir, file);
|
|
636
|
-
const module = await Promise.resolve(`${filePath}`).then(s => __importStar(require(s)));
|
|
637
|
-
for (const exported of Object.values(module)) {
|
|
638
|
-
if (typeof exported === "function" && (0, container_1.isApiController)(exported)) {
|
|
639
|
-
if (!this.controllers.some((con) => exported.name == con.name)) {
|
|
640
|
-
this.controllers.push(exported);
|
|
641
|
-
}
|
|
642
|
-
//this.buildController(exported);
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
useControllers(controllers) {
|
|
649
|
-
if (Array.isArray(controllers)) {
|
|
650
|
-
this.controllers = controllers;
|
|
651
|
-
controllers.forEach((controller) => {
|
|
652
|
-
if (!this.controllers.includes(controller)) {
|
|
653
|
-
this.controllers.push(controller);
|
|
654
|
-
}
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
else {
|
|
658
|
-
this.registerControllerAuto = true;
|
|
659
|
-
if (controllers.path) {
|
|
660
|
-
this.registerControllerPath = controllers.path;
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
async _mapControllers() {
|
|
665
|
-
if (this.controllers.length > 0) {
|
|
666
|
-
for (let controller of this.controllers) {
|
|
667
|
-
if ((0, container_1.isApiController)(controller)) {
|
|
668
|
-
await this.buildController(controller);
|
|
669
|
-
}
|
|
670
|
-
else {
|
|
671
|
-
throw new system_exception_1.SystemUseError("Not a api controller.");
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
async mapFn(fn) {
|
|
677
|
-
const original = fn;
|
|
678
|
-
fn = function () { };
|
|
679
|
-
return fn;
|
|
680
|
-
}
|
|
681
|
-
_handleError(error) {
|
|
682
|
-
if (error instanceof exceptions_1.BaseHttpException) {
|
|
683
|
-
return {
|
|
684
|
-
code: error.code,
|
|
685
|
-
error: error.name,
|
|
686
|
-
message: (0, helpers_1.isValidJsonString)(error.message)
|
|
687
|
-
? JSON.parse(error.message)
|
|
688
|
-
: error.message,
|
|
689
|
-
};
|
|
690
|
-
}
|
|
691
|
-
return {
|
|
692
|
-
code: 500,
|
|
693
|
-
error: "INTERNAL_ERROR",
|
|
694
|
-
message: error.message ? error.message : "Something going wrong.",
|
|
695
|
-
};
|
|
696
|
-
}
|
|
697
|
-
async mapRoute(method, path = "", fn) {
|
|
698
|
-
await this.mapFn(fn);
|
|
699
|
-
this.app[method](path, async (req, res) => {
|
|
700
|
-
try {
|
|
701
|
-
const result = await fn.apply(this, [req, res]);
|
|
702
|
-
if (typeof result === "object" && result !== null) {
|
|
703
|
-
res.json(result);
|
|
704
|
-
}
|
|
705
|
-
else {
|
|
706
|
-
res.send(result);
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
catch (error) {
|
|
710
|
-
console.error(`Error in ${method} route handler:`, error);
|
|
711
|
-
const handledErr = this._handleError(error);
|
|
712
|
-
res.status(handledErr.code).send(handledErr);
|
|
713
|
-
}
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
|
-
_routeHandler(routePath, method, fn) {
|
|
717
|
-
const routeKey = method + ":" + routePath;
|
|
718
|
-
this.rMap.set(routeKey, {
|
|
719
|
-
handler: fn,
|
|
720
|
-
middlewares: [],
|
|
721
|
-
schema: {},
|
|
722
|
-
});
|
|
723
|
-
const route = {
|
|
724
|
-
useMiddleware: (middlewares) => {
|
|
725
|
-
const midds = Array.isArray(middlewares) ? middlewares : [middlewares];
|
|
726
|
-
const ms = midds.map((mclass) => {
|
|
727
|
-
const cls = typedi_1.default.get(mclass);
|
|
728
|
-
this.middlewares.set(mclass.name, cls);
|
|
729
|
-
return cls.invoke;
|
|
730
|
-
});
|
|
731
|
-
const r = this.rMap.get(routeKey);
|
|
732
|
-
if (r) {
|
|
733
|
-
r.middlewares = ms;
|
|
734
|
-
}
|
|
735
|
-
return route;
|
|
736
|
-
},
|
|
737
|
-
useOpenApi: (options) => {
|
|
738
|
-
const r = this.rMap.get(routeKey);
|
|
739
|
-
if (r) {
|
|
740
|
-
r.schema = options;
|
|
741
|
-
}
|
|
742
|
-
return route;
|
|
743
|
-
},
|
|
744
|
-
};
|
|
745
|
-
return route;
|
|
746
|
-
}
|
|
747
|
-
mapGet(path = "", fn) {
|
|
748
|
-
return this._routeHandler(path, "GET", fn);
|
|
749
|
-
}
|
|
750
|
-
mapPost(path = "", fn) {
|
|
751
|
-
return this._routeHandler(path, "POST", fn);
|
|
752
|
-
}
|
|
753
|
-
mapPut(path = "", fn) {
|
|
754
|
-
return this._routeHandler(path, "PUT", fn);
|
|
755
|
-
}
|
|
756
|
-
mapDelete(path = "", fn) {
|
|
757
|
-
return this._routeHandler(path, "DELETE", fn);
|
|
758
|
-
}
|
|
759
|
-
_mapFeatures() {
|
|
760
|
-
const features = typedi_1.default.get("features");
|
|
761
|
-
}
|
|
762
|
-
async initializeDatabase() {
|
|
763
|
-
if (this.dataSourceOptions && this.dataSource) {
|
|
764
|
-
await this.dataSource.initialize();
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
handleSocket(socket) {
|
|
768
|
-
const contextService = typedi_1.default.get(event_dispatcher_1.SocketContextService);
|
|
769
|
-
subscriberRegistry.register(socket);
|
|
770
|
-
// Wrap all future event handlers with context
|
|
771
|
-
const originalOn = socket.on.bind(socket);
|
|
772
|
-
socket.on = (event, handler) => {
|
|
773
|
-
return originalOn(event, (...args) => {
|
|
774
|
-
contextService.run(socket, () => handler(...args));
|
|
775
|
-
});
|
|
776
|
-
};
|
|
777
|
-
}
|
|
778
|
-
async run(port = 4000, fn) {
|
|
779
|
-
if (this.alreadyRun)
|
|
780
|
-
throw new system_exception_1.SystemUseError("App already running");
|
|
781
|
-
this.alreadyRun = true;
|
|
782
|
-
if (this.hasSwagger) {
|
|
783
|
-
await this.initSwagger(this.globalSwaggerOptions);
|
|
784
|
-
}
|
|
785
|
-
await this.initializeDatabase();
|
|
786
|
-
if (this.isMapFeatures) {
|
|
787
|
-
this._mapFeatures();
|
|
788
|
-
}
|
|
789
|
-
if (this.registerControllerAuto) {
|
|
790
|
-
await this.autoControllers();
|
|
791
|
-
}
|
|
792
|
-
await this._mapControllers();
|
|
793
|
-
this.rMap.forEach((value, key) => {
|
|
794
|
-
const [m, r] = key.split(":");
|
|
795
|
-
this.app.route({
|
|
796
|
-
method: m.toUpperCase(),
|
|
797
|
-
url: r,
|
|
798
|
-
schema: value.schema || {},
|
|
799
|
-
preHandler: value.middlewares ? value.middlewares : [],
|
|
800
|
-
handler: async (req, res) => {
|
|
801
|
-
const result = await value.handler.apply(this, [req, res]);
|
|
802
|
-
return result;
|
|
803
|
-
},
|
|
804
|
-
});
|
|
805
|
-
});
|
|
806
|
-
this.app.setErrorHandler((error, request, reply) => {
|
|
807
|
-
if (error instanceof exceptions_1.BaseHttpException) {
|
|
808
|
-
const response = {
|
|
809
|
-
code: error.code,
|
|
810
|
-
status: "Error",
|
|
811
|
-
data: error.payload,
|
|
812
|
-
};
|
|
813
|
-
return reply
|
|
814
|
-
.status(error.code || 500)
|
|
815
|
-
.type("application/json")
|
|
816
|
-
.serializer((payload) => JSON.stringify(payload))
|
|
817
|
-
.send(response);
|
|
818
|
-
}
|
|
819
|
-
return reply.status(500).send({
|
|
820
|
-
code: 500,
|
|
821
|
-
message: error.message || "Internal Server Error",
|
|
822
|
-
...(process.env.NODE_ENV === "development" && { stack: error.stack }),
|
|
823
|
-
});
|
|
824
|
-
});
|
|
825
|
-
await this.app.ready();
|
|
826
|
-
if (this._hasWebsocket) {
|
|
827
|
-
if (!this.app.io) {
|
|
828
|
-
throw new Error("Socket.IO not initialized. Make sure fastify-socket.io is registered correctly.");
|
|
829
|
-
}
|
|
830
|
-
// Register the io instance in Container
|
|
831
|
-
typedi_1.default.set(socket_io_1.Server, this.app.io);
|
|
832
|
-
// Register middleware first
|
|
833
|
-
// await this.app.io.use(
|
|
834
|
-
// (
|
|
835
|
-
// socket: { handshake: { auth: { token: any } }; data: { user: any } },
|
|
836
|
-
// next: any,
|
|
837
|
-
// ) => {
|
|
838
|
-
// const token = socket.handshake.auth.token;
|
|
839
|
-
// try {
|
|
840
|
-
// const user = { id: 1, name: "tareq" };
|
|
841
|
-
// socket.data.user = user; // this powers @AuthUser()
|
|
842
|
-
// next();
|
|
843
|
-
// } catch {
|
|
844
|
-
// next(new Error("Unauthorized"));
|
|
845
|
-
// }
|
|
846
|
-
// },
|
|
847
|
-
// );
|
|
848
|
-
// Then register connection handler
|
|
849
|
-
await this.app.io.on("connection", this.handleSocket.bind(this));
|
|
850
|
-
}
|
|
851
|
-
await this.app.listen({ port });
|
|
852
|
-
console.log(`Application running on http://127.0.0.1:${port}`);
|
|
853
|
-
}
|
|
854
|
-
getTestApp(buildOptions) {
|
|
855
|
-
try {
|
|
856
|
-
this._mapControllers();
|
|
857
|
-
this.rMap.forEach((value, key) => {
|
|
858
|
-
const [m, r] = key.split(":");
|
|
859
|
-
this.app.route({
|
|
860
|
-
method: m.toUpperCase(),
|
|
861
|
-
url: r,
|
|
862
|
-
schema: value.schema || {},
|
|
863
|
-
preHandler: value.middlewares ? value.middlewares : [],
|
|
864
|
-
handler: async (req, res) => {
|
|
865
|
-
const result = await value.handler.apply(this, [req, res]);
|
|
866
|
-
return result;
|
|
867
|
-
},
|
|
868
|
-
});
|
|
869
|
-
});
|
|
870
|
-
this.app.setErrorHandler(async (error, req, res) => {
|
|
871
|
-
const handledErr = this._handleError(error);
|
|
872
|
-
if (error instanceof exceptions_1.ValidationErrorException) {
|
|
873
|
-
return res.status(handledErr.code).send({
|
|
874
|
-
code: handledErr.code,
|
|
875
|
-
error: handledErr.error,
|
|
876
|
-
errors: handledErr.message,
|
|
877
|
-
});
|
|
878
|
-
}
|
|
879
|
-
return res.status(handledErr.code).send(handledErr);
|
|
880
|
-
});
|
|
881
|
-
// return this.app as any;
|
|
882
|
-
//
|
|
883
|
-
return {
|
|
884
|
-
get: async (url, options) => this.app.inject({ method: "GET", url, ...options }),
|
|
885
|
-
post: async (url, options) => this.app.inject({ method: "POST", url, ...options }),
|
|
886
|
-
put: async (url, options) => this.app.inject({ method: "PUT", url, ...options }),
|
|
887
|
-
patch: async (url, options) => this.app.inject({ method: "PATCH", url, ...options }),
|
|
888
|
-
delete: async (url, options) => this.app.inject({ method: "DELETE", url, ...options }),
|
|
889
|
-
options: async (url, options) => this.app.inject({ method: "OPTIONS", url, ...options }),
|
|
890
|
-
getController: (controller, deps = []) => {
|
|
891
|
-
const paramTypes = Reflect.getMetadata("design:paramtypes", controller) || [];
|
|
892
|
-
deps.forEach((dep, i) => {
|
|
893
|
-
typedi_1.default.set(paramTypes[i], dep);
|
|
894
|
-
});
|
|
895
|
-
return typedi_1.default.get(controller);
|
|
896
|
-
},
|
|
897
|
-
};
|
|
898
|
-
}
|
|
899
|
-
catch (error) {
|
|
900
|
-
throw new system_exception_1.SystemUseError("Can't get test appliction");
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
exports.AvleonApplication = AvleonApplication;
|
|
905
|
-
AvleonApplication.buildOptions = {};
|
|
906
|
-
// Applciation Builder
|
|
907
|
-
// export interface ITestBuilder {
|
|
908
|
-
// getTestApplication(): AvleonTestAppliction;
|
|
909
|
-
// createTestApplication(options: any): AvleonTestAppliction;
|
|
910
|
-
// }
|
|
911
|
-
// export interface IAppBuilder {
|
|
912
|
-
// registerPlugin<T extends Function, S extends {}>(
|
|
913
|
-
// plugin: T,
|
|
914
|
-
// options: S,
|
|
915
|
-
// ): Promise<void>;
|
|
916
|
-
// addDataSource<
|
|
917
|
-
// T extends IConfig<R>,
|
|
918
|
-
// R = ReturnType<InstanceType<Constructable<T>>["config"]>,
|
|
919
|
-
// >(
|
|
920
|
-
// ConfigClass: Constructable<T>,
|
|
921
|
-
// modifyConfig?: (config: R) => R,
|
|
922
|
-
// ): void;
|
|
923
|
-
// build<T extends IAvleonApplication>(): T;
|
|
924
|
-
// }
|
|
925
|
-
class AvleonTest {
|
|
926
|
-
constructor() {
|
|
927
|
-
process.env.NODE_ENV = "test";
|
|
928
|
-
}
|
|
929
|
-
static getController(controller, deps = []) {
|
|
930
|
-
const paramTypes = Reflect.getMetadata("design:paramtypes", controller) || [];
|
|
931
|
-
deps.forEach((dep, i) => {
|
|
932
|
-
typedi_1.default.set(paramTypes[i], dep);
|
|
933
|
-
});
|
|
934
|
-
return typedi_1.default.get(controller);
|
|
935
|
-
}
|
|
936
|
-
static getProvider(service, deps = []) {
|
|
937
|
-
const paramTypes = Reflect.getMetadata("design:paramtypes", service) || [];
|
|
938
|
-
deps.forEach((dep, i) => {
|
|
939
|
-
typedi_1.default.set(paramTypes[i], dep);
|
|
940
|
-
});
|
|
941
|
-
return typedi_1.default.get(service);
|
|
942
|
-
}
|
|
943
|
-
static createTestApplication(options) {
|
|
944
|
-
const app = AvleonApplication.getInternalApp({
|
|
945
|
-
dataSourceOptions: options.dataSource ? options.dataSource : null,
|
|
946
|
-
});
|
|
947
|
-
app.useControllers([...options.controllers]);
|
|
948
|
-
return app.getTestApp();
|
|
949
|
-
}
|
|
950
|
-
static from(app) {
|
|
951
|
-
return app.getTestApp();
|
|
952
|
-
}
|
|
953
|
-
static clean() {
|
|
954
|
-
typedi_1.default.reset();
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
exports.AvleonTest = AvleonTest;
|
|
958
|
-
class Avleon {
|
|
959
|
-
static createApplication() {
|
|
960
|
-
const app = AvleonApplication.getApp();
|
|
961
|
-
return app;
|
|
962
|
-
}
|
|
963
|
-
static createTestApplication(options) {
|
|
964
|
-
const app = AvleonTest.createTestApplication(options);
|
|
965
|
-
return app;
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
exports.Avleon = Avleon;
|