diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2d2b47d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +node_modules \ No newline at end of file diff --git a/dist/Application.d.ts b/dist/Application.d.ts new file mode 100644 index 0000000..6e32dfe --- /dev/null +++ b/dist/Application.d.ts @@ -0,0 +1,20 @@ +import WebSocketListener from "./WebSocketListener"; +import ApplicationComponent from "./ApplicationComponent"; +import Controller from "./Controller"; +export default abstract class Application { + private readonly version; + private readonly controllers; + private readonly webSocketListeners; + private readonly components; + private ready; + protected constructor(version: string); + protected abstract init(): Promise; + protected use(thing: Controller | WebSocketListener | ApplicationComponent): void; + start(): Promise; + stop(): Promise; + private routes; + getWebSocketListeners(): { + [p: string]: WebSocketListener; + }; + isReady(): boolean; +} diff --git a/dist/Application.js b/dist/Application.js new file mode 100644 index 0000000..2552ede --- /dev/null +++ b/dist/Application.js @@ -0,0 +1,140 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import express from 'express'; +import { BadRequestError, HttpError, NotFoundHttpError, ServerError, ServiceUnavailableHttpError } from "./HttpError"; +import { lib } from "nunjucks"; +import Logger from "./Logger"; +import WebSocketListener from "./WebSocketListener"; +var TemplateError = lib.TemplateError; +import Controller from "./Controller"; +export default class Application { + constructor(version) { + this.controllers = []; + this.webSocketListeners = {}; + this.components = []; + this.ready = false; + this.version = version; + } + use(thing) { + if (thing instanceof Controller) { + this.controllers.push(thing); + } + else if (thing instanceof WebSocketListener) { + const path = thing.path(); + this.webSocketListeners[path] = thing; + Logger.info(`Added websocket listener on ${path}`); + } + else { + this.components.push(thing); + } + } + start() { + return __awaiter(this, void 0, void 0, function* () { + Logger.info(`${this.constructor.name} v${this.version} - hi`); + process.once('SIGINT', () => { + this.stop().catch(console.error); + }); + // Register all components and alike + yield this.init(); + // Init express + const app = express(); + const router = express.Router({}); + app.use(router); + // Error handler + app.use((err, req, res, next) => { + if (res.headersSent) { + return next(err); + } + let errorID; + let logStr = `${req.method} ${req.originalUrl} - `; + if (err instanceof BadRequestError || err instanceof ServiceUnavailableHttpError) { + logStr += `${err.errorCode} ${err.name}`; + errorID = Logger.silentError(err, logStr); + } + else { + errorID = Logger.error(err, logStr + `500 Internal Error`, err); + } + let httpError; + if (err instanceof HttpError) { + httpError = err; + } + else if (err instanceof TemplateError && err.cause instanceof HttpError) { + httpError = err.cause; + } + else { + httpError = new ServerError('Internal server error.', err); + } + res.status(httpError.errorCode); + res.format({ + html: () => { + res.render('errors/' + httpError.errorCode + '.njk', { + error_code: httpError.errorCode, + error_message: httpError.message, + error_instructions: httpError.instructions, + error_id: errorID, + }); + }, + json: () => { + res.json({ + status: 'error', + code: httpError.errorCode, + message: httpError.message, + instructions: httpError.instructions, + error_id: errorID, + }); + }, + default: () => { + res.type('txt').send(`${httpError.errorCode} - ${httpError.message}\n\n${httpError.instructions}\n\nError ID: ${errorID}`); + } + }); + }); + // Start all components + for (const component of this.components) { + yield component.start(app, router); + } + // Routes + this.routes(router); + this.ready = true; + }); + } + stop() { + return __awaiter(this, void 0, void 0, function* () { + Logger.info('Stopping application...'); + for (const component of this.components) { + yield component.stop(); + } + Logger.info(`${this.constructor.name} v${this.version} - bye`); + }); + } + routes(rootRouter) { + for (const controller of this.controllers) { + if (controller.hasGlobalHandlers()) { + controller.setupGlobalHandlers(rootRouter); + Logger.info(`Registered global middlewares for controller ${controller.constructor.name}`); + } + } + for (const controller of this.controllers) { + const router = express.Router(); + controller.setupRoutes(router); + rootRouter.use(controller.getRoutesPrefix(), router); + Logger.info(`> Registered routes for controller ${controller.constructor.name}`); + } + rootRouter.use((req) => { + throw new NotFoundHttpError('page', req.originalUrl); + }); + } + getWebSocketListeners() { + return this.webSocketListeners; + } + isReady() { + return this.ready; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXBwbGljYXRpb24uanMiLCJzb3VyY2VSb290IjoiLi8iLCJzb3VyY2VzIjpbIkFwcGxpY2F0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBLE9BQU8sT0FBa0QsTUFBTSxTQUFTLENBQUM7QUFDekUsT0FBTyxFQUNILGVBQWUsRUFDZixTQUFTLEVBQ1QsaUJBQWlCLEVBQ2pCLFdBQVcsRUFDWCwyQkFBMkIsRUFDOUIsTUFBTSxhQUFhLENBQUM7QUFDckIsT0FBTyxFQUFDLEdBQUcsRUFBQyxNQUFNLFVBQVUsQ0FBQztBQUM3QixPQUFPLE1BQU0sTUFBTSxVQUFVLENBQUM7QUFDOUIsT0FBTyxpQkFBaUIsTUFBTSxxQkFBcUIsQ0FBQztBQUVwRCxJQUFPLGFBQWEsR0FBRyxHQUFHLENBQUMsYUFBYSxDQUFDO0FBQ3pDLE9BQU8sVUFBVSxNQUFNLGNBQWMsQ0FBQztBQUV0QyxNQUFNLENBQUMsT0FBTyxPQUFnQixXQUFXO0lBUXJDLFlBQXNCLE9BQWU7UUFOcEIsZ0JBQVcsR0FBaUIsRUFBRSxDQUFDO1FBQy9CLHVCQUFrQixHQUF1QyxFQUFFLENBQUM7UUFDNUQsZUFBVSxHQUFnQyxFQUFFLENBQUM7UUFFdEQsVUFBSyxHQUFZLEtBQUssQ0FBQztRQUczQixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztJQUMzQixDQUFDO0lBSVMsR0FBRyxDQUFDLEtBQWlFO1FBQzNFLElBQUksS0FBSyxZQUFZLFVBQVUsRUFBRTtZQUM3QixJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUNoQzthQUFNLElBQUksS0FBSyxZQUFZLGlCQUFpQixFQUFFO1lBQzNDLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUMxQixJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLEdBQUcsS0FBSyxDQUFDO1lBQ3RDLE1BQU0sQ0FBQyxJQUFJLENBQUMsK0JBQStCLElBQUksRUFB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QUFNLENBQUMsSUFBSSxDQUFDLGdEQUFnRCxVQUFVLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7YUFDOUY7U0FDSjtRQUVELEtBQUssTUFBTSxVQUFVLElBQUksSUFBSSxDQUFDLFdBQVcsRUFBRTtZQUN2QyxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDaEMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUMvQixVQUFVLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxlQUFlLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUVyRCxNQUFNLENBQUMsSUFBSSxDQUFDLHNDQUFzQyxVQUFVLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7U0FDcEY7UUFFRCxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBWSxFQUFFLEVBQUU7WUFDNUIsTUFBTSxJQUFJLGlCQUFpQixDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDekQsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRU0scUJBQXFCO1FBQ3hCLE9BQU8sSUFBSSxDQUFDLGtCQUFrQixDQUFDO0lBQ25DLENBQUM7SUFFTSxPQUFPO1FBQ1YsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDO0lBQ3RCLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBleHByZXNzLCB7TmV4dEZ1bmN0aW9uLCBSZXF1ZXN0LCBSZXNwb25zZSwgUm91dGVyfSBmcm9tICdleHByZXNzJztcbmltcG9ydCB7XG4gICAgQmFkUmVxdWVzdEVycm9yLFxuICAgIEh0dHBFcnJvcixcbiAgICBOb3RGb3VuZEh0dHBFcnJvcixcbiAgICBTZXJ2ZXJFcnJvcixcbiAgICBTZXJ2aWNlVW5hdmFpbGFibGVIdHRwRXJyb3Jcbn0gZnJvbSBcIi4vSHR0cEVycm9yXCI7XG5pbXBvcnQge2xpYn0gZnJvbSBcIm51bmp1Y2tzXCI7XG5pbXBvcnQgTG9nZ2VyIGZyb20gXCIuL0xvZ2dlclwiO1xuaW1wb3J0IFdlYlNvY2tldExpc3RlbmVyIGZyb20gXCIuL1dlYlNvY2tldExpc3RlbmVyXCI7XG5pbXBvcnQgQXBwbGljYXRpb25Db21wb25lbnQgZnJvbSBcIi4vQXBwbGljYXRpb25Db21wb25lbnRcIjtcbmltcG9ydCBUZW1wbGF0ZUVycm9yID0gbGliLlRlbXBsYXRlRXJyb3I7XG5pbXBvcnQgQ29udHJvbGxlciBmcm9tIFwiLi9Db250cm9sbGVyXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGFic3RyYWN0IGNsYXNzIEFwcGxpY2F0aW9uIHtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHZlcnNpb246IHN0cmluZztcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNvbnRyb2xsZXJzOiBDb250cm9sbGVyW10gPSBbXTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHdlYlNvY2tldExpc3RlbmVyczogeyBbcDogc3RyaW5nXTogV2ViU29ja2V0TGlzdGVuZXIgfSA9IHt9O1xuICAgIHByaXZhdGUgcmVhZG9ubHkgY29tcG9uZW50czogQXBwbGljYXRpb25Db21wb25lbnQ8YW55PltdID0gW107XG5cbiAgICBwcml2YXRlIHJlYWR5OiBib29sZWFuID0gZmFsc2U7XG5cbiAgICBwcm90ZWN0ZWQgY29uc3RydWN0b3IodmVyc2lvbjogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMudmVyc2lvbiA9IHZlcnNpb247XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IGFzeW5jIGluaXQoKTogUHJvbWlzZTx2b2lkPjtcblxuICAgIHByb3RlY3RlZCB1c2UodGhpbmc6IENvbnRyb2xsZXIgfCBXZWJTb2NrZXRMaXN0ZW5lciB8IEFwcGxpY2F0aW9uQ29tcG9uZW50PGFueT4pIHtcbiAgICAgICAgaWYgKHRoaW5nIGluc3RhbmNlb2YgQ29udHJvbGxlcikge1xuICAgICAgICAgICAgdGhpcy5jb250cm9sbGVycy5wdXNoKHRoaW5nKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGluZyBpbnN0YW5jZW9mIFdlYlNvY2tldExpc3RlbmVyKSB7XG4gICAgICAgICAgICBjb25zdCBwYXRoID0gdGhpbmcucGF0aCgpO1xuICAgICAgICAgICAgdGhpcy53ZWJTb2NrZXRMaXN0ZW5lcnNbcGF0aF0gPSB0aGluZztcbiAgICAgICAgICAgIExvZ2dlci5pbmZvKGBBZGRlZCB3ZWJzb2NrZXQgbGlzdGVuZXIgb24gJHtwYXRofWApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5jb21wb25lbnRzLnB1c2godGhpbmcpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHN0YXJ0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBMb2dnZXIuaW5mbyhgJHt0aGlzLmNvbnN0cnVjdG9yLm5hbWV9IHYke3RoaXMudmVyc2lvbn0gLSBoaWApO1xuICAgICAgICBwcm9jZXNzLm9uY2UoJ1NJR0lOVCcsICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc3RvcCgpLmNhdGNoKGNvbnNvbGUuZXJyb3IpO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBSZWdpc3RlciBhbGwgY29tcG9uZW50cyBhbmQgYWxpa2VcbiAgICAgICAgYXdhaXQgdGhpcy5pbml0KCk7XG5cbiAgICAgICAgLy8gSW5pdCBleHByZXNzXG4gICAgICAgIGNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcbiAgICAgICAgY29uc3Qgcm91dGVyID0gZXhwcmVzcy5Sb3V0ZXIoe30pO1xuICAgICAgICBhcHAudXNlKHJvdXRlcik7XG5cbiAgICAgICAgLy8gRXJyb3IgaGFuZGxlclxuICAgICAgICBhcHAudXNlKChlcnI6IGFueSwgcmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pID0+IHtcbiAgICAgICAgICAgIGlmIChyZXMuaGVhZGVyc1NlbnQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV4dChlcnIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsZXQgZXJyb3JJRDogc3RyaW5nO1xuXG4gICAgICAgICAgICBsZXQgbG9nU3RyID0gYCR7cmVxLm1ldGhvZH0gJHtyZXEub3JpZ2luYWxVcmx9IC0gYDtcbiAgICAgICAgICAgIGlmIChlcnIgaW5zdGFuY2VvZiBCYWRSZXF1ZXN0RXJyb3IgfHwgZXJyIGluc3RhbmNlb2YgU2VydmljZVVuYXZhaWxhYmxlSHR0cEVycm9yKSB7XG4gICAgICAgICAgICAgICAgbG9nU3RyICs9IGAke2Vyci5lcnJvckNvZGV9ICR7ZXJyLm5hbWV9YDtcbiAgICAgICAgICAgICAgICBlcnJvcklEID0gTG9nZ2VyLnNpbGVudEVycm9yKGVyciwgbG9nU3RyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZXJyb3JJRCA9IExvZ2dlci5lcnJvcihlcnIsIGxvZ1N0ciArIGA1MDAgSW50ZXJuYWwgRXJyb3JgLCBlcnIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsZXQgaHR0cEVycm9yOiBIdHRwRXJyb3I7XG5cbiAgICAgICAgICAgIGlmIChlcnIgaW5zdGFuY2VvZiBIdHRwRXJyb3IpIHtcbiAgICAgICAgICAgICAgICBodHRwRXJyb3IgPSBlcnI7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGVyciBpbnN0YW5jZW9mIFRlbXBsYXRlRXJyb3IgJiYgZXJyLmNhdXNlIGluc3RhbmNlb2YgSHR0cEVycm9yKSB7XG4gICAgICAgICAgICAgICAgaHR0cEVycm9yID0gZXJyLmNhdXNlO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBodHRwRXJyb3IgPSBuZXcgU2VydmVyRXJyb3IoJ0ludGVybmFsIHNlcnZlciBlcnJvci4nLCBlcnIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXMuc3RhdHVzKGh0dHBFcnJvci5lcnJvckNvZGUpO1xuICAgICAgICAgICAgcmVzLmZvcm1hdCh7XG4gICAgICAgICAgICAgICAgaHRtbDogKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICByZXMucmVuZGVyKCdlcnJvcnMvJyArIGh0dHBFcnJvci5lcnJvckNvZGUgKyAnLm5qaycsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yX2NvZGU6IGh0dHBFcnJvci5lcnJvckNvZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvcl9tZXNzYWdlOiBodHRwRXJyb3IubWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yX2luc3RydWN0aW9uczogaHR0cEVycm9yLmluc3RydWN0aW9ucyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yX2lkOiBlcnJvcklELFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGpzb246ICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgcmVzLmpzb24oe1xuICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzOiAnZXJyb3InLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29kZTogaHR0cEVycm9yLmVycm9yQ29kZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGh0dHBFcnJvci5tZXNzYWdlLFxuICAgICAgICAgICAgICAgICAgICAgICAgaW5zdHJ1Y3Rpb25zOiBodHRwRXJyb3IuaW5zdHJ1Y3Rpb25zLFxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JfaWQ6IGVycm9ySUQsXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICByZXMudHlwZSgndHh0Jykuc2VuZChgJHtodHRwRXJyb3IuZXJyb3JDb2RlfSAtICR7aHR0cEVycm9yLm1lc3NhZ2V9XFxuXFxuJHtodHRwRXJyb3IuaW5zdHJ1Y3Rpb25zfVxcblxcbkVycm9yIElEOiAke2Vycm9ySUR9YCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIFN0YXJ0IGFsbCBjb21wb25lbnRzXG4gICAgICAgIGZvciAoY29uc3QgY29tcG9uZW50IG9mIHRoaXMuY29tcG9uZW50cykge1xuICAgICAgICAgICAgYXdhaXQgY29tcG9uZW50LnN0YXJ0KGFwcCwgcm91dGVyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFJvdXRlc1xuICAgICAgICB0aGlzLnJvdXRlcyhyb3V0ZXIpO1xuXG4gICAgICAgIHRoaXMucmVhZHkgPSB0cnVlO1xuICAgIH1cblxuICAgIGFzeW5jIHN0b3AoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIExvZ2dlci5pbmZvKCdTdG9wcGluZyBhcHBsaWNhdGlvbi4uLicpO1xuXG4gICAgICAgIGZvciAoY29uc3QgY29tcG9uZW50IG9mIHRoaXMuY29tcG9uZW50cykge1xuICAgICAgICAgICAgYXdhaXQgY29tcG9uZW50LnN0b3AoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIExvZ2dlci5pbmZvKGAke3RoaXMuY29uc3RydWN0b3IubmFtZX0gdiR7dGhpcy52ZXJzaW9ufSAtIGJ5ZWApO1xuICAgIH1cblxuICAgIHByaXZhdGUgcm91dGVzKHJvb3RSb3V0ZXI6IFJvdXRlcikge1xuICAgICAgICBmb3IgKGNvbnN0IGNvbnRyb2xsZXIgb2YgdGhpcy5jb250cm9sbGVycykge1xuICAgICAgICAgICAgaWYgKGNvbnRyb2xsZXIuaGFzR2xvYmFsSGFuZGxlcnMoKSkge1xuICAgICAgICAgICAgICAgIGNvbnRyb2xsZXIuc2V0dXBHbG9iYWxIYW5kbGVycyhyb290Um91dGVyKTtcblxuICAgICAgICAgICAgICAgIExvZ2dlci5pbmZvKGBSZWdpc3RlcmVkIGdsb2JhbCBtaWRkbGV3YXJlcyBmb3IgY29udHJvbGxlciAke2NvbnRyb2xsZXIuY29uc3RydWN0b3IubmFtZX1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGZvciAoY29uc3QgY29udHJvbGxlciBvZiB0aGlzLmNvbnRyb2xsZXJzKSB7XG4gICAgICAgICAgICBjb25zdCByb3V0ZXIgPSBleHByZXNzLlJvdXRlcigpO1xuICAgICAgICAgICAgY29udHJvbGxlci5zZXR1cFJvdXRlcyhyb3V0ZXIpO1xuICAgICAgICAgICAgcm9vdFJvdXRlci51c2UoY29udHJvbGxlci5nZXRSb3V0ZXNQcmVmaXgoKSwgcm91dGVyKTtcblxuICAgICAgICAgICAgTG9nZ2VyLmluZm8oYD4gUmVnaXN0ZXJlZCByb3V0ZXMgZm9yIGNvbnRyb2xsZXIgJHtjb250cm9sbGVyLmNvbnN0cnVjdG9yLm5hbWV9YCk7XG4gICAgICAgIH1cblxuICAgICAgICByb290Um91dGVyLnVzZSgocmVxOiBSZXF1ZXN0KSA9PiB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgTm90Rm91bmRIdHRwRXJyb3IoJ3BhZ2UnLCByZXEub3JpZ2luYWxVcmwpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0V2ViU29ja2V0TGlzdGVuZXJzKCk6IHsgW3A6IHN0cmluZ106IFdlYlNvY2tldExpc3RlbmVyIH0ge1xuICAgICAgICByZXR1cm4gdGhpcy53ZWJTb2NrZXRMaXN0ZW5lcnM7XG4gICAgfVxuXG4gICAgcHVibGljIGlzUmVhZHkoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnJlYWR5O1xuICAgIH1cbn0iXX0= \ No newline at end of file diff --git a/dist/ApplicationComponent.d.ts b/dist/ApplicationComponent.d.ts new file mode 100644 index 0000000..3b7d47a --- /dev/null +++ b/dist/ApplicationComponent.d.ts @@ -0,0 +1,10 @@ +import { Express, Router } from "express"; +export default abstract class ApplicationComponent { + private val?; + abstract start(app: Express, router: Router): Promise; + abstract stop(): Promise; + protected export(val: T): void; + import(): T; + protected prepare(name: string, prepare: () => Promise): Promise; + protected close(thingName: string, thing: any, fn: Function): Promise; +} diff --git a/dist/ApplicationComponent.js b/dist/ApplicationComponent.js new file mode 100644 index 0000000..f102212 --- /dev/null +++ b/dist/ApplicationComponent.js @@ -0,0 +1,55 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import Logger from "./Logger"; +import { sleep } from "./Utils"; +export default class ApplicationComponent { + export(val) { + this.val = val; + } + import() { + if (!this.val) + throw 'Cannot import if nothing was exported.'; + return this.val; + } + prepare(name, prepare) { + return __awaiter(this, void 0, void 0, function* () { + let err; + do { + try { + yield prepare(); + err = null; + } + catch (e) { + err = e; + Logger.error(err, `${name} failed to prepare; retrying in 5s...`); + yield sleep(5000); + } + } while (err); + Logger.info(`${name} ready!`); + }); + } + close(thingName, thing, fn) { + return __awaiter(this, void 0, void 0, function* () { + try { + yield new Promise((resolve, reject) => fn.call(thing, (err) => { + if (err) + reject(err); + else + resolve(); + })); + Logger.info(`${thingName} closed.`); + } + catch (e) { + Logger.error(e, `An error occurred while closing the ${thingName}.`); + } + }); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXBwbGljYXRpb25Db21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiLi8iLCJzb3VyY2VzIjpbIkFwcGxpY2F0aW9uQ29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUNBLE9BQU8sTUFBTSxNQUFNLFVBQVUsQ0FBQztBQUM5QixPQUFPLEVBQUMsS0FBSyxFQUFDLE1BQU0sU0FBUyxDQUFDO0FBRTlCLE1BQU0sQ0FBQyxPQUFPLE9BQWdCLG9CQUFvQjtJQU9wQyxNQUFNLENBQUMsR0FBTTtRQUNuQixJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQztJQUNuQixDQUFDO0lBRU0sTUFBTTtRQUNULElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRztZQUFFLE1BQU0sd0NBQXdDLENBQUM7UUFDOUQsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDO0lBQ3BCLENBQUM7SUFFZSxPQUFPLENBQUMsSUFBWSxFQUFFLE9BQTRCOztZQUM5RCxJQUFJLEdBQUcsQ0FBQztZQUNSLEdBQUc7Z0JBQ0MsSUFBSTtvQkFDQSxNQUFNLE9BQU8sRUFBRSxDQUFDO29CQUNoQixHQUFHLEdBQUcsSUFBSSxDQUFDO2lCQUNkO2dCQUFDLE9BQU8sQ0FBQyxFQUFFO29CQUNSLEdBQUcsR0FBRyxDQUFDLENBQUM7b0JBQ1IsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLHVDQUF1QyxDQUFDLENBQUE7b0JBQ2pFLE1BQU0sS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO2lCQUNyQjthQUNKLFFBQVEsR0FBRyxFQUFFO1lBQ2QsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksU0FBUyxDQUFDLENBQUM7UUFDbEMsQ0FBQztLQUFBO0lBRWUsS0FBSyxDQUFDLFNBQWlCLEVBQUUsS0FBVSxFQUFFLEVBQVk7O1lBQzdELElBQUk7Z0JBQ0EsTUFBTSxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUMsR0FBUSxFQUFFLEVBQUU7b0JBQy9ELElBQUksR0FBRzt3QkFBRSxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7O3dCQUNoQixPQUFPLEVBQUUsQ0FBQztnQkFDbkIsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFFSixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsU0FBUyxVQUFVLENBQUMsQ0FBQzthQUN2QztZQUFDLE9BQU8sQ0FBQyxFQUFFO2dCQUNSLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLHVDQUF1QyxTQUFTLEdBQUcsQ0FBQyxDQUFDO2FBQ3hFO1FBQ0wsQ0FBQztLQUFBO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0V4cHJlc3MsIFJvdXRlcn0gZnJvbSBcImV4cHJlc3NcIjtcbmltcG9ydCBMb2dnZXIgZnJvbSBcIi4vTG9nZ2VyXCI7XG5pbXBvcnQge3NsZWVwfSBmcm9tIFwiLi9VdGlsc1wiO1xuXG5leHBvcnQgZGVmYXVsdCBhYnN0cmFjdCBjbGFzcyBBcHBsaWNhdGlvbkNvbXBvbmVudDxUPiB7XG4gICAgcHJpdmF0ZSB2YWw/OiBUO1xuXG4gICAgcHVibGljIGFic3RyYWN0IGFzeW5jIHN0YXJ0KGFwcDogRXhwcmVzcywgcm91dGVyOiBSb3V0ZXIpOiBQcm9taXNlPHZvaWQ+O1xuXG4gICAgcHVibGljIGFic3RyYWN0IGFzeW5jIHN0b3AoKTogUHJvbWlzZTx2b2lkPjtcblxuICAgIHByb3RlY3RlZCBleHBvcnQodmFsOiBUKSB7XG4gICAgICAgIHRoaXMudmFsID0gdmFsO1xuICAgIH1cblxuICAgIHB1YmxpYyBpbXBvcnQoKTogVCB7XG4gICAgICAgIGlmICghdGhpcy52YWwpIHRocm93ICdDYW5ub3QgaW1wb3J0IGlmIG5vdGhpbmcgd2FzIGV4cG9ydGVkLic7XG4gICAgICAgIHJldHVybiB0aGlzLnZhbDtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYXN5bmMgcHJlcGFyZShuYW1lOiBzdHJpbmcsIHByZXBhcmU6ICgpID0+IFByb21pc2U8dm9pZD4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgbGV0IGVycjtcbiAgICAgICAgZG8ge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBhd2FpdCBwcmVwYXJlKCk7XG4gICAgICAgICAgICAgICAgZXJyID0gbnVsbDtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBlcnIgPSBlO1xuICAgICAgICAgICAgICAgIExvZ2dlci5lcnJvcihlcnIsIGAke25hbWV9IGZhaWxlZCB0byBwcmVwYXJlOyByZXRyeWluZyBpbiA1cy4uLmApXG4gICAgICAgICAgICAgICAgYXdhaXQgc2xlZXAoNTAwMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gd2hpbGUgKGVycik7XG4gICAgICAgIExvZ2dlci5pbmZvKGAke25hbWV9IHJlYWR5IWApO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBhc3luYyBjbG9zZSh0aGluZ05hbWU6IHN0cmluZywgdGhpbmc6IGFueSwgZm46IEZ1bmN0aW9uKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiBmbi5jYWxsKHRoaW5nLCAoZXJyOiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyKSByZWplY3QoZXJyKTtcbiAgICAgICAgICAgICAgICBlbHNlIHJlc29sdmUoKTtcbiAgICAgICAgICAgIH0pKTtcblxuICAgICAgICAgICAgTG9nZ2VyLmluZm8oYCR7dGhpbmdOYW1lfSBjbG9zZWQuYCk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIExvZ2dlci5lcnJvcihlLCBgQW4gZXJyb3Igb2NjdXJyZWQgd2hpbGUgY2xvc2luZyB0aGUgJHt0aGluZ05hbWV9LmApO1xuICAgICAgICB9XG4gICAgfVxufSJdfQ== \ No newline at end of file diff --git a/dist/Controller.d.ts b/dist/Controller.d.ts new file mode 100644 index 0000000..af0b6df --- /dev/null +++ b/dist/Controller.d.ts @@ -0,0 +1,21 @@ +import { RequestHandler, Router } from "express"; +import { PathParams } from "express-serve-static-core"; +export default abstract class Controller { + private static readonly routes; + static route(route: string, params?: RouteParams, absolute?: boolean): string; + private router?; + getGlobalHandlers(): RequestHandler[]; + hasGlobalHandlers(): boolean; + setupGlobalHandlers(router: Router): void; + getRoutesPrefix(): string; + abstract routes(): void; + setupRoutes(router: Router): void; + protected use(handler: RequestHandler): void; + protected get(path: PathParams, handler: RequestHandler, routeName?: string, ...middlewares: RequestHandler[]): void; + protected post(path: PathParams, handler: RequestHandler, routeName?: string, ...middlewares: RequestHandler[]): void; + private wrap; + private registerRoutes; +} +export declare type RouteParams = { + [p: string]: string; +} | string[] | string | number; diff --git a/dist/Controller.js b/dist/Controller.js new file mode 100644 index 0000000..a605402 --- /dev/null +++ b/dist/Controller.js @@ -0,0 +1,104 @@ +import config from "config"; +import Logger from "./Logger"; +export default class Controller { + static route(route, params = [], absolute = false) { + let path = this.routes[route]; + if (path === undefined) + throw new Error(`Unknown route for name ${route}.`); + if (typeof params === 'string' || typeof params === 'number') { + path = path.replace(/:[a-zA-Z_-]+\??/, '' + params); + } + else if (Array.isArray(params)) { + let i = 0; + for (const match of path.matchAll(/:[a-zA-Z_-]+\??/)) { + if (match.length > 0) { + path = path.replace(match[0], typeof params[i] !== 'undefined' ? params[i] : ''); + } + i++; + } + path = path.replace(/\/+/, '/'); + } + else { + for (const key in params) { + if (params.hasOwnProperty(key)) { + path = path.replace(new RegExp(`:${key}\\??`), params[key]); + } + } + } + return `${absolute ? config.get('public_url') : ''}${path}`; + } + getGlobalHandlers() { + return []; + } + hasGlobalHandlers() { + return this.getGlobalHandlers().length > 0; + } + setupGlobalHandlers(router) { + for (const globalHandler of this.getGlobalHandlers()) { + router.use(this.wrap(globalHandler)); + } + } + getRoutesPrefix() { + return '/'; + } + setupRoutes(router) { + this.router = router; + this.routes(); + } + use(handler) { + var _a; + (_a = this.router) === null || _a === void 0 ? void 0 : _a.use(this.wrap(handler)); + } + get(path, handler, routeName, ...middlewares) { + var _a, _b; + this.registerRoutes(path, handler, routeName); + for (const middleware of middlewares) { + (_a = this.router) === null || _a === void 0 ? void 0 : _a.get(path, this.wrap(middleware)); + } + (_b = this.router) === null || _b === void 0 ? void 0 : _b.get(path, this.wrap(handler)); + } + post(path, handler, routeName, ...middlewares) { + var _a, _b; + this.registerRoutes(path, handler, routeName); + for (const middleware of middlewares) { + (_a = this.router) === null || _a === void 0 ? void 0 : _a.post(path, this.wrap(middleware)); + } + (_b = this.router) === null || _b === void 0 ? void 0 : _b.post(path, this.wrap(handler)); + } + wrap(handler) { + return (req, res, next) => { + const promise = handler.call(this, req, res, next); + if (promise instanceof Promise) { + promise.catch(err => next(err)); + } + }; + } + registerRoutes(path, handler, routeName) { + if (typeof routeName !== 'string') { + routeName = handler.name + .replace(/(?:^|\.?)([A-Z])/g, (x, y) => '_' + y.toLowerCase()) + .replace(/(^_|get_|post_)/g, ''); + } + if (routeName.length === 0) + return; + let routePath = null; + if (path instanceof Array && path.length > 0) { + path = path[0]; + } + if (typeof path === 'string') { + const prefix = this.getRoutesPrefix(); + routePath = (prefix !== '/' ? prefix : '') + path; + } + if (!Controller.routes[routeName]) { + if (typeof routePath === 'string') { + Logger.info(`Route ${routeName} has path ${routePath}`); + Controller.routes[routeName] = routePath; + } + else { + Logger.warn(`Cannot assign path to route ${routeName}.`); + } + } + } +} +Controller.routes = {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29udHJvbGxlci5qcyIsInNvdXJjZVJvb3QiOiIuLyIsInNvdXJjZXMiOlsiQ29udHJvbGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFDNUIsT0FBTyxNQUFNLE1BQU0sVUFBVSxDQUFDO0FBRTlCLE1BQU0sQ0FBQyxPQUFPLE9BQWdCLFVBQVU7SUFHN0IsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFhLEVBQUUsU0FBc0IsRUFBRSxFQUFFLFdBQW9CLEtBQUs7UUFDbEYsSUFBSSxJQUFJLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM5QixJQUFJLElBQUksS0FBSyxTQUFTO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQywwQkFBMEIsS0FBSyxHQUFHLENBQUMsQ0FBQztRQUU1RSxJQUFJLE9BQU8sTUFBTSxLQUFLLFFBQVEsSUFBSSxPQUFPLE1BQU0sS0FBSyxRQUFRLEVBQUU7WUFDMUQsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsaUJBQWlCLEVBQUUsRUFBRSxHQUFHLE1BQU0sQ0FBQyxDQUFDO1NBQ3ZEO2FBQU0sSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFO1lBQzlCLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNWLEtBQUssTUFBTSxLQUFLLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFO2dCQUNsRCxJQUFJLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO29CQUNsQixJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLEtBQUssV0FBVyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO2lCQUNwRjtnQkFDRCxDQUFDLEVBQUUs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QUN4RCxVQUFVLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxHQUFHLFNBQVMsQ0FBQzthQUM1QztpQkFBTTtnQkFDSCxNQUFNLENBQUMsSUFBSSxDQUFDLCtCQUErQixTQUFTLEdBQUcsQ0FBQyxDQUFDO2FBQzVEO1NBQ0o7SUFDTCxDQUFDOztBQTlHdUIsaUJBQU0sR0FBNEIsRUFBRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtSZXF1ZXN0SGFuZGxlciwgUm91dGVyfSBmcm9tIFwiZXhwcmVzc1wiO1xuaW1wb3J0IHtQYXRoUGFyYW1zfSBmcm9tIFwiZXhwcmVzcy1zZXJ2ZS1zdGF0aWMtY29yZVwiO1xuaW1wb3J0IGNvbmZpZyBmcm9tIFwiY29uZmlnXCI7XG5pbXBvcnQgTG9nZ2VyIGZyb20gXCIuL0xvZ2dlclwiO1xuXG5leHBvcnQgZGVmYXVsdCBhYnN0cmFjdCBjbGFzcyBDb250cm9sbGVyIHtcbiAgICBwcml2YXRlIHN0YXRpYyByZWFkb25seSByb3V0ZXM6IHsgW3A6IHN0cmluZ106IHN0cmluZyB9ID0ge307XG5cbiAgICBwdWJsaWMgc3RhdGljIHJvdXRlKHJvdXRlOiBzdHJpbmcsIHBhcmFtczogUm91dGVQYXJhbXMgPSBbXSwgYWJzb2x1dGU6IGJvb2xlYW4gPSBmYWxzZSk6IHN0cmluZyB7XG4gICAgICAgIGxldCBwYXRoID0gdGhpcy5yb3V0ZXNbcm91dGVdO1xuICAgICAgICBpZiAocGF0aCA9PT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gcm91dGUgZm9yIG5hbWUgJHtyb3V0ZX0uYCk7XG5cbiAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnIHx8IHR5cGVvZiBwYXJhbXMgPT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICBwYXRoID0gcGF0aC5yZXBsYWNlKC86W2EtekEtWl8tXStcXD8/LywgJycgKyBwYXJhbXMpO1xuICAgICAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkocGFyYW1zKSkge1xuICAgICAgICAgICAgbGV0IGkgPSAwO1xuICAgICAgICAgICAgZm9yIChjb25zdCBtYXRjaCBvZiBwYXRoLm1hdGNoQWxsKC86W2EtekEtWl8tXStcXD8/LykpIHtcbiAgICAgICAgICAgICAgICBpZiAobWF0Y2gubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICBwYXRoID0gcGF0aC5yZXBsYWNlKG1hdGNoWzBdLCB0eXBlb2YgcGFyYW1zW2ldICE9PSAndW5kZWZpbmVkJyA/IHBhcmFtc1tpXSA6ICcnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaSsrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcGF0aCA9IHBhdGgucmVwbGFjZSgvXFwvKy8sICcvJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGtleSBpbiBwYXJhbXMpIHtcbiAgICAgICAgICAgICAgICBpZiAocGFyYW1zLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcGF0aCA9IHBhdGgucmVwbGFjZShuZXcgUmVnRXhwKGA6JHtrZXl9XFxcXD8/YCksIHBhcmFtc1trZXldKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYCR7YWJzb2x1dGUgPyBjb25maWcuZ2V0PHN0cmluZz4oJ3B1YmxpY191cmwnKSA6ICcnfSR7cGF0aH1gO1xuICAgIH1cblxuICAgIHByaXZhdGUgcm91dGVyPzogUm91dGVyO1xuXG4gICAgcHVibGljIGdldEdsb2JhbEhhbmRsZXJzKCk6IFJlcXVlc3RIYW5kbGVyW10ge1xuICAgICAgICByZXR1cm4gW107XG4gICAgfVxuXG4gICAgcHVibGljIGhhc0dsb2JhbEhhbmRsZXJzKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRHbG9iYWxIYW5kbGVycygpLmxlbmd0aCA+IDA7XG4gICAgfVxuXG4gICAgcHVibGljIHNldHVwR2xvYmFsSGFuZGxlcnMocm91dGVyOiBSb3V0ZXIpOiB2b2lkIHtcbiAgICAgICAgZm9yIChjb25zdCBnbG9iYWxIYW5kbGVyIG9mIHRoaXMuZ2V0R2xvYmFsSGFuZGxlcnMoKSkge1xuICAgICAgICAgICAgcm91dGVyLnVzZSh0aGlzLndyYXAoZ2xvYmFsSGFuZGxlcikpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIGdldFJvdXRlc1ByZWZpeCgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gJy8nO1xuICAgIH1cblxuICAgIHB1YmxpYyBhYnN0cmFjdCByb3V0ZXMoKTogdm9pZDtcblxuICAgIHB1YmxpYyBzZXR1cFJvdXRlcyhyb3V0ZXI6IFJvdXRlcik6IHZvaWQge1xuICAgICAgICB0aGlzLnJvdXRlciA9IHJvdXRlcjtcbiAgICAgICAgdGhpcy5yb3V0ZXMoKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgdXNlKGhhbmRsZXI6IFJlcXVlc3RIYW5kbGVyKSB7XG4gICAgICAgIHRoaXMucm91dGVyPy51c2UodGhpcy53cmFwKGhhbmRsZXIpKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgZ2V0KHBhdGg6IFBhdGhQYXJhbXMsIGhhbmRsZXI6IFJlcXVlc3RIYW5kbGVyLCByb3V0ZU5hbWU/OiBzdHJpbmcsIC4uLm1pZGRsZXdhcmVzOiBSZXF1ZXN0SGFuZGxlcltdKSB7XG4gICAgICAgIHRoaXMucmVnaXN0ZXJSb3V0ZXMocGF0aCwgaGFuZGxlciwgcm91dGVOYW1lKTtcbiAgICAgICAgZm9yIChjb25zdCBtaWRkbGV3YXJlIG9mIG1pZGRsZXdhcmVzKSB7XG4gICAgICAgICAgICB0aGlzLnJvdXRlcj8uZ2V0KHBhdGgsIHRoaXMud3JhcChtaWRkbGV3YXJlKSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5yb3V0ZXI/LmdldChwYXRoLCB0aGlzLndyYXAoaGFuZGxlcikpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBwb3N0KHBhdGg6IFBhdGhQYXJhbXMsIGhhbmRsZXI6IFJlcXVlc3RIYW5kbGVyLCByb3V0ZU5hbWU/OiBzdHJpbmcsIC4uLm1pZGRsZXdhcmVzOiBSZXF1ZXN0SGFuZGxlcltdKSB7XG4gICAgICAgIHRoaXMucmVnaXN0ZXJSb3V0ZXMocGF0aCwgaGFuZGxlciwgcm91dGVOYW1lKTtcbiAgICAgICAgZm9yIChjb25zdCBtaWRkbGV3YXJlIG9mIG1pZGRsZXdhcmVzKSB7XG4gICAgICAgICAgICB0aGlzLnJvdXRlcj8ucG9zdChwYXRoLCB0aGlzLndyYXAobWlkZGxld2FyZSkpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucm91dGVyPy5wb3N0KHBhdGgsIHRoaXMud3JhcChoYW5kbGVyKSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSB3cmFwKGhhbmRsZXI6IFJlcXVlc3RIYW5kbGVyKTogUmVxdWVzdEhhbmRsZXIge1xuICAgICAgICByZXR1cm4gKHJlcSwgcmVzLCBuZXh0KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBwcm9taXNlID0gaGFuZGxlci5jYWxsKHRoaXMsIHJlcSwgcmVzLCBuZXh0KTtcbiAgICAgICAgICAgIGlmIChwcm9taXNlIGluc3RhbmNlb2YgUHJvbWlzZSkge1xuICAgICAgICAgICAgICAgIHByb21pc2UuY2F0Y2goZXJyID0+IG5leHQoZXJyKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSByZWdpc3RlclJvdXRlcyhwYXRoOiBQYXRoUGFyYW1zLCBoYW5kbGVyOiBSZXF1ZXN0SGFuZGxlciwgcm91dGVOYW1lPzogc3RyaW5nKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygcm91dGVOYW1lICE9PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgcm91dGVOYW1lID0gaGFuZGxlci5uYW1lXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLyg/Ol58XFwuPykoW0EtWl0pL2csICh4LCB5KSA9PiAnXycgKyB5LnRvTG93ZXJDYXNlKCkpXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLyheX3xnZXRffHBvc3RfKS9nLCAnJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocm91dGVOYW1lLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuXG4gICAgICAgIGxldCByb3V0ZVBhdGggPSBudWxsO1xuICAgICAgICBpZiAocGF0aCBpbnN0YW5jZW9mIEFycmF5ICYmIHBhdGgubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgcGF0aCA9IHBhdGhbMF07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHR5cGVvZiBwYXRoID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgY29uc3QgcHJlZml4ID0gdGhpcy5nZXRSb3V0ZXNQcmVmaXgoKTtcbiAgICAgICAgICAgIHJvdXRlUGF0aCA9IChwcmVmaXggIT09ICcvJyA/IHByZWZpeCA6ICcnKSArIHBhdGg7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIUNvbnRyb2xsZXIucm91dGVzW3JvdXRlTmFtZV0pIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygcm91dGVQYXRoID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIExvZ2dlci5pbmZvKGBSb3V0ZSAke3JvdXRlTmFtZX0gaGFzIHBhdGggJHtyb3V0ZVBhdGh9YCk7XG4gICAgICAgICAgICAgICAgQ29udHJvbGxlci5yb3V0ZXNbcm91dGVOYW1lXSA9IHJvdXRlUGF0aDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgTG9nZ2VyLndhcm4oYENhbm5vdCBhc3NpZ24gcGF0aCB0byByb3V0ZSAke3JvdXRlTmFtZX0uYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmV4cG9ydCB0eXBlIFJvdXRlUGFyYW1zID0geyBbcDogc3RyaW5nXTogc3RyaW5nIH0gfCBzdHJpbmdbXSB8IHN0cmluZyB8IG51bWJlcjsiXX0= \ No newline at end of file diff --git a/dist/HttpError.d.ts b/dist/HttpError.d.ts new file mode 100644 index 0000000..b6e6831 --- /dev/null +++ b/dist/HttpError.d.ts @@ -0,0 +1,28 @@ +import { WrappingError } from "./Utils"; +export declare abstract class HttpError extends WrappingError { + readonly instructions: string; + constructor(message: string, instructions: string, cause?: Error); + get name(): string; + abstract get errorCode(): number; +} +export declare class BadRequestError extends HttpError { + readonly url: string; + constructor(message: string, instructions: string, url: string, cause?: Error); + get errorCode(): number; +} +export declare class ForbiddenHttpError extends BadRequestError { + constructor(thing: string, url: string, cause?: Error); + get errorCode(): number; +} +export declare class NotFoundHttpError extends BadRequestError { + constructor(thing: string, url: string, cause?: Error); + get errorCode(): number; +} +export declare class ServerError extends HttpError { + constructor(message: string, cause?: Error); + get errorCode(): number; +} +export declare class ServiceUnavailableHttpError extends ServerError { + constructor(message: string, cause?: Error); + get errorCode(): number; +} diff --git a/dist/HttpError.js b/dist/HttpError.js new file mode 100644 index 0000000..26efec1 --- /dev/null +++ b/dist/HttpError.js @@ -0,0 +1,52 @@ +import { WrappingError } from "./Utils"; +export class HttpError extends WrappingError { + constructor(message, instructions, cause) { + super(message, cause); + this.instructions = instructions; + } + get name() { + return this.constructor.name; + } +} +export class BadRequestError extends HttpError { + constructor(message, instructions, url, cause) { + super(message, instructions, cause); + this.url = url; + } + get errorCode() { + return 400; + } +} +export class ForbiddenHttpError extends BadRequestError { + constructor(thing, url, cause) { + super(`You don't have access to this ${thing}.`, `${url} doesn't belong to *you*.`, url, cause); + } + get errorCode() { + return 403; + } +} +export class NotFoundHttpError extends BadRequestError { + constructor(thing, url, cause) { + super(`${thing.charAt(0).toUpperCase()}${thing.substr(1)} not found.`, `${url} doesn't exist or was deleted.`, url, cause); + } + get errorCode() { + return 404; + } +} +export class ServerError extends HttpError { + constructor(message, cause) { + super(message, `Maybe you should contact us; see instructions below.`, cause); + } + get errorCode() { + return 500; + } +} +export class ServiceUnavailableHttpError extends ServerError { + constructor(message, cause) { + super(message, cause); + } + get errorCode() { + return 503; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSHR0cEVycm9yLmpzIiwic291cmNlUm9vdCI6Ii4vIiwic291cmNlcyI6WyJIdHRwRXJyb3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLFNBQVMsQ0FBQztBQUV0QyxNQUFNLE9BQWdCLFNBQVUsU0FBUSxhQUFhO0lBR2pELFlBQVksT0FBZSxFQUFFLFlBQW9CLEVBQUUsS0FBYTtRQUM1RCxLQUFLLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3RCLElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO0lBQ3JDLENBQUM7SUFFRCxJQUFJLElBQUk7UUFDSixPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDO0lBQ2pDLENBQUM7Q0FHSjtBQUVELE1BQU0sT0FBTyxlQUFnQixTQUFRLFNBQVM7SUFHMUMsWUFBWSxPQUFlLEVBQUUsWUFBb0IsRUFBRSxHQUFXLEVBQUUsS0FBYTtRQUN6RSxLQUFLLENBQUMsT0FBTyxFQUFFLFlBQVksRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNwQyxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQztJQUNuQixDQUFDO0lBRUQsSUFBSSxTQUFTO1FBQ1QsT0FBTyxHQUFHLENBQUM7SUFDZixDQUFDO0NBQ0o7QUFFRCxNQUFNLE9BQU8sa0JBQW1CLFNBQVEsZUFBZTtJQUNuRCxZQUFZLEtBQWEsRUFBRSxHQUFXLEVBQUUsS0FBYTtRQUNqRCxLQUFLLENBQ0QsaUNBQWlDLEtBQUssR0FBRyxFQUN6QyxHQUFHLEdBQUcsMkJBQTJCLEVBQ2pDLEdBQUcsRUFDSCxLQUFLLENBQ1IsQ0FBQztJQUNOLENBQUM7SUFFRCxJQUFJLFNBQVM7UUFDVCxPQUFPLEdBQUcsQ0FBQztJQUNmLENBQUM7Q0FDSjtBQUVELE1BQU0sT0FBTyxpQkFBa0IsU0FBUSxlQUFlO0lBQ2xELFlBQVksS0FBYSxFQUFFLEdBQVcsRUFBRSxLQUFhO1FBQ2pELEtBQUssQ0FDRCxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsYUFBYSxFQUMvRCxHQUFHLEdBQUcsZ0NBQWdDLEVBQ3RDLEdBQUcsRUFDSCxLQUFLLENBQ1IsQ0FBQztJQUNOLENBQUM7SUFFRCxJQUFJLFNBQVM7UUFDVCxPQUFPLEdBQUcsQ0FBQztJQUNmLENBQUM7Q0FDSjtBQUVELE1BQU0sT0FBTyxXQUFZLFNBQVEsU0FBUztJQUN0QyxZQUFZLE9BQWUsRUFBRSxLQUFhO1FBQ3RDLEtBQUssQ0FBQyxPQUFPLEVBQUUsc0RBQXNELEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDbEYsQ0FBQztJQUVELElBQUksU0FBUztRQUNULE9BQU8sR0FBRyxDQUFDO0lBQ2YsQ0FBQztDQUNKO0FBRUQsTUFBTSxPQUFPLDJCQUE0QixTQUFRLFdBQVc7SUFDeEQsWUFBWSxPQUFlLEVBQUUsS0FBYTtRQUN0QyxLQUFLLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQzFCLENBQUM7SUFFRCxJQUFJLFNBQVM7UUFDVCxPQUFPLEdBQUcsQ0FBQztJQUNmLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7V3JhcHBpbmdFcnJvcn0gZnJvbSBcIi4vVXRpbHNcIjtcblxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEh0dHBFcnJvciBleHRlbmRzIFdyYXBwaW5nRXJyb3Ige1xuICAgIHB1YmxpYyByZWFkb25seSBpbnN0cnVjdGlvbnM6IHN0cmluZztcblxuICAgIGNvbnN0cnVjdG9yKG1lc3NhZ2U6IHN0cmluZywgaW5zdHJ1Y3Rpb25zOiBzdHJpbmcsIGNhdXNlPzogRXJyb3IpIHtcbiAgICAgICAgc3VwZXIobWVzc2FnZSwgY2F1c2UpO1xuICAgICAgICB0aGlzLmluc3RydWN0aW9ucyA9IGluc3RydWN0aW9ucztcbiAgICB9XG5cbiAgICBnZXQgbmFtZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5jb25zdHJ1Y3Rvci5uYW1lO1xuICAgIH1cblxuICAgIGFic3RyYWN0IGdldCBlcnJvckNvZGUoKTogbnVtYmVyO1xufVxuXG5leHBvcnQgY2xhc3MgQmFkUmVxdWVzdEVycm9yIGV4dGVuZHMgSHR0cEVycm9yIHtcbiAgICBwdWJsaWMgcmVhZG9ubHkgdXJsOiBzdHJpbmc7XG5cbiAgICBjb25zdHJ1Y3RvcihtZXNzYWdlOiBzdHJpbmcsIGluc3RydWN0aW9uczogc3RyaW5nLCB1cmw6IHN0cmluZywgY2F1c2U/OiBFcnJvcikge1xuICAgICAgICBzdXBlcihtZXNzYWdlLCBpbnN0cnVjdGlvbnMsIGNhdXNlKTtcbiAgICAgICAgdGhpcy51cmwgPSB1cmw7XG4gICAgfVxuXG4gICAgZ2V0IGVycm9yQ29kZSgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gNDAwO1xuICAgIH1cbn1cblxuZXhwb3J0IGNsYXNzIEZvcmJpZGRlbkh0dHBFcnJvciBleHRlbmRzIEJhZFJlcXVlc3RFcnJvciB7XG4gICAgY29uc3RydWN0b3IodGhpbmc6IHN0cmluZywgdXJsOiBzdHJpbmcsIGNhdXNlPzogRXJyb3IpIHtcbiAgICAgICAgc3VwZXIoXG4gICAgICAgICAgICBgWW91IGRvbid0IGhhdmUgYWNjZXNzIHRvIHRoaXMgJHt0aGluZ30uYCxcbiAgICAgICAgICAgIGAke3VybH0gZG9lc24ndCBiZWxvbmcgdG8gKnlvdSouYCxcbiAgICAgICAgICAgIHVybCxcbiAgICAgICAgICAgIGNhdXNlXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgZ2V0IGVycm9yQ29kZSgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gNDAzO1xuICAgIH1cbn1cblxuZXhwb3J0IGNsYXNzIE5vdEZvdW5kSHR0cEVycm9yIGV4dGVuZHMgQmFkUmVxdWVzdEVycm9yIHtcbiAgICBjb25zdHJ1Y3Rvcih0aGluZzogc3RyaW5nLCB1cmw6IHN0cmluZywgY2F1c2U/OiBFcnJvcikge1xuICAgICAgICBzdXBlcihcbiAgICAgICAgICAgIGAke3RoaW5nLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpfSR7dGhpbmcuc3Vic3RyKDEpfSBub3QgZm91bmQuYCxcbiAgICAgICAgICAgIGAke3VybH0gZG9lc24ndCBleGlzdCBvciB3YXMgZGVsZXRlZC5gLFxuICAgICAgICAgICAgdXJsLFxuICAgICAgICAgICAgY2F1c2VcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBnZXQgZXJyb3JDb2RlKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiA0MDQ7XG4gICAgfVxufVxuXG5leHBvcnQgY2xhc3MgU2VydmVyRXJyb3IgZXh0ZW5kcyBIdHRwRXJyb3Ige1xuICAgIGNvbnN0cnVjdG9yKG1lc3NhZ2U6IHN0cmluZywgY2F1c2U/OiBFcnJvcikge1xuICAgICAgICBzdXBlcihtZXNzYWdlLCBgTWF5YmUgeW91IHNob3VsZCBjb250YWN0IHVzOyBzZWUgaW5zdHJ1Y3Rpb25zIGJlbG93LmAsIGNhdXNlKTtcbiAgICB9XG5cbiAgICBnZXQgZXJyb3JDb2RlKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiA1MDA7XG4gICAgfVxufVxuXG5leHBvcnQgY2xhc3MgU2VydmljZVVuYXZhaWxhYmxlSHR0cEVycm9yIGV4dGVuZHMgU2VydmVyRXJyb3Ige1xuICAgIGNvbnN0cnVjdG9yKG1lc3NhZ2U6IHN0cmluZywgY2F1c2U/OiBFcnJvcikge1xuICAgICAgICBzdXBlcihtZXNzYWdlLCBjYXVzZSk7XG4gICAgfVxuXG4gICAgZ2V0IGVycm9yQ29kZSgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gNTAzO1xuICAgIH1cbn0iXX0= \ No newline at end of file diff --git a/dist/Logger.d.ts b/dist/Logger.d.ts new file mode 100644 index 0000000..755ec36 --- /dev/null +++ b/dist/Logger.d.ts @@ -0,0 +1,18 @@ +export default class Logger { + static silentError(error: Error, ...message: any[]): string; + static error(error: Error, ...message: any[]): string; + static warn(...message: any[]): void; + static info(...message: any[]): void; + static debug(...message: any[]): void; + static dev(...message: any[]): void; + private static log; + private constructor(); +} +export declare enum LogLevel { + ERROR = 0, + WARN = 1, + INFO = 2, + DEBUG = 3, + DEV = 4 +} +export declare type LogLevelKeys = keyof typeof LogLevel; diff --git a/dist/Logger.js b/dist/Logger.js new file mode 100644 index 0000000..b9bef78 --- /dev/null +++ b/dist/Logger.js @@ -0,0 +1,111 @@ +import config from "config"; +import { v4 as uuid } from "uuid"; +import Log from "./models/Log"; +const LOG_LEVEL = config.get('log_level'); +const DB_LOG_LEVEL = config.get('db_log_level'); +export default class Logger { + static silentError(error, ...message) { + return this.log('ERROR', message, error, true) || ''; + } + static error(error, ...message) { + return this.log('ERROR', message, error) || ''; + } + static warn(...message) { + this.log('WARN', message); + } + static info(...message) { + this.log('INFO', message); + } + static debug(...message) { + this.log('DEBUG', message); + } + static dev(...message) { + this.log('DEV', message); + } + static log(level, message, error, silent = false) { + const levelIndex = LogLevel[level]; + if (levelIndex <= LogLevel[LOG_LEVEL]) { + if (error) { + if (levelIndex > LogLevel.ERROR) + this.warn(`Wrong log level ${level} with attached error.`); + } + else { + if (levelIndex <= LogLevel.ERROR) + this.warn(`No error attached with log level ${level}.`); + } + const computedMsg = message.map(v => { + if (typeof v === 'string') { + return v; + } + else { + return JSON.stringify(v, (key, value) => { + if (value instanceof Object) { + if (value.type === 'Buffer') { + return `Buffer<${Buffer.from(value.data).toString('hex')}>`; + } + else if (value !== v) { + return `[object Object]`; + } + } + if (typeof value === 'string' && value.length > 96) { + return value.substr(0, 96) + '...'; + } + return value; + }, 4); + } + }).join(' '); + const log = new Log({}); + log.setLevel(level); + log.message = computedMsg; + log.setError(error); + let logID = Buffer.alloc(16); + uuid({}, logID); + log.setLogID(logID); + let output = `[${level}] `; + let pad = output.length; + if (levelIndex <= LogLevel[DB_LOG_LEVEL]) + output += `${log.getLogID()} - `; + output += computedMsg.replace(/\n/g, '\n' + ' '.repeat(pad)); + switch (level) { + case "ERROR": + if (silent || !error) { + console.error(output); + } + else { + console.error(output, error); + } + break; + case "WARN": + console.warn(output); + break; + case "INFO": + console.info(output); + break; + case "DEBUG": + case "DEV": + console.debug(output); + break; + } + if (levelIndex <= LogLevel[DB_LOG_LEVEL]) { + log.save().catch(err => { + if (!silent && err.message.indexOf('ECONNREFUSED') < 0) { + console.error({ save_err: err, error }); + } + }); + } + return log.getLogID(); + } + return null; + } + constructor() { + } +} +export var LogLevel; +(function (LogLevel) { + LogLevel[LogLevel["ERROR"] = 0] = "ERROR"; + LogLevel[LogLevel["WARN"] = 1] = "WARN"; + LogLevel[LogLevel["INFO"] = 2] = "INFO"; + LogLevel[LogLevel["DEBUG"] = 3] = "DEBUG"; + LogLevel[LogLevel["DEV"] = 4] = "DEV"; +})(LogLevel || (LogLevel = {})); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTG9nZ2VyLmpzIiwic291cmNlUm9vdCI6Ii4vIiwic291cmNlcyI6WyJMb2dnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBQzVCLE9BQU8sRUFBQyxFQUFFLElBQUksSUFBSSxFQUFDLE1BQU0sTUFBTSxDQUFDO0FBQ2hDLE9BQU8sR0FBRyxNQUFNLGNBQWMsQ0FBQztBQUUvQixNQUFNLFNBQVMsR0FBK0IsTUFBTSxDQUFDLEdBQUcsQ0FBUyxXQUFXLENBQUMsQ0FBQztBQUM5RSxNQUFNLFlBQVksR0FBK0IsTUFBTSxDQUFDLEdBQUcsQ0FBUyxjQUFjLENBQUMsQ0FBQztBQUVwRixNQUFNLENBQUMsT0FBTyxPQUFPLE1BQU07SUFDaEIsTUFBTSxDQUFDLFdBQVcsQ0FBQyxLQUFZLEVBQUUsR0FBRyxPQUFjO1FBQ3JELE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDekQsQ0FBQztJQUVNLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBWSxFQUFFLEdBQUcsT0FBYztRQUMvQyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDbkQsQ0FBQztJQUVNLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxPQUFjO1FBQ2hDLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQzlCLENBQUM7SUFFTSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBYztRQUNoQyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztJQUM5QixDQUFDO0lBRU0sTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLE9BQWM7UUFDakMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxD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UUFBUSxLQUFSLFFBQVEsUUFNbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgY29uZmlnIGZyb20gXCJjb25maWdcIjtcbmltcG9ydCB7djQgYXMgdXVpZH0gZnJvbSBcInV1aWRcIjtcbmltcG9ydCBMb2cgZnJvbSBcIi4vbW9kZWxzL0xvZ1wiO1xuXG5jb25zdCBMT0dfTEVWRUw6IExvZ0xldmVsS2V5cyA9IDxMb2dMZXZlbEtleXM+Y29uZmlnLmdldDxzdHJpbmc+KCdsb2dfbGV2ZWwnKTtcbmNvbnN0IERCX0xPR19MRVZFTDogTG9nTGV2ZWxLZXlzID0gPExvZ0xldmVsS2V5cz5jb25maWcuZ2V0PHN0cmluZz4oJ2RiX2xvZ19sZXZlbCcpO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBMb2dnZXIge1xuICAgIHB1YmxpYyBzdGF0aWMgc2lsZW50RXJyb3IoZXJyb3I6IEVycm9yLCAuLi5tZXNzYWdlOiBhbnlbXSk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLmxvZygnRVJST1InLCBtZXNzYWdlLCBlcnJvciwgdHJ1ZSkgfHwgJyc7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBlcnJvcihlcnJvcjogRXJyb3IsIC4uLm1lc3NhZ2U6IGFueVtdKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubG9nKCdFUlJPUicsIG1lc3NhZ2UsIGVycm9yKSB8fCAnJztcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIHdhcm4oLi4ubWVzc2FnZTogYW55W10pIHtcbiAgICAgICAgdGhpcy5sb2coJ1dBUk4nLCBtZXNzYWdlKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGluZm8oLi4ubWVzc2FnZTogYW55W10pIHtcbiAgICAgICAgdGhpcy5sb2coJ0lORk8nLCBtZXNzYWdlKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGRlYnVnKC4uLm1lc3NhZ2U6IGFueVtdKSB7XG4gICAgICAgIHRoaXMubG9nKCdERUJVRycsIG1lc3NhZ2UpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgZGV2KC4uLm1lc3NhZ2U6IGFueVtdKSB7XG4gICAgICAgIHRoaXMubG9nKCdERVYnLCBtZXNzYWdlKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBsb2cobGV2ZWw6IExvZ0xldmVsS2V5cywgbWVzc2FnZTogYW55W10sIGVycm9yPzogRXJyb3IsIHNpbGVudDogYm9vbGVhbiA9IGZhbHNlKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgICAgIGNvbnN0IGxldmVsSW5kZXggPSBMb2dMZXZlbFtsZXZlbF07XG4gICAgICAgIGlmIChsZXZlbEluZGV4IDw9IExvZ0xldmVsW0xPR19MRVZFTF0pIHtcbiAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgIGlmIChsZXZlbEluZGV4ID4gTG9nTGV2ZWwuRVJST1IpIHRoaXMud2FybihgV3JvbmcgbG9nIGxldmVsICR7bGV2ZWx9IHdpdGggYXR0YWNoZWQgZXJyb3IuYCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmIChsZXZlbEluZGV4IDw9IExvZ0xldmVsLkVSUk9SKSB0aGlzLndhcm4oYE5vIGVycm9yIGF0dGFjaGVkIHdpdGggbG9nIGxldmVsICR7bGV2ZWx9LmApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBjb21wdXRlZE1zZyA9IG1lc3NhZ2UubWFwKHYgPT4ge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdiA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHY7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHYsIChrZXk6IHN0cmluZywgdmFsdWU6IGFueSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgT2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlLnR5cGUgPT09ICdCdWZmZXInKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBgQnVmZmVyPCR7QnVmZmVyLmZyb20odmFsdWUuZGF0YSkudG9TdHJpbmcoJ2hleCcpfT5gO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodmFsdWUgIT09IHYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGBbb2JqZWN0IE9iamVjdF1gO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmIHZhbHVlLmxlbmd0aCA+IDk2KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlLnN1YnN0cigwLCA5NikgKyAnLi4uJztcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgICAgICAgICAgICAgfSwgNCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSkuam9pbignICcpO1xuXG4gICAgICAgICAgICBjb25zdCBsb2cgPSBuZXcgTG9nKHt9KTtcbiAgICAgICAgICAgIGxvZy5zZXRMZXZlbChsZXZlbCk7XG4gICAgICAgICAgICBsb2cubWVzc2FnZSA9IGNvbXB1dGVkTXNnO1xuICAgICAgICAgICAgbG9nLnNldEVycm9yKGVycm9yKTtcblxuICAgICAgICAgICAgbGV0IGxvZ0lEID0gQnVmZmVyLmFsbG9jKDE2KTtcbiAgICAgICAgICAgIHV1aWQoe30sIGxvZ0lEKTtcbiAgICAgICAgICAgIGxvZy5zZXRMb2dJRChsb2dJRCk7XG5cblxuICAgICAgICAgICAgbGV0IG91dHB1dCA9IGBbJHtsZXZlbH1dIGA7XG4gICAgICAgICAgICBsZXQgcGFkID0gb3V0cHV0Lmxlbmd0aDtcbiAgICAgICAgICAgIGlmIChsZXZlbEluZGV4IDw9IExvZ0xldmVsW0RCX0xPR19MRVZFTF0pIG91dHB1dCArPSBgJHtsb2cuZ2V0TG9nSUQoKX0gLSBgO1xuICAgICAgICAgICAgb3V0cHV0ICs9IGNvbXB1dGVkTXNnLnJlcGxhY2UoL1xcbi9nLCAnXFxuJyArICcgJy5yZXBlYXQocGFkKSk7XG5cbiAgICAgICAgICAgIHN3aXRjaCAobGV2ZWwpIHtcbiAgICAgICAgICAgICAgICBjYXNlIFwiRVJST1JcIjpcbiAgICAgICAgICAgICAgICAgICAgaWYgKHNpbGVudCB8fCAhZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3Iob3V0cHV0KTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3Iob3V0cHV0LCBlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSBcIldBUk5cIjpcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKG91dHB1dCk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgXCJJTkZPXCI6XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhvdXRwdXQpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlIFwiREVCVUdcIjpcbiAgICAgICAgICAgICAgICBjYXNlIFwiREVWXCI6XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZGVidWcob3V0cHV0KTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChsZXZlbEluZGV4IDw9IExvZ0xldmVsW0RCX0xPR19MRVZFTF0pIHtcbiAgICAgICAgICAgICAgICBsb2cuc2F2ZSgpLmNhdGNoKGVyciA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghc2lsZW50ICYmIGVyci5tZXNzYWdlLmluZGV4T2YoJ0VDT05OUkVGVVNFRCcpIDwgMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcih7c2F2ZV9lcnI6IGVyciwgZXJyb3J9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGxvZy5nZXRMb2dJRCgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHByaXZhdGUgY29uc3RydWN0b3IoKSB7XG4gICAgfVxufVxuXG5leHBvcnQgZW51bSBMb2dMZXZlbCB7XG4gICAgRVJST1IsXG4gICAgV0FSTixcbiAgICBJTkZPLFxuICAgIERFQlVHLFxuICAgIERFVixcbn1cblxuZXhwb3J0IHR5cGUgTG9nTGV2ZWxLZXlzID0ga2V5b2YgdHlwZW9mIExvZ0xldmVsO1xuIl19 \ No newline at end of file diff --git a/dist/Mail.d.ts b/dist/Mail.d.ts new file mode 100644 index 0000000..04bc02c --- /dev/null +++ b/dist/Mail.d.ts @@ -0,0 +1,24 @@ +import { SentMessageInfo } from "nodemailer"; +export declare function mailRoute(template: string): string; +export default class Mail { + private static transporter; + private static getTransporter; + static prepare(): Promise; + static end(): void; + static parse(template: string, data: any, textOnly: boolean): string; + private readonly template; + private readonly options; + private readonly data; + constructor(template: MailTemplate, data?: { + [p: string]: any; + }); + private verifyData; + send(...to: string[]): Promise; +} +export declare class MailTemplate { + private readonly _template; + private readonly subject; + constructor(template: string, subject: (data: any) => string); + get template(): string; + getSubject(data: any): string; +} diff --git a/dist/Mail.js b/dist/Mail.js new file mode 100644 index 0000000..d10f620 --- /dev/null +++ b/dist/Mail.js @@ -0,0 +1,122 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import nodemailer from "nodemailer"; +import config from "config"; +import nunjucks from 'nunjucks'; +import * as util from "util"; +import { WrappingError } from "./Utils"; +import mjml2html from "mjml"; +import * as querystring from "querystring"; +import Logger from "./Logger"; +export function mailRoute(template) { + return `/mail/${template}`; +} +export default class Mail { + constructor(template, data = {}) { + this.options = {}; + this.template = template; + this.data = data; + this.options.subject = this.template.getSubject(data); + this.verifyData(); + } + static getTransporter() { + if (!this.transporter) + throw new MailError('Mail system was not prepared.'); + return this.transporter; + } + static prepare() { + return __awaiter(this, void 0, void 0, function* () { + const transporter = nodemailer.createTransport({ + host: config.get('mail.host'), + port: config.get('mail.port'), + secure: config.get('mail.secure'), + auth: { + user: config.get('mail.username'), + pass: config.get('mail.password'), + }, + tls: { + rejectUnauthorized: !config.get('mail.allow_invalid_tls') + } + }); + try { + yield util.promisify(transporter.verify)(); + this.transporter = transporter; + } + catch (e) { + throw new MailError('Connection to mail service unsuccessful.', e); + } + Logger.info(`Mail ready to be distributed via ${config.get('mail.host')}:${config.get('mail.port')}`); + }); + } + static end() { + this.transporter.close(); + } + static parse(template, data, textOnly) { + data.text = textOnly; + const nunjucksResult = nunjucks.render(template, data); + if (textOnly) + return nunjucksResult; + const mjmlResult = mjml2html(nunjucksResult, {}); + if (mjmlResult.errors.length > 0) { + throw new MailError(`Error while parsing mail template ${template}: ${JSON.stringify(mjmlResult.errors, null, 4)}`); + } + return mjmlResult.html; + } + verifyData() { + for (const forbiddenField of [ + 'to', + ]) { + if (this.data[forbiddenField] !== undefined) { + throw new MailError(`Can't use reserved data.${forbiddenField}.`); + } + } + } + send(...to) { + return __awaiter(this, void 0, void 0, function* () { + const results = []; + for (const destEmail of to) { + // Reset options + this.options.html = this.options.text = undefined; + // Set options + this.options.to = destEmail; + // Set data + this.data.mail_subject = this.options.subject; + this.data.mail_to = this.options.to; + this.data.mail_link = `${config.get('public_url')}${mailRoute(this.template.template)}?${querystring.stringify(this.data)}`; + // Log + Logger.dev('Send mail', this.options); + // Render email + this.options.html = Mail.parse('mails/' + this.template.template + '.mjml.njk', this.data, false); + this.options.text = Mail.parse('mails/' + this.template.template + '.mjml.njk', this.data, true); + // Send email + results.push(yield Mail.getTransporter().sendMail(this.options)); + } + return results; + }); + } +} +export class MailTemplate { + constructor(template, subject) { + this._template = template; + this.subject = subject; + } + get template() { + return this._template; + } + getSubject(data) { + return 'Watch My Stream - ' + this.subject(data); + } +} +class MailError extends WrappingError { + constructor(message = 'An error occurred while sending mail.', cause) { + super(message, cause); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWFpbC5qcyIsInNvdXJjZVJvb3QiOiIuLyIsInNvdXJjZXMiOlsiTWFpbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFBQSxPQUFPLFVBQTBDLE1BQU0sWUFBWSxDQUFDO0FBQ3BFLE9BQU8sTUFBTSxNQUFNLFFBQVEsQ0FBQztBQUU1QixPQUFPLFFBQVEsTUFBTSxVQUFVLENBQUM7QUFDaEMsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLFNBQVMsQ0FBQztBQUN0QyxPQUFPLFNBQVMsTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxLQUFLLFdBQVcsTUFBTSxhQUFhLENBQUM7QUFDM0MsT0FBTyxNQUFNLE1BQU0sVUFBVSxDQUFDO0FBRTlCLE1BQU0sVUFBVSxTQUFTLENBQUMsUUFBZ0I7SUFDdEMsT0FBTyxTQUFTLFFBQVEsRUFBRSxDQUFDO0FBQy9CLENBQUM7QUFFRCxNQUFNLENBQUMsT0FBTyxPQUFPLElBQUk7SUFzRHJCLFlBQVksUUFBc0IsRUFBRSxPQUE2QixFQUFFO1FBSGxELFlBQU8sR0FBWSxFQUFFLENBQUM7UUFJbkMsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFDekIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7UUFDakIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFdEQsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO0lBQ3RCLENBQUM7SUF6RE8sTUFBTSxDQUFDLGNBQWM7UUFDekIsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXO1lBQUUsTUFBTSxJQUFJLFNBQVMsQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO1FBQzVFLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQztJQUM1QixDQUFDO0lBRU0sTUFBTSxDQUFPLE9BQU87O1lBQ3ZCLE1BQU0sV0FB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QyxJQUFTO1FBQ3ZCLE9BQU8sb0JBQW9CLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNyRCxDQUFDO0NBQ0o7QUFFRCxNQUFNLFNBQVUsU0FBUSxhQUFhO0lBQ2pDLFlBQVksVUFBa0IsdUNBQXVDLEVBQUUsS0FBYTtRQUNoRixLQUFLLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQzFCLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBub2RlbWFpbGVyLCB7U2VudE1lc3NhZ2VJbmZvLCBUcmFuc3BvcnRlcn0gZnJvbSBcIm5vZGVtYWlsZXJcIjtcbmltcG9ydCBjb25maWcgZnJvbSBcImNvbmZpZ1wiO1xuaW1wb3J0IHtPcHRpb25zfSBmcm9tIFwibm9kZW1haWxlci9saWIvbWFpbGVyXCI7XG5pbXBvcnQgbnVuanVja3MgZnJvbSAnbnVuanVja3MnO1xuaW1wb3J0ICogYXMgdXRpbCBmcm9tIFwidXRpbFwiO1xuaW1wb3J0IHtXcmFwcGluZ0Vycm9yfSBmcm9tIFwiLi9VdGlsc1wiO1xuaW1wb3J0IG1qbWwyaHRtbCBmcm9tIFwibWptbFwiO1xuaW1wb3J0ICogYXMgcXVlcnlzdHJpbmcgZnJvbSBcInF1ZXJ5c3RyaW5nXCI7XG5pbXBvcnQgTG9nZ2VyIGZyb20gXCIuL0xvZ2dlclwiO1xuXG5leHBvcnQgZnVuY3Rpb24gbWFpbFJvdXRlKHRlbXBsYXRlOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBgL21haWwvJHt0ZW1wbGF0ZX1gO1xufVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNYWlsIHtcbiAgICBwcml2YXRlIHN0YXRpYyB0cmFuc3BvcnRlcjogVHJhbnNwb3J0ZXI7XG5cbiAgICBwcml2YXRlIHN0YXRpYyBnZXRUcmFuc3BvcnRlcigpOiBUcmFuc3BvcnRlciB7XG4gICAgICAgIGlmICghdGhpcy50cmFuc3BvcnRlcikgdGhyb3cgbmV3IE1haWxFcnJvcignTWFpbCBzeXN0ZW0gd2FzIG5vdCBwcmVwYXJlZC4nKTtcbiAgICAgICAgcmV0dXJuIHRoaXMudHJhbnNwb3J0ZXI7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBhc3luYyBwcmVwYXJlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCB0cmFuc3BvcnRlciA9IG5vZGVtYWlsZXIuY3JlYXRlVHJhbnNwb3J0KHtcbiAgICAgICAgICAgIGhvc3Q6IGNvbmZpZy5nZXQoJ21haWwuaG9zdCcpLFxuICAgICAgICAgICAgcG9ydDogY29uZmlnLmdldCgnbWFpbC5wb3J0JyksXG4gICAgICAgICAgICBzZWN1cmU6IGNvbmZpZy5nZXQoJ21haWwuc2VjdXJlJyksXG4gICAgICAgICAgICBhdXRoOiB7XG4gICAgICAgICAgICAgICAgdXNlcjogY29uZmlnLmdldCgnbWFpbC51c2VybmFtZScpLFxuICAgICAgICAgICAgICAgIHBhc3M6IGNvbmZpZy5nZXQoJ21haWwucGFzc3dvcmQnKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB0bHM6IHtcbiAgICAgICAgICAgICAgICByZWplY3RVbmF1dGhvcml6ZWQ6ICFjb25maWcuZ2V0KCdtYWlsLmFsbG93X2ludmFsaWRfdGxzJylcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IHV0aWwucHJvbWlzaWZ5KHRyYW5zcG9ydGVyLnZlcmlmeSkoKTtcbiAgICAgICAgICAgIHRoaXMudHJhbnNwb3J0ZXIgPSB0cmFuc3BvcnRlcjtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IE1haWxFcnJvcignQ29ubmVjdGlvbiB0byBtYWlsIHNlcnZpY2UgdW5zdWNjZXNzZnVsLicsIGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgTG9nZ2VyLmluZm8oYE1haWwgcmVhZHkgdG8gYmUgZGlzdHJpYnV0ZWQgdmlhICR7Y29uZmlnLmdldCgnbWFpbC5ob3N0Jyl9OiR7Y29uZmlnLmdldCgnbWFpbC5wb3J0Jyl9YCk7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBlbmQoKSB7XG4gICAgICAgIHRoaXMudHJhbnNwb3J0ZXIuY2xvc2UoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIHBhcnNlKHRlbXBsYXRlOiBzdHJpbmcsIGRhdGE6IGFueSwgdGV4dE9ubHk6IGJvb2xlYW4pOiBzdHJpbmcge1xuICAgICAgICBkYXRhLnRleHQgPSB0ZXh0T25seTtcbiAgICAgICAgY29uc3QgbnVuanVja3NSZXN1bHQgPSBudW5qdWNrcy5yZW5kZXIodGVtcGxhdGUsIGRhdGEpO1xuICAgICAgICBpZiAodGV4dE9ubHkpIHJldHVybiBudW5qdWNrc1Jlc3VsdDtcblxuICAgICAgICBjb25zdCBtam1sUmVzdWx0ID0gbWptbDJodG1sKG51bmp1Y2tzUmVzdWx0LCB7fSk7XG5cbiAgICAgICAgaWYgKG1qbWxSZXN1bHQuZXJyb3JzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBNYWlsRXJyb3IoYEVycm9yIHdoaWxlIHBhcnNpbmcgbWFpbCB0ZW1wbGF0ZSAke3RlbXBsYXRlfTogJHtKU09OLnN0cmluZ2lmeShtam1sUmVzdWx0LmVycm9ycywgbnVsbCwgNCl9YCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbWptbFJlc3VsdC5odG1sO1xuICAgIH1cblxuICAgIHByaXZhdGUgcmVhZG9ubHkgdGVtcGxhdGU6IE1haWxUZW1wbGF0ZTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IG9wdGlvbnM6IE9wdGlvbnMgPSB7fTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IGRhdGE6IHsgW3A6IHN0cmluZ106IGFueSB9O1xuXG4gICAgY29uc3RydWN0b3IodGVtcGxhdGU6IE1haWxUZW1wbGF0ZSwgZGF0YTogeyBbcDogc3RyaW5nXTogYW55IH0gPSB7fSkge1xuICAgICAgICB0aGlzLnRlbXBsYXRlID0gdGVtcGxhdGU7XG4gICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7XG4gICAgICAgIHRoaXMub3B0aW9ucy5zdWJqZWN0ID0gdGhpcy50ZW1wbGF0ZS5nZXRTdWJqZWN0KGRhdGEpO1xuXG4gICAgICAgIHRoaXMudmVyaWZ5RGF0YSgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgdmVyaWZ5RGF0YSgpIHtcbiAgICAgICAgZm9yIChjb25zdCBmb3JiaWRkZW5GaWVsZCBvZiBbXG4gICAgICAgICAgICAndG8nLFxuICAgICAgICBdKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5kYXRhW2ZvcmJpZGRlbkZpZWxkXSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IE1haWxFcnJvcihgQ2FuJ3QgdXNlIHJlc2VydmVkIGRhdGEuJHtmb3JiaWRkZW5GaWVsZH0uYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc2VuZCguLi50bzogc3RyaW5nW10pOiBQcm9taXNlPFNlbnRNZXNzYWdlSW5mb1tdPiB7XG4gICAgICAgIGNvbnN0IHJlc3VsdHMgPSBbXTtcblxuICAgICAgICBmb3IgKGNvbnN0IGRlc3RFbWFpbCBvZiB0bykge1xuICAgICAgICAgICAgLy8gUmVzZXQgb3B0aW9uc1xuICAgICAgICAgICAgdGhpcy5vcHRpb25zLmh0bWwgPSB0aGlzLm9wdGlvbnMudGV4dCA9IHVuZGVmaW5lZDtcblxuICAgICAgICAgICAgLy8gU2V0IG9wdGlvbnNcbiAgICAgICAgICAgIHRoaXMub3B0aW9ucy50byA9IGRlc3RFbWFpbDtcblxuICAgICAgICAgICAgLy8gU2V0IGRhdGFcbiAgICAgICAgICAgIHRoaXMuZGF0YS5tYWlsX3N1YmplY3QgPSB0aGlzLm9wdGlvbnMuc3ViamVjdDtcbiAgICAgICAgICAgIHRoaXMuZGF0YS5tYWlsX3RvID0gdGhpcy5vcHRpb25zLnRvO1xuICAgICAgICAgICAgdGhpcy5kYXRhLm1haWxfbGluayA9IGAke2NvbmZpZy5nZXQ8c3RyaW5nPigncHVibGljX3VybCcpfSR7bWFpbFJvdXRlKHRoaXMudGVtcGxhdGUudGVtcGxhdGUpfT8ke3F1ZXJ5c3RyaW5nLnN0cmluZ2lmeSh0aGlzLmRhdGEpfWA7XG5cbiAgICAgICAgICAgIC8vIExvZ1xuICAgICAgICAgICAgTG9nZ2VyLmRldignU2VuZCBtYWlsJywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICAgICAgLy8gUmVuZGVyIGVtYWlsXG4gICAgICAgICAgICB0aGlzLm9wdGlvbnMuaHRtbCA9IE1haWwucGFyc2UoJ21haWxzLycgKyB0aGlzLnRlbXBsYXRlLnRlbXBsYXRlICsgJy5tam1sLm5qaycsIHRoaXMuZGF0YSwgZmFsc2UpO1xuICAgICAgICAgICAgdGhpcy5vcHRpb25zLnRleHQgPSBNYWlsLnBhcnNlKCdtYWlscy8nICsgdGhpcy50ZW1wbGF0ZS50ZW1wbGF0ZSArICcubWptbC5uamsnLCB0aGlzLmRhdGEsIHRydWUpO1xuXG4gICAgICAgICAgICAvLyBTZW5kIGVtYWlsXG4gICAgICAgICAgICByZXN1bHRzLnB1c2goYXdhaXQgTWFpbC5nZXRUcmFuc3BvcnRlcigpLnNlbmRNYWlsKHRoaXMub3B0aW9ucykpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlc3VsdHM7XG4gICAgfVxufVxuXG5leHBvcnQgY2xhc3MgTWFpbFRlbXBsYXRlIHtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF90ZW1wbGF0ZTogc3RyaW5nO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgc3ViamVjdDogKGRhdGE6IGFueSkgPT4gc3RyaW5nO1xuXG4gICAgY29uc3RydWN0b3IodGVtcGxhdGU6IHN0cmluZywgc3ViamVjdDogKGRhdGE6IGFueSkgPT4gc3RyaW5nKSB7XG4gICAgICAgIHRoaXMuX3RlbXBsYXRlID0gdGVtcGxhdGU7XG4gICAgICAgIHRoaXMuc3ViamVjdCA9IHN1YmplY3Q7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCB0ZW1wbGF0ZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5fdGVtcGxhdGU7XG4gICAgfVxuXG4gICAgcHVibGljIGdldFN1YmplY3QoZGF0YTogYW55KTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuICdXYXRjaCBNeSBTdHJlYW0gLSAnICsgdGhpcy5zdWJqZWN0KGRhdGEpO1xuICAgIH1cbn1cblxuY2xhc3MgTWFpbEVycm9yIGV4dGVuZHMgV3JhcHBpbmdFcnJvciB7XG4gICAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nID0gJ0FuIGVycm9yIG9jY3VycmVkIHdoaWxlIHNlbmRpbmcgbWFpbC4nLCBjYXVzZT86IEVycm9yKSB7XG4gICAgICAgIHN1cGVyKG1lc3NhZ2UsIGNhdXNlKTtcbiAgICB9XG59Il19 \ No newline at end of file diff --git a/dist/Pagination.d.ts b/dist/Pagination.d.ts new file mode 100644 index 0000000..ee6c5c7 --- /dev/null +++ b/dist/Pagination.d.ts @@ -0,0 +1,10 @@ +import Model from "./db/Model"; +export default class Pagination { + private readonly models; + readonly page: number; + readonly perPage: number; + readonly totalCount: number; + constructor(models: T[], page: number, perPage: number, totalCount: number); + hasPrevious(): boolean; + hasNext(): boolean; +} diff --git a/dist/Pagination.js b/dist/Pagination.js new file mode 100644 index 0000000..42e59b8 --- /dev/null +++ b/dist/Pagination.js @@ -0,0 +1,15 @@ +export default class Pagination { + constructor(models, page, perPage, totalCount) { + this.models = models; + this.page = page; + this.perPage = perPage; + this.totalCount = totalCount; + } + hasPrevious() { + return this.page > 1; + } + hasNext() { + return this.models.length >= this.perPage && this.page * this.perPage < this.totalCount; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGFnaW5hdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIuLyIsInNvdXJjZXMiOlsiUGFnaW5hdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxNQUFNLENBQUMsT0FBTyxPQUFPLFVBQVU7SUFNM0IsWUFBWSxNQUFXLEVBQUUsSUFBWSxFQUFFLE9BQWUsRUFBRSxVQUFrQjtRQUN0RSxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztRQUNqQixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUN2QixJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztJQUNqQyxDQUFDO0lBRU0sV0FBVztRQUNkLE9BQU8sSUFBSSxDQUFDLElBQUksR0FBRyxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUVNLE9BQU87UUFDVixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxJQUFJLElBQUksQ0FBQyxPQUFPLElBQUksSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUM7SUFDNUYsQ0FBQztDQUVKIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IE1vZGVsIGZyb20gXCIuL2RiL01vZGVsXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFBhZ2luYXRpb248VCBleHRlbmRzIE1vZGVsPiB7XG4gICAgcHJpdmF0ZSByZWFkb25seSBtb2RlbHM6IFRbXTtcbiAgICBwdWJsaWMgcmVhZG9ubHkgcGFnZTogbnVtYmVyO1xuICAgIHB1YmxpYyByZWFkb25seSBwZXJQYWdlOiBudW1iZXI7XG4gICAgcHVibGljIHJlYWRvbmx5IHRvdGFsQ291bnQ6IG51bWJlcjtcblxuICAgIGNvbnN0cnVjdG9yKG1vZGVsczogVFtdLCBwYWdlOiBudW1iZXIsIHBlclBhZ2U6IG51bWJlciwgdG90YWxDb3VudDogbnVtYmVyKSB7XG4gICAgICAgIHRoaXMubW9kZWxzID0gbW9kZWxzO1xuICAgICAgICB0aGlzLnBhZ2UgPSBwYWdlO1xuICAgICAgICB0aGlzLnBlclBhZ2UgPSBwZXJQYWdlO1xuICAgICAgICB0aGlzLnRvdGFsQ291bnQgPSB0b3RhbENvdW50O1xuICAgIH1cblxuICAgIHB1YmxpYyBoYXNQcmV2aW91cygpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucGFnZSA+IDE7XG4gICAgfVxuXG4gICAgcHVibGljIGhhc05leHQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLm1vZGVscy5sZW5ndGggPj0gdGhpcy5wZXJQYWdlICYmIHRoaXMucGFnZSAqIHRoaXMucGVyUGFnZSA8IHRoaXMudG90YWxDb3VudDtcbiAgICB9XG5cbn0iXX0= \ No newline at end of file diff --git a/dist/Utils.d.ts b/dist/Utils.d.ts new file mode 100644 index 0000000..7d7c2b4 --- /dev/null +++ b/dist/Utils.d.ts @@ -0,0 +1,7 @@ +export declare function sleep(ms: number): Promise; +export declare abstract class WrappingError extends Error { + readonly cause?: Error; + protected constructor(message: string, cause?: Error); + get name(): string; +} +export declare function cryptoRandomDictionary(size: number, dictionary: string): string; diff --git a/dist/Utils.js b/dist/Utils.js new file mode 100644 index 0000000..18b3e25 --- /dev/null +++ b/dist/Utils.js @@ -0,0 +1,38 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import * as crypto from "crypto"; +export function sleep(ms) { + return __awaiter(this, void 0, void 0, function* () { + return yield new Promise(resolve => { + setTimeout(() => resolve(), ms); + }); + }); +} +export class WrappingError extends Error { + constructor(message, cause) { + super(message); + this.cause = cause; + if (cause !== undefined) { + this.stack = (this.stack || '') + `\n> Caused by: ${cause.stack}`; + } + } + get name() { + return this.constructor.name; + } +} +export function cryptoRandomDictionary(size, dictionary) { + const randomBytes = crypto.randomBytes(size); + const output = new Array(size); + for (let i = 0; i < size; i++) { + output[i] = dictionary[Math.floor((randomBytes[i] / 255) * dictionary.length)]; + } + return output.join(''); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVXRpbHMuanMiLCJzb3VyY2VSb290IjoiLi8iLCJzb3VyY2VzIjpbIlV0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBLE9BQU8sS0FBSyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBRWpDLE1BQU0sVUFBZ0IsS0FBSyxDQUFDLEVBQVU7O1FBQ2xDLE9BQU8sTUFBTSxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRTtZQUMvQixVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsT0FBTyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDcEMsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0NBQUE7QUFFRCxNQUFNLE9BQWdCLGFBQWMsU0FBUSxLQUFLO0lBRzdDLFlBQXNCLE9BQWUsRUFBRSxLQUFhO1FBQ2hELEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNmLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBRW5CLElBQUksS0FBSyxLQUFLLFNBQVMsRUFBRTtZQUNyQixJQUFJLENBQUMsS0FBSyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUMsR0FBRyxrQkFBa0IsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDO1NBQ3JFO0lBQ0wsQ0FBQztJQUVELElBQUksSUFBSTtRQUNKLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUM7SUFDakMsQ0FBQztDQUNKO0FBRUQsTUFBTSxVQUFVLHNCQUFzQixDQUFDLElBQVksRUFBRSxVQUFrQjtJQUNuRSxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzdDLE1BQU0sTUFBTSxHQUFHLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBRS9CLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDM0IsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0tBQ2xGO0lBRUQsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQzNCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBjcnlwdG8gZnJvbSBcImNyeXB0b1wiO1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2xlZXAobXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiBhd2FpdCBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHtcbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiByZXNvbHZlKCksIG1zKTtcbiAgICB9KTtcbn1cblxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFdyYXBwaW5nRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gICAgcHVibGljIHJlYWRvbmx5IGNhdXNlPzogRXJyb3I7XG5cbiAgICBwcm90ZWN0ZWQgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nLCBjYXVzZT86IEVycm9yKSB7XG4gICAgICAgIHN1cGVyKG1lc3NhZ2UpO1xuICAgICAgICB0aGlzLmNhdXNlID0gY2F1c2U7XG5cbiAgICAgICAgaWYgKGNhdXNlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRoaXMuc3RhY2sgPSAodGhpcy5zdGFjayB8fCAnJykgKyBgXFxuPiBDYXVzZWQgYnk6ICR7Y2F1c2Uuc3RhY2t9YDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGdldCBuYW1lKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLmNvbnN0cnVjdG9yLm5hbWU7XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gY3J5cHRvUmFuZG9tRGljdGlvbmFyeShzaXplOiBudW1iZXIsIGRpY3Rpb25hcnk6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgcmFuZG9tQnl0ZXMgPSBjcnlwdG8ucmFuZG9tQnl0ZXMoc2l6ZSk7XG4gICAgY29uc3Qgb3V0cHV0ID0gbmV3IEFycmF5KHNpemUpO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzaXplOyBpKyspIHtcbiAgICAgICAgb3V0cHV0W2ldID0gZGljdGlvbmFyeVtNYXRoLmZsb29yKChyYW5kb21CeXRlc1tpXSAvIDI1NSkgKiBkaWN0aW9uYXJ5Lmxlbmd0aCldO1xuICAgIH1cblxuICAgIHJldHVybiBvdXRwdXQuam9pbignJyk7XG59Il19 \ No newline at end of file diff --git a/dist/WebSocketListener.d.ts b/dist/WebSocketListener.d.ts new file mode 100644 index 0000000..0610621 --- /dev/null +++ b/dist/WebSocketListener.d.ts @@ -0,0 +1,8 @@ +/// +/// +import WebSocket from "ws"; +import { IncomingMessage } from "http"; +export default abstract class WebSocketListener { + abstract path(): string; + abstract handle(socket: WebSocket, request: IncomingMessage, session: Express.SessionData): Promise; +} diff --git a/dist/WebSocketListener.js b/dist/WebSocketListener.js new file mode 100644 index 0000000..03ed92d --- /dev/null +++ b/dist/WebSocketListener.js @@ -0,0 +1,3 @@ +export default class WebSocketListener { +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV2ViU29ja2V0TGlzdGVuZXIuanMiLCJzb3VyY2VSb290IjoiLi8iLCJzb3VyY2VzIjpbIldlYlNvY2tldExpc3RlbmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBLE1BQU0sQ0FBQyxPQUFPLE9BQWdCLGlCQUFpQjtDQUk5QyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBXZWJTb2NrZXQgZnJvbSBcIndzXCI7XG5pbXBvcnQge0luY29taW5nTWVzc2FnZX0gZnJvbSBcImh0dHBcIjtcblxuZXhwb3J0IGRlZmF1bHQgYWJzdHJhY3QgY2xhc3MgV2ViU29ja2V0TGlzdGVuZXIge1xuICAgIHB1YmxpYyBhYnN0cmFjdCBwYXRoKCk6IHN0cmluZztcblxuICAgIHB1YmxpYyBhYnN0cmFjdCBhc3luYyBoYW5kbGUoc29ja2V0OiBXZWJTb2NrZXQsIHJlcXVlc3Q6IEluY29taW5nTWVzc2FnZSwgc2Vzc2lvbjogRXhwcmVzcy5TZXNzaW9uRGF0YSk6IFByb21pc2U8dm9pZD47XG59Il19 \ No newline at end of file diff --git a/dist/components/CsrfProtectionComponent.d.ts b/dist/components/CsrfProtectionComponent.d.ts new file mode 100644 index 0000000..9d9dd67 --- /dev/null +++ b/dist/components/CsrfProtectionComponent.d.ts @@ -0,0 +1,6 @@ +import ApplicationComponent from "../ApplicationComponent"; +import { Express, Router } from "express"; +export default class CsrfProtectionComponent extends ApplicationComponent { + start(app: Express, router: Router): Promise; + stop(): Promise; +} diff --git a/dist/components/CsrfProtectionComponent.js b/dist/components/CsrfProtectionComponent.js new file mode 100644 index 0000000..54d2ee1 --- /dev/null +++ b/dist/components/CsrfProtectionComponent.js @@ -0,0 +1,57 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import ApplicationComponent from "../ApplicationComponent"; +import crypto from "crypto"; +import { BadRequestError } from "../HttpError"; +export default class CsrfProtectionComponent extends ApplicationComponent { + start(app, router) { + return __awaiter(this, void 0, void 0, function* () { + router.use((req, res, next) => { + if (!req.session) { + throw new Error('Session is unavailable.'); + } + res.locals.getCSRFToken = () => { + if (typeof req.session.csrf !== 'string') { + req.session.csrf = crypto.randomBytes(64).toString('base64'); + } + return req.session.csrf; + }; + if (!['GET', 'HEAD', 'OPTIONS'].find(s => s === req.method)) { + if (req.session.csrf === undefined) { + throw new InvalidCsrfTokenError(req.baseUrl, `You weren't assigned any CSRF token.`); + } + else if (req.body.csrf === undefined) { + throw new InvalidCsrfTokenError(req.baseUrl, `You didn't provide any CSRF token.`); + } + else if (req.session.csrf !== req.body.csrf) { + throw new InvalidCsrfTokenError(req.baseUrl, `Tokens don't match.`); + } + } + next(); + }); + }); + } + stop() { + return __awaiter(this, void 0, void 0, function* () { + }); + } +} +class InvalidCsrfTokenError extends BadRequestError { + constructor(url, details, cause) { + super(`Invalid CSRF token`, `${details} We can't process this request. Please try again.`, url, cause); + } + get name() { + return 'Invalid CSRF Token'; + } + get errorCode() { + return 401; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ3NyZlByb3RlY3Rpb25Db21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiLi8iLCJzb3VyY2VzIjpbImNvbXBvbmVudHMvQ3NyZlByb3RlY3Rpb25Db21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBQUEsT0FBTyxvQkFBb0IsTUFBTSx5QkFBeUIsQ0FBQztBQUUzRCxPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFDNUIsT0FBTyxFQUFDLGVBQWUsRUFBQyxNQUFNLGNBQWMsQ0FBQztBQUU3QyxNQUFNLENBQUMsT0FBTyxPQUFPLHVCQUF3QixTQUFRLG9CQUEwQjtJQUM5RCxLQUFLLENBQUMsR0FBWSxFQUFFLE1BQWM7O1lBQzNDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFO2dCQUMxQixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRTtvQkFDZCxNQUFNLElBQUksS0FBSyxDQUFDLHlCQUF5QixDQUFDLENBQUM7aUJBQzlDO2dCQUVELEdBQUcsQ0FBQyxNQUFNLENBQUMsWUFBWSxHQUFHLEdBQUcsRUFBRTtvQkFDM0IsSUFBSSxPQUFPLEdBQUcsQ0FBQyxPQUFRLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBRTt3QkFDdkMsR0FBRyxDQUFDLE9BQVEsQ0FBQyxJQUFJLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUM7cUJBQ2pFO29CQUNELE9BQU8sR0FBRyxDQUFDLE9BQVEsQ0FBQyxJQUFJLENBQUM7Z0JBQzdCLENBQUMsQ0FBQztnQkFFRixJQUFJLENBQUMsQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLFNBQVMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsS0FBSyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUU7b0JBQ3pELElBQUksR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEtBQUssU0FBUyxFQUFFO3dCQUNoQyxNQUFNLElBQUkscUJBQXFCLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxzQ0FBc0MsQ0FBQyxDQUFDO3FCQUN4Rjt5QkFBTSxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLFNBQVMsRUFBRTt3QkFDcEMsTUFBTSxJQUFJLHFCQUFxQixDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsb0NBQW9DLENBQUMsQ0FBQztxQkFDdEY7eUJBQU0sSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksS0FBSyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRTt3QkFDM0MsTUFBTSxJQUFJLHFCQUFxQixDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUscUJBQXFCLENBQUMsQ0FBQztxQkFDdkU7aUJBQ0o7Z0JBQ0QsSUFBSSxFQUFFLENBQUM7WUFDWCxDQUFDLENBQUMsQ0FBQztRQUNQLENBQUM7S0FBQTtJQUVZLElBQUk7O1FBQ2pCLENBQUM7S0FBQTtDQUNKO0FBRUQsTUFBTSxxQkFBc0IsU0FBUSxlQUFlO0lBQy9DLFlBQVksR0FBVyxFQUFFLE9BQWUsRUFBRSxLQUFhO1FBQ25ELEtBQUssQ0FDRCxvQkFBb0IsRUFDcEIsR0FBRyxPQUFPLG1EQUFtRCxFQUM3RCxHQUFHLEVBQ0gsS0FBSyxDQUNSLENBQUM7SUFDTixDQUFDO0lBRUQsSUFBSSxJQUFJO1FBQ0osT0FBTyxvQkFBb0IsQ0FBQztJQUNoQyxDQUFDO0lBRUQsSUFBSSxTQUFTO1FBQ1QsT0FBTyxHQUFHLENBQUM7SUFDZixDQUFDO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgQXBwbGljYXRpb25Db21wb25lbnQgZnJvbSBcIi4uL0FwcGxpY2F0aW9uQ29tcG9uZW50XCI7XG5pbXBvcnQge0V4cHJlc3MsIFJvdXRlcn0gZnJvbSBcImV4cHJlc3NcIjtcbmltcG9ydCBjcnlwdG8gZnJvbSBcImNyeXB0b1wiO1xuaW1wb3J0IHtCYWRSZXF1ZXN0RXJyb3J9IGZyb20gXCIuLi9IdHRwRXJyb3JcIjtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQ3NyZlByb3RlY3Rpb25Db21wb25lbnQgZXh0ZW5kcyBBcHBsaWNhdGlvbkNvbXBvbmVudDx2b2lkPiB7XG4gICAgcHVibGljIGFzeW5jIHN0YXJ0KGFwcDogRXhwcmVzcywgcm91dGVyOiBSb3V0ZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgcm91dGVyLnVzZSgocmVxLCByZXMsIG5leHQpID0+IHtcbiAgICAgICAgICAgIGlmICghcmVxLnNlc3Npb24pIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Nlc3Npb24gaXMgdW5hdmFpbGFibGUuJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJlcy5sb2NhbHMuZ2V0Q1NSRlRva2VuID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgcmVxLnNlc3Npb24hLmNzcmYgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcS5zZXNzaW9uIS5jc3JmID0gY3J5cHRvLnJhbmRvbUJ5dGVzKDY0KS50b1N0cmluZygnYmFzZTY0Jyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiByZXEuc2Vzc2lvbiEuY3NyZjtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGlmICghWydHRVQnLCAnSEVBRCcsICdPUFRJT05TJ10uZmluZChzID0+IHMgPT09IHJlcS5tZXRob2QpKSB7XG4gICAgICAgICAgICAgICAgaWYgKHJlcS5zZXNzaW9uLmNzcmYgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgSW52YWxpZENzcmZUb2tlbkVycm9yKHJlcS5iYXNlVXJsLCBgWW91IHdlcmVuJ3QgYXNzaWduZWQgYW55IENTUkYgdG9rZW4uYCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChyZXEuYm9keS5jc3JmID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEludmFsaWRDc3JmVG9rZW5FcnJvcihyZXEuYmFzZVVybCwgYFlvdSBkaWRuJ3QgcHJvdmlkZSBhbnkgQ1NSRiB0b2tlbi5gKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHJlcS5zZXNzaW9uLmNzcmYgIT09IHJlcS5ib2R5LmNzcmYpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEludmFsaWRDc3JmVG9rZW5FcnJvcihyZXEuYmFzZVVybCwgYFRva2VucyBkb24ndCBtYXRjaC5gKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBuZXh0KCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBzdG9wKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIH1cbn1cblxuY2xhc3MgSW52YWxpZENzcmZUb2tlbkVycm9yIGV4dGVuZHMgQmFkUmVxdWVzdEVycm9yIHtcbiAgICBjb25zdHJ1Y3Rvcih1cmw6IHN0cmluZywgZGV0YWlsczogc3RyaW5nLCBjYXVzZT86IEVycm9yKSB7XG4gICAgICAgIHN1cGVyKFxuICAgICAgICAgICAgYEludmFsaWQgQ1NSRiB0b2tlbmAsXG4gICAgICAgICAgICBgJHtkZXRhaWxzfSBXZSBjYW4ndCBwcm9jZXNzIHRoaXMgcmVxdWVzdC4gUGxlYXNlIHRyeSBhZ2Fpbi5gLFxuICAgICAgICAgICAgdXJsLFxuICAgICAgICAgICAgY2F1c2VcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBnZXQgbmFtZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gJ0ludmFsaWQgQ1NSRiBUb2tlbic7XG4gICAgfVxuXG4gICAgZ2V0IGVycm9yQ29kZSgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gNDAxO1xuICAgIH1cbn1cbiJdfQ== \ No newline at end of file diff --git a/dist/components/ExpressAppComponent.d.ts b/dist/components/ExpressAppComponent.d.ts new file mode 100644 index 0000000..08f55bb --- /dev/null +++ b/dist/components/ExpressAppComponent.d.ts @@ -0,0 +1,12 @@ +/// +import ApplicationComponent from "../ApplicationComponent"; +import { Express, Router } from "express"; +import { Server } from "http"; +export default class ExpressAppComponent extends ApplicationComponent { + private readonly port; + private server?; + constructor(port: number); + start(app: Express, router: Router): Promise; + stop(): Promise; + getServer(): Server; +} diff --git a/dist/components/ExpressAppComponent.js b/dist/components/ExpressAppComponent.js new file mode 100644 index 0000000..63a63db --- /dev/null +++ b/dist/components/ExpressAppComponent.js @@ -0,0 +1,45 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import ApplicationComponent from "../ApplicationComponent"; +import express from "express"; +import Logger from "../Logger"; +export default class ExpressAppComponent extends ApplicationComponent { + constructor(port) { + super(); + this.port = port; + } + start(app, router) { + return __awaiter(this, void 0, void 0, function* () { + this.server = app.listen(this.port, 'localhost', () => { + Logger.info(`Web server running on localhost:${this.port}.`); + }); + router.use(express.json()); + router.use(express.urlencoded()); + router.use((req, res, next) => { + req.models = {}; + req.modelCollections = {}; + next(); + }); + }); + } + stop() { + return __awaiter(this, void 0, void 0, function* () { + if (this.server) { + yield this.close('Webserver', this.server, this.server.close); + } + }); + } + getServer() { + if (!this.server) + throw 'Server was not initialized.'; + return this.server; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRXhwcmVzc0FwcENvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIuLyIsInNvdXJjZXMiOlsiY29tcG9uZW50cy9FeHByZXNzQXBwQ29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBLE9BQU8sb0JBQW9CLE1BQU0seUJBQXlCLENBQUM7QUFDM0QsT0FBTyxPQUEwQixNQUFNLFNBQVMsQ0FBQztBQUNqRCxPQUFPLE1BQU0sTUFBTSxXQUFXLENBQUM7QUFHL0IsTUFBTSxDQUFDLE9BQU8sT0FBTyxtQkFBb0IsU0FBUSxvQkFBMEI7SUFJdkUsWUFBWSxJQUFZO1FBQ3BCLEtBQUssRUFBRSxDQUFDO1FBQ1IsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7SUFDckIsQ0FBQztJQUVZLEtBQUssQ0FBQyxHQUFZLEVBQUUsTUFBYzs7WUFDM0MsSUFBSSxDQUFDLE1BQU0sR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsV0FBVyxFQUFFLEdBQUcsRUFBRTtnQkFDbEQsTUFBTSxDQUFDLElBQUksQ0FBQyxtQ0FBbUMsSUFBSSxDQUFDLElBQUksR0FBRyxDQUFDLENBQUM7WUFDakUsQ0FBQyxDQUFDLENBQUM7WUFFSCxNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1lBQzNCLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7WUFFakMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLEVBQUU7Z0JBQzFCLEdBQUcsQ0FBQyxNQUFNLEdBQUcsRUFBRSxDQUFDO2dCQUNoQixHQUFHLENBQUMsZ0JBQWdCLEdBQUcsRUFBRSxDQUFDO2dCQUMxQixJQUFJLEVBQUUsQ0FBQztZQUNYLENBQUMsQ0FBQyxDQUFDO1FBQ1AsQ0FBQztLQUFBO0lBRVksSUFBSTs7WUFDYixJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUU7Z0JBQ2IsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7YUFDakU7UUFDTCxDQUFDO0tBQUE7SUFFTSxTQUFTO1FBQ1osSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNO1lBQUUsTUFBTSw2QkFBNkIsQ0FBQztRQUN0RCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUM7SUFDdkIsQ0FBQztDQUNKIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IEFwcGxpY2F0aW9uQ29tcG9uZW50IGZyb20gXCIuLi9BcHBsaWNhdGlvbkNvbXBvbmVudFwiO1xuaW1wb3J0IGV4cHJlc3MsIHtFeHByZXNzLCBSb3V0ZXJ9IGZyb20gXCJleHByZXNzXCI7XG5pbXBvcnQgTG9nZ2VyIGZyb20gXCIuLi9Mb2dnZXJcIjtcbmltcG9ydCB7U2VydmVyfSBmcm9tIFwiaHR0cFwiO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBFeHByZXNzQXBwQ29tcG9uZW50IGV4dGVuZHMgQXBwbGljYXRpb25Db21wb25lbnQ8dm9pZD4ge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgcG9ydDogbnVtYmVyO1xuICAgIHByaXZhdGUgc2VydmVyPzogU2VydmVyO1xuXG4gICAgY29uc3RydWN0b3IocG9ydDogbnVtYmVyKSB7XG4gICAgICAgIHN1cGVyKCk7XG4gICAgICAgIHRoaXMucG9ydCA9IHBvcnQ7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHN0YXJ0KGFwcDogRXhwcmVzcywgcm91dGVyOiBSb3V0ZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy5zZXJ2ZXIgPSBhcHAubGlzdGVuKHRoaXMucG9ydCwgJ2xvY2FsaG9zdCcsICgpID0+IHtcbiAgICAgICAgICAgIExvZ2dlci5pbmZvKGBXZWIgc2VydmVyIHJ1bm5pbmcgb24gbG9jYWxob3N0OiR7dGhpcy5wb3J0fS5gKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcm91dGVyLnVzZShleHByZXNzLmpzb24oKSk7XG4gICAgICAgIHJvdXRlci51c2UoZXhwcmVzcy51cmxlbmNvZGVkKCkpO1xuXG4gICAgICAgIHJvdXRlci51c2UoKHJlcSwgcmVzLCBuZXh0KSA9PiB7XG4gICAgICAgICAgICByZXEubW9kZWxzID0ge307XG4gICAgICAgICAgICByZXEubW9kZWxDb2xsZWN0aW9ucyA9IHt9O1xuICAgICAgICAgICAgbmV4dCgpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc3RvcCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKHRoaXMuc2VydmVyKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmNsb3NlKCdXZWJzZXJ2ZXInLCB0aGlzLnNlcnZlciwgdGhpcy5zZXJ2ZXIuY2xvc2UpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIGdldFNlcnZlcigpOiBTZXJ2ZXIge1xuICAgICAgICBpZiAoIXRoaXMuc2VydmVyKSB0aHJvdyAnU2VydmVyIHdhcyBub3QgaW5pdGlhbGl6ZWQuJztcbiAgICAgICAgcmV0dXJuIHRoaXMuc2VydmVyO1xuICAgIH1cbn0iXX0= \ No newline at end of file diff --git a/dist/components/FormHelperComponent.d.ts b/dist/components/FormHelperComponent.d.ts new file mode 100644 index 0000000..2d69e20 --- /dev/null +++ b/dist/components/FormHelperComponent.d.ts @@ -0,0 +1,6 @@ +import ApplicationComponent from "../ApplicationComponent"; +import { Express, Router } from "express"; +export default class FormHelperComponent extends ApplicationComponent { + start(app: Express, router: Router): Promise; + stop(): Promise; +} diff --git a/dist/components/FormHelperComponent.js b/dist/components/FormHelperComponent.js new file mode 100644 index 0000000..3e207cd --- /dev/null +++ b/dist/components/FormHelperComponent.js @@ -0,0 +1,52 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import ApplicationComponent from "../ApplicationComponent"; +export default class FormHelperComponent extends ApplicationComponent { + start(app, router) { + return __awaiter(this, void 0, void 0, function* () { + router.use((req, res, next) => { + if (!req.session) { + throw new Error('Session is unavailable.'); + } + res.locals.query = req.query; + let _validation = null; + res.locals.validation = () => { + if (!_validation) { + const v = req.flash('validation'); + _validation = v.length > 0 ? v[0] : null; + } + return _validation; + }; + let _previousFormData = null; + res.locals.previousFormData = () => { + if (!_previousFormData) { + const v = req.flash('previousFormData'); + _previousFormData = v.length > 0 ? v[0] : null; + } + return _previousFormData; + }; + next(); + }); + router.use((req, res, next) => { + if (['GET', 'POST'].find(m => m === req.method)) { + if (typeof req.body === 'object') { + req.flash('previousFormData', req.body); + } + } + next(); + }); + }); + } + stop() { + return __awaiter(this, void 0, void 0, function* () { + }); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRm9ybUhlbHBlckNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIuLyIsInNvdXJjZXMiOlsiY29tcG9uZW50cy9Gb3JtSGVscGVyQ29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBLE9BQU8sb0JBQW9CLE1BQU0seUJBQXlCLENBQUM7QUFHM0QsTUFBTSxDQUFDLE9BQU8sT0FBTyxtQkFBb0IsU0FBUSxvQkFBMEI7SUFDMUQsS0FBSyxDQUFDLEdBQVksRUFBRSxNQUFjOztZQUMzQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsRUFBRTtnQkFDMUIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUU7b0JBQ2QsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO2lCQUM5QztnQkFFRCxHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUssR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDO2dCQUU3QixJQUFJLFdBQVcsR0FBUSxJQUFJLENBQUM7Z0JBQzVCLEdBQUcsQ0FBQyxNQUFNLENBQUMsVUFBVSxHQUFHLEdBQUcsRUFBRTtvQkFDekIsSUFBSSxDQUFDLFdBQVcsRUFBRTt3QkFDZCxNQUFNLENBQUMsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFDO3dCQUNsQyxXQUFXLEdBQUcsQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO3FCQUM1QztvQkFFRCxPQUFPLFdBQVcsQ0FBQztnQkFDdkIsQ0FBQyxDQUFBO2dCQUVELElBQUksaUJBQWlCLEdBQVEsSUFBSSxDQUFDO2dCQUNsQyxHQUFHLENBQUMsTUFBTSxDQUFDLGdCQUFnQixHQUFHLEdBQUcsRUFBRTtvQkFDL0IsSUFBSSxDQUFDLGlCQUFpQixFQUFFO3dCQUNwQixNQUFNLENBQUMsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLGtCQUFrQixDQUFDLENBQUM7d0JBQ3hDLGlCQUFpQixHQUFHLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztxQkFDbkQ7b0JBRUQsT0FBTyxpQkFBaUIsQ0FBQztnQkFDN0IsQ0FBQyxDQUFDO2dCQUNGLElBQUksRUFBRSxDQUFDO1lBQ1gsQ0FBQyxDQUFDLENBQUM7WUFFSCxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsRUFBRTtnQkFDMUIsSUFBSSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFO29CQUM3QyxJQUFJLE9BQU8sR0FBRyxDQUFDLElBQUksS0FBSyxRQUFRLEVBQUU7d0JBQzlCLEdBQUcsQ0FBQyxLQUFLLENBQUMsa0JBQWtCLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO3FCQUMzQztpQkFDSjtnQkFDRCxJQUFJLEVBQUUsQ0FBQztZQUNYLENBQUMsQ0FBQyxDQUFDO1FBQ1AsQ0FBQztLQUFBO0lBRVksSUFBSTs7UUFDakIsQ0FBQztLQUFBO0NBRUoiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgQXBwbGljYXRpb25Db21wb25lbnQgZnJvbSBcIi4uL0FwcGxpY2F0aW9uQ29tcG9uZW50XCI7XG5pbXBvcnQge0V4cHJlc3MsIFJvdXRlcn0gZnJvbSBcImV4cHJlc3NcIjtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRm9ybUhlbHBlckNvbXBvbmVudCBleHRlbmRzIEFwcGxpY2F0aW9uQ29tcG9uZW50PHZvaWQ+IHtcbiAgICBwdWJsaWMgYXN5bmMgc3RhcnQoYXBwOiBFeHByZXNzLCByb3V0ZXI6IFJvdXRlcik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICByb3V0ZXIudXNlKChyZXEsIHJlcywgbmV4dCkgPT4ge1xuICAgICAgICAgICAgaWYgKCFyZXEuc2Vzc2lvbikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignU2Vzc2lvbiBpcyB1bmF2YWlsYWJsZS4nKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmVzLmxvY2Fscy5xdWVyeSA9IHJlcS5xdWVyeTtcblxuICAgICAgICAgICAgbGV0IF92YWxpZGF0aW9uOiBhbnkgPSBudWxsO1xuICAgICAgICAgICAgcmVzLmxvY2Fscy52YWxpZGF0aW9uID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmICghX3ZhbGlkYXRpb24pIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdiA9IHJlcS5mbGFzaCgndmFsaWRhdGlvbicpO1xuICAgICAgICAgICAgICAgICAgICBfdmFsaWRhdGlvbiA9IHYubGVuZ3RoID4gMCA/IHZbMF0gOiBudWxsO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBfdmFsaWRhdGlvbjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbGV0IF9wcmV2aW91c0Zvcm1EYXRhOiBhbnkgPSBudWxsO1xuICAgICAgICAgICAgcmVzLmxvY2Fscy5wcmV2aW91c0Zvcm1EYXRhID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmICghX3ByZXZpb3VzRm9ybURhdGEpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdiA9IHJlcS5mbGFzaCgncHJldmlvdXNGb3JtRGF0YScpO1xuICAgICAgICAgICAgICAgICAgICBfcHJldmlvdXNGb3JtRGF0YSA9IHYubGVuZ3RoID4gMCA/IHYgWzBdIDogbnVsbDtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gX3ByZXZpb3VzRm9ybURhdGE7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgbmV4dCgpO1xuICAgICAgICB9KTtcblxuICAgICAgICByb3V0ZXIudXNlKChyZXEsIHJlcywgbmV4dCkgPT4ge1xuICAgICAgICAgICAgaWYgKFsnR0VUJywgJ1BPU1QnXS5maW5kKG0gPT4gbSA9PT0gcmVxLm1ldGhvZCkpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHJlcS5ib2R5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgICAgICByZXEuZmxhc2goJ3ByZXZpb3VzRm9ybURhdGEnLCByZXEuYm9keSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbmV4dCgpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc3RvcCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB9XG5cbn0iXX0= \ No newline at end of file diff --git a/dist/components/LogRequestsComponent.d.ts b/dist/components/LogRequestsComponent.d.ts new file mode 100644 index 0000000..c043dc4 --- /dev/null +++ b/dist/components/LogRequestsComponent.d.ts @@ -0,0 +1,6 @@ +import ApplicationComponent from "../ApplicationComponent"; +import { Express, Router } from "express"; +export default class LogRequestsComponent extends ApplicationComponent { + start(app: Express, router: Router): Promise; + stop(): Promise; +} diff --git a/dist/components/LogRequestsComponent.js b/dist/components/LogRequestsComponent.js new file mode 100644 index 0000000..2d5ea22 --- /dev/null +++ b/dist/components/LogRequestsComponent.js @@ -0,0 +1,31 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import ApplicationComponent from "../ApplicationComponent"; +import onFinished from "on-finished"; +import Logger from "../Logger"; +export default class LogRequestsComponent extends ApplicationComponent { + start(app, router) { + return __awaiter(this, void 0, void 0, function* () { + router.use((req, res, next) => { + onFinished(res, (err) => { + if (!err) { + Logger.info(`${req.method} ${req.originalUrl} - ${res.statusCode}`); + } + }); + next(); + }); + }); + } + stop() { + return __awaiter(this, void 0, void 0, function* () { + }); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTG9nUmVxdWVzdHNDb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiLi8iLCJzb3VyY2VzIjpbImNvbXBvbmVudHMvTG9nUmVxdWVzdHNDb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBQUEsT0FBTyxvQkFBb0IsTUFBTSx5QkFBeUIsQ0FBQztBQUMzRCxPQUFPLFVBQVUsTUFBTSxhQUFhLENBQUM7QUFDckMsT0FBTyxNQUFNLE1BQU0sV0FBVyxDQUFDO0FBRy9CLE1BQU0sQ0FBQyxPQUFPLE9BQU8sb0JBQXFCLFNBQVEsb0JBQTBCO0lBQzNELEtBQUssQ0FBQyxHQUFZLEVBQUUsTUFBYzs7WUFDM0MsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLEVBQUU7Z0JBQzFCLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRTtvQkFDcEIsSUFBSSxDQUFDLEdBQUcsRUFBRTt3QkFDTixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsR0FBRyxDQUFDLE1BQU0sSUFBSSxHQUFHLENBQUMsV0FBVyxNQUFNLEdBQUcsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO3FCQUN2RTtnQkFDTCxDQUFDLENBQUMsQ0FBQztnQkFDSCxJQUFJLEVBQUUsQ0FBQztZQUNYLENBQUMsQ0FBQyxDQUFDO1FBQ1AsQ0FBQztLQUFBO0lBRVksSUFBSTs7UUFDakIsQ0FBQztLQUFBO0NBRUoiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgQXBwbGljYXRpb25Db21wb25lbnQgZnJvbSBcIi4uL0FwcGxpY2F0aW9uQ29tcG9uZW50XCI7XG5pbXBvcnQgb25GaW5pc2hlZCBmcm9tIFwib24tZmluaXNoZWRcIjtcbmltcG9ydCBMb2dnZXIgZnJvbSBcIi4uL0xvZ2dlclwiO1xuaW1wb3J0IHtFeHByZXNzLCBSb3V0ZXJ9IGZyb20gXCJleHByZXNzXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIExvZ1JlcXVlc3RzQ29tcG9uZW50IGV4dGVuZHMgQXBwbGljYXRpb25Db21wb25lbnQ8dm9pZD4ge1xuICAgIHB1YmxpYyBhc3luYyBzdGFydChhcHA6IEV4cHJlc3MsIHJvdXRlcjogUm91dGVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHJvdXRlci51c2UoKHJlcSwgcmVzLCBuZXh0KSA9PiB7XG4gICAgICAgICAgICBvbkZpbmlzaGVkKHJlcywgKGVycikgPT4ge1xuICAgICAgICAgICAgICAgIGlmICghZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIExvZ2dlci5pbmZvKGAke3JlcS5tZXRob2R9ICR7cmVxLm9yaWdpbmFsVXJsfSAtICR7cmVzLnN0YXR1c0NvZGV9YCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBuZXh0KCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBzdG9wKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIH1cblxufSJdfQ== \ No newline at end of file diff --git a/dist/components/MailComponent.d.ts b/dist/components/MailComponent.d.ts new file mode 100644 index 0000000..d708d33 --- /dev/null +++ b/dist/components/MailComponent.d.ts @@ -0,0 +1,6 @@ +import ApplicationComponent from "../ApplicationComponent"; +import { Express, Router } from "express"; +export default class MailComponent extends ApplicationComponent { + start(app: Express, router: Router): Promise; + stop(): Promise; +} diff --git a/dist/components/MailComponent.js b/dist/components/MailComponent.js new file mode 100644 index 0000000..1cd2a88 --- /dev/null +++ b/dist/components/MailComponent.js @@ -0,0 +1,24 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import ApplicationComponent from "../ApplicationComponent"; +import Mail from "../Mail"; +export default class MailComponent extends ApplicationComponent { + start(app, router) { + return __awaiter(this, void 0, void 0, function* () { + yield this.prepare('Mail connection', () => Mail.prepare()); + }); + } + stop() { + return __awaiter(this, void 0, void 0, function* () { + Mail.end(); + }); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWFpbENvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIuLyIsInNvdXJjZXMiOlsiY29tcG9uZW50cy9NYWlsQ29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBLE9BQU8sb0JBQW9CLE1BQU0seUJBQXlCLENBQUM7QUFFM0QsT0FBTyxJQUFJLE1BQU0sU0FBUyxDQUFDO0FBRTNCLE1BQU0sQ0FBQyxPQUFPLE9BQU8sYUFBYyxTQUFRLG9CQUEwQjtJQUNwRCxLQUFLLENBQUMsR0FBWSxFQUFFLE1BQWM7O1lBQzNDLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUNoRSxDQUFDO0tBQUE7SUFFWSxJQUFJOztZQUNiLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUNmLENBQUM7S0FBQTtDQUVKIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IEFwcGxpY2F0aW9uQ29tcG9uZW50IGZyb20gXCIuLi9BcHBsaWNhdGlvbkNvbXBvbmVudFwiO1xuaW1wb3J0IHtFeHByZXNzLCBSb3V0ZXJ9IGZyb20gXCJleHByZXNzXCI7XG5pbXBvcnQgTWFpbCBmcm9tIFwiLi4vTWFpbFwiO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNYWlsQ29tcG9uZW50IGV4dGVuZHMgQXBwbGljYXRpb25Db21wb25lbnQ8dm9pZD4ge1xuICAgIHB1YmxpYyBhc3luYyBzdGFydChhcHA6IEV4cHJlc3MsIHJvdXRlcjogUm91dGVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMucHJlcGFyZSgnTWFpbCBjb25uZWN0aW9uJywgKCkgPT4gTWFpbC5wcmVwYXJlKCkpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBzdG9wKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBNYWlsLmVuZCgpO1xuICAgIH1cblxufSJdfQ== \ No newline at end of file diff --git a/dist/components/MaintenanceComponent.d.ts b/dist/components/MaintenanceComponent.d.ts new file mode 100644 index 0000000..01fc5a7 --- /dev/null +++ b/dist/components/MaintenanceComponent.d.ts @@ -0,0 +1,10 @@ +import ApplicationComponent from "../ApplicationComponent"; +import { Express, Router } from "express"; +import Application from "../Application"; +export default class MaintenanceComponent extends ApplicationComponent { + private readonly application; + private readonly canServe; + constructor(application: Application, canServe: () => boolean); + start(app: Express, router: Router): Promise; + stop(): Promise; +} diff --git a/dist/components/MaintenanceComponent.js b/dist/components/MaintenanceComponent.js new file mode 100644 index 0000000..b590313 --- /dev/null +++ b/dist/components/MaintenanceComponent.js @@ -0,0 +1,42 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import ApplicationComponent from "../ApplicationComponent"; +import { ServiceUnavailableHttpError } from "../HttpError"; +export default class MaintenanceComponent extends ApplicationComponent { + constructor(application, canServe) { + super(); + this.application = application; + this.canServe = canServe; + } + start(app, router) { + return __awaiter(this, void 0, void 0, function* () { + router.use((req, res, next) => { + if (res.headersSent) { + return next(); + } + if (!this.application.isReady()) { + res.header({ 'Retry-After': 60 }); + res.locals.refresh_after = 5; + throw new ServiceUnavailableHttpError('Watch My Stream is readying up. Please wait a few seconds...'); + } + if (!this.canServe()) { + res.locals.refresh_after = 30; + throw new ServiceUnavailableHttpError('Watch My Stream is unavailable due to failure of dependent services.'); + } + next(); + }); + }); + } + stop() { + return __awaiter(this, void 0, void 0, function* () { + }); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWFpbnRlbmFuY2VDb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiLi8iLCJzb3VyY2VzIjpbImNvbXBvbmVudHMvTWFpbnRlbmFuY2VDb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBQUEsT0FBTyxvQkFBb0IsTUFBTSx5QkFBeUIsQ0FBQztBQUUzRCxPQUFPLEVBQUMsMkJBQTJCLEVBQUMsTUFBTSxjQUFjLENBQUM7QUFHekQsTUFBTSxDQUFDLE9BQU8sT0FBTyxvQkFBcUIsU0FBUSxvQkFBMEI7SUFJeEUsWUFBWSxXQUF3QixFQUFFLFFBQXVCO1FBQ3pELEtBQUssRUFBRSxDQUFDO1FBQ1IsSUFBSSxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUM7UUFDL0IsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7SUFDN0IsQ0FBQztJQUVZLEtBQUssQ0FBQyxHQUFZLEVBQUUsTUFBYzs7WUFDM0MsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQVksRUFBRSxHQUFhLEVBQUUsSUFBa0IsRUFBRSxFQUFFO2dCQUMzRCxJQUFJLEdBQUcsQ0FBQyxXQUFXLEVBQUU7b0JBQ2pCLE9BQU8sSUFBSSxFQUFFLENBQUM7aUJBQ2pCO2dCQUVELElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sRUFBRSxFQUFFO29CQUM3QixHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUMsYUFBYSxFQUFFLEVBQUUsRUFBQyxDQUFDLENBQUM7b0JBQ2hDLEdBQUcsQ0FBQyxNQUFNLENBQUMsYUFBYSxHQUFHLENBQUMsQ0FBQztvQkFDN0IsTUFBTSxJQUFJLDJCQUEyQixDQUFDLDhEQUE4RCxDQUFDLENBQUM7aUJBQ3pHO2dCQUVELElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLEVBQUU7b0JBQ2xCLEdBQUcsQ0FBQyxNQUFNLENBQUMsYUFBYSxHQUFHLEVBQUUsQ0FBQztvQkFDOUIsTUFBTSxJQUFJLDJCQUEyQixDQUFDLHNFQUFzRSxDQUFDLENBQUM7aUJBQ2pIO2dCQUVELElBQUksRUFBRSxDQUFDO1lBQ1gsQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDO0tBQUE7SUFFWSxJQUFJOztRQUNqQixDQUFDO0tBQUE7Q0FFSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBBcHBsaWNhdGlvbkNvbXBvbmVudCBmcm9tIFwiLi4vQXBwbGljYXRpb25Db21wb25lbnRcIjtcbmltcG9ydCB7RXhwcmVzcywgTmV4dEZ1bmN0aW9uLCBSZXF1ZXN0LCBSZXNwb25zZSwgUm91dGVyfSBmcm9tIFwiZXhwcmVzc1wiO1xuaW1wb3J0IHtTZXJ2aWNlVW5hdmFpbGFibGVIdHRwRXJyb3J9IGZyb20gXCIuLi9IdHRwRXJyb3JcIjtcbmltcG9ydCBBcHBsaWNhdGlvbiBmcm9tIFwiLi4vQXBwbGljYXRpb25cIjtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTWFpbnRlbmFuY2VDb21wb25lbnQgZXh0ZW5kcyBBcHBsaWNhdGlvbkNvbXBvbmVudDx2b2lkPiB7XG4gICAgcHJpdmF0ZSByZWFkb25seSBhcHBsaWNhdGlvbjogQXBwbGljYXRpb247XG4gICAgcHJpdmF0ZSByZWFkb25seSBjYW5TZXJ2ZTogKCkgPT4gYm9vbGVhbjtcblxuICAgIGNvbnN0cnVjdG9yKGFwcGxpY2F0aW9uOiBBcHBsaWNhdGlvbiwgY2FuU2VydmU6ICgpID0+IGJvb2xlYW4pIHtcbiAgICAgICAgc3VwZXIoKTtcbiAgICAgICAgdGhpcy5hcHBsaWNhdGlvbiA9IGFwcGxpY2F0aW9uO1xuICAgICAgICB0aGlzLmNhblNlcnZlID0gY2FuU2VydmU7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHN0YXJ0KGFwcDogRXhwcmVzcywgcm91dGVyOiBSb3V0ZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgcm91dGVyLnVzZSgocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pID0+IHtcbiAgICAgICAgICAgIGlmIChyZXMuaGVhZGVyc1NlbnQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV4dCgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIXRoaXMuYXBwbGljYXRpb24uaXNSZWFkeSgpKSB7XG4gICAgICAgICAgICAgICAgcmVzLmhlYWRlcih7J1JldHJ5LUFmdGVyJzogNjB9KTtcbiAgICAgICAgICAgICAgICByZXMubG9jYWxzLnJlZnJlc2hfYWZ0ZXIgPSA1O1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBTZXJ2aWNlVW5hdmFpbGFibGVIdHRwRXJyb3IoJ1dhdGNoIE15IFN0cmVhbSBpcyByZWFkeWluZyB1cC4gUGxlYXNlIHdhaXQgYSBmZXcgc2Vjb25kcy4uLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIXRoaXMuY2FuU2VydmUoKSkge1xuICAgICAgICAgICAgICAgIHJlcy5sb2NhbHMucmVmcmVzaF9hZnRlciA9IDMwO1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBTZXJ2aWNlVW5hdmFpbGFibGVIdHRwRXJyb3IoJ1dhdGNoIE15IFN0cmVhbSBpcyB1bmF2YWlsYWJsZSBkdWUgdG8gZmFpbHVyZSBvZiBkZXBlbmRlbnQgc2VydmljZXMuJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG5leHQoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHN0b3AoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgfVxuXG59Il19 \ No newline at end of file diff --git a/dist/components/MysqlComponent.d.ts b/dist/components/MysqlComponent.d.ts new file mode 100644 index 0000000..2b1fd92 --- /dev/null +++ b/dist/components/MysqlComponent.d.ts @@ -0,0 +1,7 @@ +import ApplicationComponent from "../ApplicationComponent"; +import { Express, Router } from "express"; +export default class MysqlComponent extends ApplicationComponent { + start(app: Express, router: Router): Promise; + stop(): Promise; + canServe(): boolean; +} diff --git a/dist/components/MysqlComponent.js b/dist/components/MysqlComponent.js new file mode 100644 index 0000000..7c7816d --- /dev/null +++ b/dist/components/MysqlComponent.js @@ -0,0 +1,27 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import ApplicationComponent from "../ApplicationComponent"; +import MysqlConnectionManager from "../db/MysqlConnectionManager"; +export default class MysqlComponent extends ApplicationComponent { + start(app, router) { + return __awaiter(this, void 0, void 0, function* () { + yield this.prepare('Mysql connection', () => MysqlConnectionManager.prepare()); + }); + } + stop() { + return __awaiter(this, void 0, void 0, function* () { + yield MysqlConnectionManager.endPool(); + }); + } + canServe() { + return MysqlConnectionManager.pool !== undefined; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTXlzcWxDb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiLi8iLCJzb3VyY2VzIjpbImNvbXBvbmVudHMvTXlzcWxDb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBQUEsT0FBTyxvQkFBb0IsTUFBTSx5QkFBeUIsQ0FBQztBQUUzRCxPQUFPLHNCQUFzQixNQUFNLDhCQUE4QixDQUFDO0FBRWxFLE1BQU0sQ0FBQyxPQUFPLE9BQU8sY0FBZSxTQUFRLG9CQUEwQjtJQUNyRCxLQUFLLENBQUMsR0FBWSxFQUFFLE1BQWM7O1lBQzNDLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxrQkFBa0IsRUFBRSxHQUFHLEVBQUUsQ0FBQyxzQkFBc0IsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ25GLENBQUM7S0FBQTtJQUVZLElBQUk7O1lBQ2IsTUFBTSxzQkFBc0IsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUMzQyxDQUFDO0tBQUE7SUFFTSxRQUFRO1FBQ1gsT0FBTyxzQkFBc0IsQ0FBQyxJQUFJLEtBQUssU0FBUyxDQUFDO0lBQ3JELENBQUM7Q0FFSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBBcHBsaWNhdGlvbkNvbXBvbmVudCBmcm9tIFwiLi4vQXBwbGljYXRpb25Db21wb25lbnRcIjtcbmltcG9ydCB7RXhwcmVzcywgUm91dGVyfSBmcm9tIFwiZXhwcmVzc1wiO1xuaW1wb3J0IE15c3FsQ29ubmVjdGlvbk1hbmFnZXIgZnJvbSBcIi4uL2RiL015c3FsQ29ubmVjdGlvbk1hbmFnZXJcIjtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTXlzcWxDb21wb25lbnQgZXh0ZW5kcyBBcHBsaWNhdGlvbkNvbXBvbmVudDx2b2lkPiB7XG4gICAgcHVibGljIGFzeW5jIHN0YXJ0KGFwcDogRXhwcmVzcywgcm91dGVyOiBSb3V0ZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5wcmVwYXJlKCdNeXNxbCBjb25uZWN0aW9uJywgKCkgPT4gTXlzcWxDb25uZWN0aW9uTWFuYWdlci5wcmVwYXJlKCkpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBzdG9wKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCBNeXNxbENvbm5lY3Rpb25NYW5hZ2VyLmVuZFBvb2woKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgY2FuU2VydmUoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBNeXNxbENvbm5lY3Rpb25NYW5hZ2VyLnBvb2wgIT09IHVuZGVmaW5lZDtcbiAgICB9XG5cbn0iXX0= \ No newline at end of file diff --git a/dist/components/RedirectBackComponent.d.ts b/dist/components/RedirectBackComponent.d.ts new file mode 100644 index 0000000..1958ecb --- /dev/null +++ b/dist/components/RedirectBackComponent.d.ts @@ -0,0 +1,6 @@ +import ApplicationComponent from "../ApplicationComponent"; +import { Express, Router } from "express"; +export default class RedirectBackComponent extends ApplicationComponent { + start(app: Express, router: Router): Promise; + stop(): Promise; +} diff --git a/dist/components/RedirectBackComponent.js b/dist/components/RedirectBackComponent.js new file mode 100644 index 0000000..20364e0 --- /dev/null +++ b/dist/components/RedirectBackComponent.js @@ -0,0 +1,52 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import ApplicationComponent from "../ApplicationComponent"; +import onFinished from "on-finished"; +import Logger from "../Logger"; +import { ServerError } from "../HttpError"; +export default class RedirectBackComponent extends ApplicationComponent { + start(app, router) { + return __awaiter(this, void 0, void 0, function* () { + router.use((req, res, next) => { + if (!req.session) { + throw new Error('Session is unavailable.'); + } + onFinished(res, (err) => { + if (!err && res.statusCode === 200) { + req.session.previousUrl = req.originalUrl; + Logger.debug('Prev url set to', req.session.previousUrl); + req.session.save((err) => { + if (err) { + Logger.error(err, 'Error while saving session'); + } + }); + } + }); + res.redirectBack = (defaultUrl) => { + if (req.session && typeof req.session.previousUrl === 'string') { + res.redirect(req.session.previousUrl); + } + else if (typeof defaultUrl === 'string') { + res.redirect(defaultUrl); + } + else { + throw new ServerError('There is no previous url and no default redirection url was provided.'); + } + }; + next(); + }); + }); + } + stop() { + return __awaiter(this, void 0, void 0, function* () { + }); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVkaXJlY3RCYWNrQ29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Ii4vIiwic291cmNlcyI6WyJjb21wb25lbnRzL1JlZGlyZWN0QmFja0NvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFBQSxPQUFPLG9CQUFvQixNQUFNLHlCQUF5QixDQUFDO0FBRTNELE9BQU8sVUFBVSxNQUFNLGFBQWEsQ0FBQztBQUNyQyxPQUFPLE1BQU0sTUFBTSxXQUFXLENBQUM7QUFDL0IsT0FBTyxFQUFDLFdBQVcsRUFBQyxNQUFNLGNBQWMsQ0FBQztBQUV6QyxNQUFNLENBQUMsT0FBTyxPQUFPLHFCQUFzQixTQUFRLG9CQUEwQjtJQUM1RCxLQUFLLENBQUMsR0FBWSxFQUFFLE1BQWM7O1lBQzNDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFO2dCQUMxQixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRTtvQkFDZCxNQUFNLElBQUksS0FBSyxDQUFDLHlCQUF5QixDQUFDLENBQUM7aUJBQzlDO2dCQUVELFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRTtvQkFDcEIsSUFBSSxDQUFDLEdBQUcsSUFBSSxHQUFHLENBQUMsVUFBVSxLQUFLLEdBQUcsRUFBRTt3QkFDaEMsR0FBRyxDQUFDLE9BQVEsQ0FBQyxXQUFXLEdBQUcsR0FBRyxDQUFDLFdBQVcsQ0FBQzt3QkFDM0MsTUFBTSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsRUFBRSxHQUFHLENBQUMsT0FBUSxDQUFDLFdBQVcsQ0FBQyxDQUFDO3dCQUMxRCxHQUFHLENBQUMsT0FBUSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFOzRCQUN0QixJQUFJLEdBQUcsRUFBRTtnQ0FDTCxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSw0QkFBNEIsQ0FBQyxDQUFDOzZCQUNuRDt3QkFDTCxDQUFDLENBQUMsQ0FBQztxQkFDTjtnQkFDTCxDQUFDLENBQUMsQ0FBQztnQkFFSCxHQUFHLENBQUMsWUFBWSxHQUFHLENBQUMsVUFBbUIsRUFBRSxFQUFFO29CQUN2QyxJQUFJLEdBQUcsQ0FBQyxPQUFPLElBQUksT0FBTyxHQUFHLENBQUMsT0FBTyxDQUFDLFdBQVcsS0FBSyxRQUFRLEVBQUU7d0JBQzVELEdBQUcsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztxQkFDekM7eUJBQU0sSUFBSSxPQUFPLFVBQVUsS0FBSyxRQUFRLEVBQUU7d0JBQ3ZDLEdBQUcsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUM7cUJBQzVCO3lCQUFNO3dCQUNILE1BQU0sSUFBSSxXQUFXLENBQUMsdUVBQXVFLENBQUMsQ0FBQztxQkFDbEc7Z0JBQ0wsQ0FBQyxDQUFDO2dCQUVGLElBQUksRUFBRSxDQUFDO1lBQ1gsQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDO0tBQUE7SUFFWSxJQUFJOztRQUNqQixDQUFDO0tBQUE7Q0FFSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBBcHBsaWNhdGlvbkNvbXBvbmVudCBmcm9tIFwiLi4vQXBwbGljYXRpb25Db21wb25lbnRcIjtcbmltcG9ydCB7RXhwcmVzcywgUm91dGVyfSBmcm9tIFwiZXhwcmVzc1wiO1xuaW1wb3J0IG9uRmluaXNoZWQgZnJvbSBcIm9uLWZpbmlzaGVkXCI7XG5pbXBvcnQgTG9nZ2VyIGZyb20gXCIuLi9Mb2dnZXJcIjtcbmltcG9ydCB7U2VydmVyRXJyb3J9IGZyb20gXCIuLi9IdHRwRXJyb3JcIjtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgUmVkaXJlY3RCYWNrQ29tcG9uZW50IGV4dGVuZHMgQXBwbGljYXRpb25Db21wb25lbnQ8dm9pZD4ge1xuICAgIHB1YmxpYyBhc3luYyBzdGFydChhcHA6IEV4cHJlc3MsIHJvdXRlcjogUm91dGVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHJvdXRlci51c2UoKHJlcSwgcmVzLCBuZXh0KSA9PiB7XG4gICAgICAgICAgICBpZiAoIXJlcS5zZXNzaW9uKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTZXNzaW9uIGlzIHVuYXZhaWxhYmxlLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBvbkZpbmlzaGVkKHJlcywgKGVycikgPT4ge1xuICAgICAgICAgICAgICAgIGlmICghZXJyICYmIHJlcy5zdGF0dXNDb2RlID09PSAyMDApIHtcbiAgICAgICAgICAgICAgICAgICAgcmVxLnNlc3Npb24hLnByZXZpb3VzVXJsID0gcmVxLm9yaWdpbmFsVXJsO1xuICAgICAgICAgICAgICAgICAgICBMb2dnZXIuZGVidWcoJ1ByZXYgdXJsIHNldCB0bycsIHJlcS5zZXNzaW9uIS5wcmV2aW91c1VybCk7XG4gICAgICAgICAgICAgICAgICAgIHJlcS5zZXNzaW9uIS5zYXZlKChlcnIpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBMb2dnZXIuZXJyb3IoZXJyLCAnRXJyb3Igd2hpbGUgc2F2aW5nIHNlc3Npb24nKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJlcy5yZWRpcmVjdEJhY2sgPSAoZGVmYXVsdFVybD86IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChyZXEuc2Vzc2lvbiAmJiB0eXBlb2YgcmVxLnNlc3Npb24ucHJldmlvdXNVcmwgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcy5yZWRpcmVjdChyZXEuc2Vzc2lvbi5wcmV2aW91c1VybCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgZGVmYXVsdFVybCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzLnJlZGlyZWN0KGRlZmF1bHRVcmwpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBTZXJ2ZXJFcnJvcignVGhlcmUgaXMgbm8gcHJldmlvdXMgdXJsIGFuZCBubyBkZWZhdWx0IHJlZGlyZWN0aW9uIHVybCB3YXMgcHJvdmlkZWQuJyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgbmV4dCgpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc3RvcCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB9XG5cbn0iXX0= \ No newline at end of file diff --git a/dist/components/RedisComponent.d.ts b/dist/components/RedisComponent.d.ts new file mode 100644 index 0000000..4e16e68 --- /dev/null +++ b/dist/components/RedisComponent.d.ts @@ -0,0 +1,11 @@ +import ApplicationComponent from "../ApplicationComponent"; +import { Express, Router } from "express"; +import { Store } from "express-session"; +export default class RedisComponent extends ApplicationComponent { + private redisClient?; + private store?; + start(app: Express, router: Router): Promise; + stop(): Promise; + getStore(): Store; + canServe(): boolean; +} diff --git a/dist/components/RedisComponent.js b/dist/components/RedisComponent.js new file mode 100644 index 0000000..a6a9d5f --- /dev/null +++ b/dist/components/RedisComponent.js @@ -0,0 +1,46 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import ApplicationComponent from "../ApplicationComponent"; +import redis from "redis"; +import config from "config"; +import Logger from "../Logger"; +import session from "express-session"; +import connect_redis from "connect-redis"; +const RedisStore = connect_redis(session); +export default class RedisComponent extends ApplicationComponent { + start(app, router) { + return __awaiter(this, void 0, void 0, function* () { + this.redisClient = redis.createClient(config.get('redis.port'), config.get('redis.host'), {}); + this.redisClient.on('error', (err) => { + Logger.error(err, 'An error occurred with redis.'); + }); + this.store = new RedisStore({ + client: this.redisClient, + prefix: 'wms-sess:', + }); + }); + } + stop() { + return __awaiter(this, void 0, void 0, function* () { + if (this.redisClient) { + yield this.close('Redis connection', this.redisClient, this.redisClient.quit); + } + }); + } + getStore() { + if (!this.store) + throw `Redis store was not initialized.`; + return this.store; + } + canServe() { + return this.redisClient !== undefined && this.redisClient.connected; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVkaXNDb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiLi8iLCJzb3VyY2VzIjpbImNvbXBvbmVudHMvUmVkaXNDb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBQUEsT0FBTyxvQkFBb0IsTUFBTSx5QkFBeUIsQ0FBQztBQUUzRCxPQUFPLEtBQW9CLE1BQU0sT0FBTyxDQUFDO0FBQ3pDLE9BQU8sTUFBTSxNQUFNLFFBQVEsQ0FBQztBQUM1QixPQUFPLE1BQU0sTUFBTSxXQUFXLENBQUM7QUFDL0IsT0FBTyxPQUFnQixNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sYUFBYSxNQUFNLGVBQWUsQ0FBQztBQUUxQyxNQUFNLFVBQVUsR0FBRyxhQUFhLENBQUMsT0FBTyxDQUFDLENBQUM7QUFFMUMsTUFBTSxDQUFDLE9BQU8sT0FBTyxjQUFlLFNBQVEsb0JBQTBCO0lBSXJELEtBQUssQ0FBQyxHQUFZLEVBQUUsTUFBYzs7WUFDM0MsSUFBSSxDQUFDLFdBQVcsR0FBRyxLQUFLLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLEVBQUUsTUFBTSxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUM5RixJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxHQUFRLEVBQUUsRUFBRTtnQkFDdEMsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsK0JBQStCLENBQUMsQ0FBQztZQUN2RCxDQUFDLENBQUMsQ0FBQztZQUNILElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxVQUFVLENBQUM7Z0JBQ3hCLE1BQU0sRUFBRSxJQUFJLENBQUMsV0FBVztnQkFDeEIsTUFBTSxFQUFFLFdBQVc7YUFDdEIsQ0FBQyxDQUFDO1FBQ1AsQ0FBQztLQUFBO0lBRVksSUFBSTs7WUFDYixJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUU7Z0JBQ2xCLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsRUFBRSxJQUFJLENBQUMsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7YUFDakY7UUFDTCxDQUFDO0tBQUE7SUFFTSxRQUFRO1FBQ1gsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLO1lBQUUsTUFBTSxrQ0FBa0MsQ0FBQztRQUMxRCxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDdEIsQ0FBQztJQUVNLFFBQVE7UUFDWCxPQUFPLElBQUksQ0FBQyxXQUFXLEtBQUssU0FBUyxJQUFJLElBQUksQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDO0lBQ3hFLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBBcHBsaWNhdGlvbkNvbXBvbmVudCBmcm9tIFwiLi4vQXBwbGljYXRpb25Db21wb25lbnRcIjtcbmltcG9ydCB7RXhwcmVzcywgUm91dGVyfSBmcm9tIFwiZXhwcmVzc1wiO1xuaW1wb3J0IHJlZGlzLCB7UmVkaXNDbGllbnR9IGZyb20gXCJyZWRpc1wiO1xuaW1wb3J0IGNvbmZpZyBmcm9tIFwiY29uZmlnXCI7XG5pbXBvcnQgTG9nZ2VyIGZyb20gXCIuLi9Mb2dnZXJcIjtcbmltcG9ydCBzZXNzaW9uLCB7U3RvcmV9IGZyb20gXCJleHByZXNzLXNlc3Npb25cIjtcbmltcG9ydCBjb25uZWN0X3JlZGlzIGZyb20gXCJjb25uZWN0LXJlZGlzXCI7XG5cbmNvbnN0IFJlZGlzU3RvcmUgPSBjb25uZWN0X3JlZGlzKHNlc3Npb24pO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBSZWRpc0NvbXBvbmVudCBleHRlbmRzIEFwcGxpY2F0aW9uQ29tcG9uZW50PHZvaWQ+IHtcbiAgICBwcml2YXRlIHJlZGlzQ2xpZW50PzogUmVkaXNDbGllbnQ7XG4gICAgcHJpdmF0ZSBzdG9yZT86IFN0b3JlO1xuXG4gICAgcHVibGljIGFzeW5jIHN0YXJ0KGFwcDogRXhwcmVzcywgcm91dGVyOiBSb3V0ZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy5yZWRpc0NsaWVudCA9IHJlZGlzLmNyZWF0ZUNsaWVudChjb25maWcuZ2V0KCdyZWRpcy5wb3J0JyksIGNvbmZpZy5nZXQoJ3JlZGlzLmhvc3QnKSwge30pO1xuICAgICAgICB0aGlzLnJlZGlzQ2xpZW50Lm9uKCdlcnJvcicsIChlcnI6IGFueSkgPT4ge1xuICAgICAgICAgICAgTG9nZ2VyLmVycm9yKGVyciwgJ0FuIGVycm9yIG9jY3VycmVkIHdpdGggcmVkaXMuJyk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnN0b3JlID0gbmV3IFJlZGlzU3RvcmUoe1xuICAgICAgICAgICAgY2xpZW50OiB0aGlzLnJlZGlzQ2xpZW50LFxuICAgICAgICAgICAgcHJlZml4OiAnd21zLXNlc3M6JyxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHN0b3AoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aGlzLnJlZGlzQ2xpZW50KSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmNsb3NlKCdSZWRpcyBjb25uZWN0aW9uJywgdGhpcy5yZWRpc0NsaWVudCwgdGhpcy5yZWRpc0NsaWVudC5xdWl0KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBnZXRTdG9yZSgpOiBTdG9yZSB7XG4gICAgICAgIGlmICghdGhpcy5zdG9yZSkgdGhyb3cgYFJlZGlzIHN0b3JlIHdhcyBub3QgaW5pdGlhbGl6ZWQuYDtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RvcmU7XG4gICAgfVxuXG4gICAgcHVibGljIGNhblNlcnZlKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5yZWRpc0NsaWVudCAhPT0gdW5kZWZpbmVkICYmIHRoaXMucmVkaXNDbGllbnQuY29ubmVjdGVkO1xuICAgIH1cbn0iXX0= \ No newline at end of file diff --git a/dist/components/ServeStaticDirectoryComponent.d.ts b/dist/components/ServeStaticDirectoryComponent.d.ts new file mode 100644 index 0000000..ca770b3 --- /dev/null +++ b/dist/components/ServeStaticDirectoryComponent.d.ts @@ -0,0 +1,10 @@ +import ApplicationComponent from "../ApplicationComponent"; +import { Express, Router } from "express"; +import { PathParams } from "express-serve-static-core"; +export default class ServeStaticDirectoryComponent extends ApplicationComponent { + private readonly root; + private readonly path?; + constructor(root: string, routePath?: PathParams); + start(app: Express, router: Router): Promise; + stop(): Promise; +} diff --git a/dist/components/ServeStaticDirectoryComponent.js b/dist/components/ServeStaticDirectoryComponent.js new file mode 100644 index 0000000..2ead032 --- /dev/null +++ b/dist/components/ServeStaticDirectoryComponent.js @@ -0,0 +1,33 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import ApplicationComponent from "../ApplicationComponent"; +import express from "express"; +export default class ServeStaticDirectoryComponent extends ApplicationComponent { + constructor(root, routePath) { + super(); + this.root = root; + this.path = routePath; + } + start(app, router) { + return __awaiter(this, void 0, void 0, function* () { + if (typeof this.path !== 'undefined') { + router.use(this.path, express.static(this.root, { maxAge: 1000 * 3600 * 72 })); + } + else { + router.use(express.static(this.root, { maxAge: 1000 * 3600 * 72 })); + } + }); + } + stop() { + return __awaiter(this, void 0, void 0, function* () { + }); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VydmVTdGF0aWNEaXJlY3RvcnlDb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiLi8iLCJzb3VyY2VzIjpbImNvbXBvbmVudHMvU2VydmVTdGF0aWNEaXJlY3RvcnlDb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBQUEsT0FBTyxvQkFBb0IsTUFBTSx5QkFBeUIsQ0FBQztBQUMzRCxPQUFPLE9BQTBCLE1BQU0sU0FBUyxDQUFDO0FBR2pELE1BQU0sQ0FBQyxPQUFPLE9BQU8sNkJBQThCLFNBQVEsb0JBQTBCO0lBSWpGLFlBQVksSUFBWSxFQUFFLFNBQXNCO1FBQzVDLEtBQUssRUFBRSxDQUFDO1FBQ1IsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7UUFDakIsSUFBSSxDQUFDLElBQUksR0FBRyxTQUFTLENBQUM7SUFDMUIsQ0FBQztJQUVZLEtBQUssQ0FBQyxHQUFZLEVBQUUsTUFBYzs7WUFDM0MsSUFBSSxPQUFPLElBQUksQ0FBQyxJQUFJLEtBQUssV0FBVyxFQUFFO2dCQUNsQyxNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLEVBQUMsTUFBTSxFQUFFLElBQUksR0FBRyxJQUFJLEdBQUcsRUFBRSxFQUFDLENBQUMsQ0FBQyxDQUFDO2FBQ2hGO2lCQUFNO2dCQUNILE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLEVBQUMsTUFBTSxFQUFFLElBQUksR0FBRyxJQUFJLEdBQUcsRUFBRSxFQUFDLENBQUMsQ0FBQyxDQUFDO2FBQ3JFO1FBQ0wsQ0FBQztLQUFBO0lBRVksSUFBSTs7UUFDakIsQ0FBQztLQUFBO0NBRUoiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgQXBwbGljYXRpb25Db21wb25lbnQgZnJvbSBcIi4uL0FwcGxpY2F0aW9uQ29tcG9uZW50XCI7XG5pbXBvcnQgZXhwcmVzcywge0V4cHJlc3MsIFJvdXRlcn0gZnJvbSBcImV4cHJlc3NcIjtcbmltcG9ydCB7UGF0aFBhcmFtc30gZnJvbSBcImV4cHJlc3Mtc2VydmUtc3RhdGljLWNvcmVcIjtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgU2VydmVTdGF0aWNEaXJlY3RvcnlDb21wb25lbnQgZXh0ZW5kcyBBcHBsaWNhdGlvbkNvbXBvbmVudDx2b2lkPiB7XG4gICAgcHJpdmF0ZSByZWFkb25seSByb290OiBzdHJpbmc7XG4gICAgcHJpdmF0ZSByZWFkb25seSBwYXRoPzogUGF0aFBhcmFtcztcblxuICAgIGNvbnN0cnVjdG9yKHJvb3Q6IHN0cmluZywgcm91dGVQYXRoPzogUGF0aFBhcmFtcykge1xuICAgICAgICBzdXBlcigpO1xuICAgICAgICB0aGlzLnJvb3QgPSByb290O1xuICAgICAgICB0aGlzLnBhdGggPSByb3V0ZVBhdGg7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHN0YXJ0KGFwcDogRXhwcmVzcywgcm91dGVyOiBSb3V0ZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKHR5cGVvZiB0aGlzLnBhdGggIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICByb3V0ZXIudXNlKHRoaXMucGF0aCwgZXhwcmVzcy5zdGF0aWModGhpcy5yb290LCB7bWF4QWdlOiAxMDAwICogMzYwMCAqIDcyfSkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcm91dGVyLnVzZShleHByZXNzLnN0YXRpYyh0aGlzLnJvb3QsIHttYXhBZ2U6IDEwMDAgKiAzNjAwICogNzJ9KSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc3RvcCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB9XG5cbn0iXX0= \ No newline at end of file diff --git a/dist/components/SessionComponent.d.ts b/dist/components/SessionComponent.d.ts new file mode 100644 index 0000000..f2966f4 --- /dev/null +++ b/dist/components/SessionComponent.d.ts @@ -0,0 +1,9 @@ +import ApplicationComponent from "../ApplicationComponent"; +import RedisComponent from "./RedisComponent"; +import { Express, Router } from "express"; +export default class SessionComponent extends ApplicationComponent { + private readonly storeComponent; + constructor(storeComponent: RedisComponent); + start(app: Express, router: Router): Promise; + stop(): Promise; +} diff --git a/dist/components/SessionComponent.js b/dist/components/SessionComponent.js new file mode 100644 index 0000000..591bbdf --- /dev/null +++ b/dist/components/SessionComponent.js @@ -0,0 +1,59 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import ApplicationComponent from "../ApplicationComponent"; +import session from "express-session"; +import config from "config"; +import flash from "connect-flash"; +export default class SessionComponent extends ApplicationComponent { + constructor(storeComponent) { + super(); + this.storeComponent = storeComponent; + } + start(app, router) { + return __awaiter(this, void 0, void 0, function* () { + router.use(session({ + saveUninitialized: true, + secret: config.get('session.secret'), + store: this.storeComponent.getStore(), + resave: true, + cookie: { + httpOnly: true, + secure: config.get('session.cookie.secure'), + }, + rolling: true, + })); + router.use(flash()); + router.use((req, res, next) => { + if (!req.session) { + throw new Error('Session is unavailable.'); + } + res.locals.session = req.session; + let _flash = null; + res.locals.flash = () => { + if (!_flash) { + _flash = { + info: req.flash('info'), + success: req.flash('success'), + warning: req.flash('warning'), + error: req.flash('error'), + }; + } + return _flash; + }; + next(); + }); + }); + } + stop() { + return __awaiter(this, void 0, void 0, function* () { + }); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2Vzc2lvbkNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIuLyIsInNvdXJjZXMiOlsiY29tcG9uZW50cy9TZXNzaW9uQ29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBLE9BQU8sb0JBQW9CLE1BQU0seUJBQXlCLENBQUM7QUFDM0QsT0FBTyxPQUFPLE1BQU0saUJBQWlCLENBQUM7QUFDdEMsT0FBTyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBRTVCLE9BQU8sS0FBSyxNQUFNLGVBQWUsQ0FBQztBQUdsQyxNQUFNLENBQUMsT0FBTyxPQUFPLGdCQUFpQixTQUFRLG9CQUEwQjtJQUlwRSxZQUFtQixjQUE4QjtRQUM3QyxLQUFLLEVBQUUsQ0FBQztRQUNSLElBQUksQ0FBQyxjQUFjLEdBQUcsY0FBYyxDQUFDO0lBQ3pDLENBQUM7SUFFWSxLQUFLLENBQUMsR0FBWSxFQUFFLE1BQWM7O1lBQzNDLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDO2dCQUNmLGlCQUFpQixFQUFFLElBQUk7Z0JBQ3ZCLE1BQU0sRUFBRSxNQUFNLENBQUMsR0FBRyxDQUFDLGdCQUFnQixDQUFDO2dCQUNwQyxLQUFLLEVBQUUsSUFBSSxDQUFDLGNBQWMsQ0FBQyxRQUFRLEVBQUU7Z0JBQ3JDLE1BQU0sRUFBRSxJQUFJO2dCQUNaLE1BQU0sRUFBRTtvQkFDSixRQUFRLEVBQUUsSUFBSTtvQkFDZCxNQUFNLEVBQUUsTUFBTSxDQUFDLEdBQUcsQ0FBQyx1QkFBdUIsQ0FBQztpQkFDOUM7Z0JBQ0QsT0FBTyxFQUFFLElBQUk7YUFDaEIsQ0FBQyxDQUFDLENBQUM7WUFFSixNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7WUFFcEIsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLEVBQUU7Z0JBQzFCLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFO29CQUNkLE1BQU0sSUFBSSxLQUFLLENBQUMseUJBQXlCLENBQUMsQ0FBQztpQkFDOUM7Z0JBRUQsR0FBRyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQztnQkFFakMsSUFBSSxNQUFNLEdBQVEsSUFBSSxDQUFDO2dCQUN2QixHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUssR0FBRyxHQUFHLEVBQUU7b0JBQ3BCLElBQUksQ0FBQyxNQUFNLEVBQUU7d0JBQ1QsTUFBTSxHQUFHOzRCQUNMLElBQUksRUFBRSxHQUFHLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQzs0QkFDdkIsT0FBTyxFQUFFLEdBQUcsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDOzRCQUM3QixPQUFPLEVBQUUsR0FBRyxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUM7NEJBQzdCLEtBQUssRUFBRSxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQzt5QkFDNUIsQ0FBQztxQkFDTDtvQkFDRCxPQUFPLE1BQU0sQ0FBQztnQkFDbEIsQ0FBQyxDQUFDO2dCQUNGLElBQUksRUFBRSxDQUFDO1lBQ1gsQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDO0tBQUE7SUFFWSxJQUFJOztRQUNqQixDQUFDO0tBQUE7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBBcHBsaWNhdGlvbkNvbXBvbmVudCBmcm9tIFwiLi4vQXBwbGljYXRpb25Db21wb25lbnRcIjtcbmltcG9ydCBzZXNzaW9uIGZyb20gXCJleHByZXNzLXNlc3Npb25cIjtcbmltcG9ydCBjb25maWcgZnJvbSBcImNvbmZpZ1wiO1xuaW1wb3J0IFJlZGlzQ29tcG9uZW50IGZyb20gXCIuL1JlZGlzQ29tcG9uZW50XCI7XG5pbXBvcnQgZmxhc2ggZnJvbSBcImNvbm5lY3QtZmxhc2hcIjtcbmltcG9ydCB7RXhwcmVzcywgUm91dGVyfSBmcm9tIFwiZXhwcmVzc1wiO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBTZXNzaW9uQ29tcG9uZW50IGV4dGVuZHMgQXBwbGljYXRpb25Db21wb25lbnQ8dm9pZD4ge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgc3RvcmVDb21wb25lbnQ6IFJlZGlzQ29tcG9uZW50O1xuXG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3Ioc3RvcmVDb21wb25lbnQ6IFJlZGlzQ29tcG9uZW50KSB7XG4gICAgICAgIHN1cGVyKCk7XG4gICAgICAgIHRoaXMuc3RvcmVDb21wb25lbnQgPSBzdG9yZUNvbXBvbmVudDtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc3RhcnQoYXBwOiBFeHByZXNzLCByb3V0ZXI6IFJvdXRlcik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICByb3V0ZXIudXNlKHNlc3Npb24oe1xuICAgICAgICAgICAgc2F2ZVVuaW5pdGlhbGl6ZWQ6IHRydWUsXG4gICAgICAgICAgICBzZWNyZXQ6IGNvbmZpZy5nZXQoJ3Nlc3Npb24uc2VjcmV0JyksXG4gICAgICAgICAgICBzdG9yZTogdGhpcy5zdG9yZUNvbXBvbmVudC5nZXRTdG9yZSgpLFxuICAgICAgICAgICAgcmVzYXZlOiB0cnVlLFxuICAgICAgICAgICAgY29va2llOiB7XG4gICAgICAgICAgICAgICAgaHR0cE9ubHk6IHRydWUsXG4gICAgICAgICAgICAgICAgc2VjdXJlOiBjb25maWcuZ2V0KCdzZXNzaW9uLmNvb2tpZS5zZWN1cmUnKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICByb2xsaW5nOiB0cnVlLFxuICAgICAgICB9KSk7XG5cbiAgICAgICAgcm91dGVyLnVzZShmbGFzaCgpKTtcblxuICAgICAgICByb3V0ZXIudXNlKChyZXEsIHJlcywgbmV4dCkgPT4ge1xuICAgICAgICAgICAgaWYgKCFyZXEuc2Vzc2lvbikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignU2Vzc2lvbiBpcyB1bmF2YWlsYWJsZS4nKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmVzLmxvY2Fscy5zZXNzaW9uID0gcmVxLnNlc3Npb247XG5cbiAgICAgICAgICAgIGxldCBfZmxhc2g6IGFueSA9IG51bGw7XG4gICAgICAgICAgICByZXMubG9jYWxzLmZsYXNoID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmICghX2ZsYXNoKSB7XG4gICAgICAgICAgICAgICAgICAgIF9mbGFzaCA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGluZm86IHJlcS5mbGFzaCgnaW5mbycpLFxuICAgICAgICAgICAgICAgICAgICAgICAgc3VjY2VzczogcmVxLmZsYXNoKCdzdWNjZXNzJyksXG4gICAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nOiByZXEuZmxhc2goJ3dhcm5pbmcnKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yOiByZXEuZmxhc2goJ2Vycm9yJyksXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiBfZmxhc2g7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgbmV4dCgpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc3RvcCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB9XG59Il19 \ No newline at end of file diff --git a/dist/components/WebSocketServerComponent.d.ts b/dist/components/WebSocketServerComponent.d.ts new file mode 100644 index 0000000..1393d47 --- /dev/null +++ b/dist/components/WebSocketServerComponent.d.ts @@ -0,0 +1,14 @@ +import ApplicationComponent from "../ApplicationComponent"; +import { Express, Router } from "express"; +import ExpressAppComponent from "./ExpressAppComponent"; +import Application from "../Application"; +import RedisComponent from "./RedisComponent"; +export default class WebSocketServerComponent extends ApplicationComponent { + private readonly application; + private readonly expressAppComponent; + private readonly storeComponent; + private wss?; + constructor(application: Application, expressAppComponent: ExpressAppComponent, storeComponent: RedisComponent); + start(app: Express, router: Router): Promise; + stop(): Promise; +} diff --git a/dist/components/WebSocketServerComponent.js b/dist/components/WebSocketServerComponent.js new file mode 100644 index 0000000..ccd0926 --- /dev/null +++ b/dist/components/WebSocketServerComponent.js @@ -0,0 +1,73 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import ApplicationComponent from "../ApplicationComponent"; +import { Server as WebSocketServer } from "ws"; +import Logger from "../Logger"; +import cookie from "cookie"; +import cookieParser from "cookie-parser"; +import config from "config"; +export default class WebSocketServerComponent extends ApplicationComponent { + constructor(application, expressAppComponent, storeComponent) { + super(); + this.expressAppComponent = expressAppComponent; + this.application = application; + this.storeComponent = storeComponent; + } + start(app, router) { + return __awaiter(this, void 0, void 0, function* () { + const listeners = this.application.getWebSocketListeners(); + this.wss = new WebSocketServer({ + server: this.expressAppComponent.getServer(), + }, () => { + Logger.info(`Websocket server started over webserver.`); + }).on('error', (err) => { + Logger.error(err, 'An error occurred in the websocket server.'); + }).on('connection', (socket, request) => { + const listener = request.url ? listeners[request.url] : null; + if (!listener) { + socket.close(1002, `Path not found ${request.url}`); + return; + } + else if (!request.headers.cookie) { + socket.close(1002, `Can't process request without cookies.`); + return; + } + Logger.debug(`Websocket on ${request.url}`); + const cookies = cookie.parse(request.headers.cookie); + const sid = cookieParser.signedCookie(cookies['connect.sid'], config.get('session.secret')); + if (!sid) { + socket.close(1002); + return; + } + const store = this.storeComponent.getStore(); + store.get(sid, (err, session) => { + if (err || !session) { + Logger.error(err, 'Error while initializing session in websocket.'); + socket.close(1011); + return; + } + session.id = sid; + store.createSession(request, session); + listener.handle(socket, request, session).catch(err => { + Logger.error(err, 'Error in websocket listener.'); + }); + }); + }); + }); + } + stop() { + return __awaiter(this, void 0, void 0, function* () { + if (this.wss) { + yield this.close('WebSocket server', this.wss, this.wss.close); + } + }); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV2ViU29ja2V0U2VydmVyQ29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Ii4vIiwic291cmNlcyI6WyJjb21wb25lbnRzL1dlYlNvY2tldFNlcnZlckNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFBQSxPQUFPLG9CQUFvQixNQUFNLHlCQUF5QixDQUFDO0FBRTNELE9BQWtCLEVBQUMsTUFBTSxJQUFJLGVBQWUsRUFBQyxNQUFNLElBQUksQ0FBQztBQUN4RCxPQUFPLE1BQU0sTUFBTSxXQUFXLENBQUM7QUFDL0IsT0FBTyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBQzVCLE9BQU8sWUFBWSxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFNNUIsTUFBTSxDQUFDLE9BQU8sT0FBTyx3QkFBeUIsU0FBUSxvQkFBMEI7SUFPNUUsWUFBWSxXQUF3QixFQUFFLG1CQUF3QyxFQUFFLGNBQThCO1FBQzFHLEtBQUssRUFBRSxDQUFDO1FBQ1IsSUFBSSxDQUFDLG1CQUFtQixHQUFHLG1CQUFtQixDQUFDO1FBQy9DLElBQUksQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO1FBQy9CLElBQUksQ0FBQyxjQUFjLEdBQUcsY0FBYyxDQUFDO0lBQ3pDLENBQUM7SUFFWSxLQUFLLENBQUMsR0FBWSxFQUFFLE1BQWM7O1lBQzNDLE1BQU0sU0FBUyxHQUF1QyxJQUFJLENBQUMsV0FBVyxDQUFDLHFCQUFxQixFQUFFLENBQUM7WUFDL0YsSUFBSSxDQUFDLEdBQUcsR0FBRyxJQUFJLGVBQWUsQ0FBQztnQkFDM0IsTUFBTSxFQUFFLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxTQUFTLEVBQUU7YUFDL0MsRUFBRSxHQUFHLEVBQUU7Z0JBQ0osTUFBTSxDQUFDLElBQUksQ0FBQywwQ0FBMEMsQ0FBQyxDQUFDO1lBQzVELENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRTtnQkFDbkIsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsNENBQTRDLENBQUMsQ0FBQztZQUNwRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsWUFBWSxFQUFFLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxFQUFFO2dCQUNwQyxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7Z0JBRTdELElBQUksQ0FBQyxRQUFRLEVBQUU7b0JBQ1gsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsa0JBQWtCLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO29CQUNwRCxPQUFPO2lCQUNWO3FCQUFNLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRTtvQkFDaEMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsd0NBQXdDLENBQUMsQ0FBQztvQkFDN0QsT0FBTztpQkFDVjtnQkFFRCxNQUFNLENBQUMsS0FBSyxDQUFDLGdCQUFnQixPQUFPLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQztnQkFFNUMsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO2dCQUNyRCxNQUFNLEdBQUcsR0FBRyxZQUFZLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsRUFBRSxNQUFNLENBQUMsR0FBRyxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQztnQkFFNUYsSUFBSSxDQUFDLEdBQUcsRUFBRTtvQkFDTixNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO29CQUNuQixPQUFPO2lCQUNWO2dCQUVELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQzdDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxFQUFFLE9BQU8sRUFBRSxFQUFFO29CQUM1QixJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRTt3QkFDakIsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsZ0RBQWdELENBQUMsQ0FBQzt3QkFDcEUsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQzt3QkFDbkIsT0FBTztxQkFDVjtvQkFFRCxPQUFPLENBQUMsRUFBRSxHQUFHLEdBQUcsQ0FBQztvQkFFakIsS0FBSyxDQUFDLGFBQWEsQ0FBVSxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUM7b0JBQy9DLFFBQVEsQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUU7d0JBQ2xELE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLDhCQUE4QixDQUFDLENBQUM7b0JBQ3RELENBQUMsQ0FBQyxDQUFDO2dCQUNQLENBQUMsQ0FBQyxDQUFDO1lBQ1AsQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDO0tBQUE7SUFFWSxJQUFJOztZQUNiLElBQUksSUFBSSxDQUFDLEdBQUcsRUFBRTtnQkFDVixNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsa0JBQWtCLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO2FBQ2xFO1FBQ0wsQ0FBQztLQUFBO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgQXBwbGljYXRpb25Db21wb25lbnQgZnJvbSBcIi4uL0FwcGxpY2F0aW9uQ29tcG9uZW50XCI7XG5pbXBvcnQge0V4cHJlc3MsIFJlcXVlc3QsIFJvdXRlcn0gZnJvbSBcImV4cHJlc3NcIjtcbmltcG9ydCBXZWJTb2NrZXQsIHtTZXJ2ZXIgYXMgV2ViU29ja2V0U2VydmVyfSBmcm9tIFwid3NcIjtcbmltcG9ydCBMb2dnZXIgZnJvbSBcIi4uL0xvZ2dlclwiO1xuaW1wb3J0IGNvb2tpZSBmcm9tIFwiY29va2llXCI7XG5pbXBvcnQgY29va2llUGFyc2VyIGZyb20gXCJjb29raWUtcGFyc2VyXCI7XG5pbXBvcnQgY29uZmlnIGZyb20gXCJjb25maWdcIjtcbmltcG9ydCBFeHByZXNzQXBwQ29tcG9uZW50IGZyb20gXCIuL0V4cHJlc3NBcHBDb21wb25lbnRcIjtcbmltcG9ydCBBcHBsaWNhdGlvbiBmcm9tIFwiLi4vQXBwbGljYXRpb25cIjtcbmltcG9ydCBSZWRpc0NvbXBvbmVudCBmcm9tIFwiLi9SZWRpc0NvbXBvbmVudFwiO1xuaW1wb3J0IFdlYlNvY2tldExpc3RlbmVyIGZyb20gXCIuLi9XZWJTb2NrZXRMaXN0ZW5lclwiO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBXZWJTb2NrZXRTZXJ2ZXJDb21wb25lbnQgZXh0ZW5kcyBBcHBsaWNhdGlvbkNvbXBvbmVudDx2b2lkPiB7XG4gICAgcHJpdmF0ZSByZWFkb25seSBhcHBsaWNhdGlvbjogQXBwbGljYXRpb247XG4gICAgcHJpdmF0ZSByZWFkb25seSBleHByZXNzQXBwQ29tcG9uZW50OiBFeHByZXNzQXBwQ29tcG9uZW50O1xuICAgIHByaXZhdGUgcmVhZG9ubHkgc3RvcmVDb21wb25lbnQ6IFJlZGlzQ29tcG9uZW50O1xuXG4gICAgcHJpdmF0ZSB3c3M/OiBXZWJTb2NrZXQuU2VydmVyO1xuXG4gICAgY29uc3RydWN0b3IoYXBwbGljYXRpb246IEFwcGxpY2F0aW9uLCBleHByZXNzQXBwQ29tcG9uZW50OiBFeHByZXNzQXBwQ29tcG9uZW50LCBzdG9yZUNvbXBvbmVudDogUmVkaXNDb21wb25lbnQpIHtcbiAgICAgICAgc3VwZXIoKTtcbiAgICAgICAgdGhpcy5leHByZXNzQXBwQ29tcG9uZW50ID0gZXhwcmVzc0FwcENvbXBvbmVudDtcbiAgICAgICAgdGhpcy5hcHBsaWNhdGlvbiA9IGFwcGxpY2F0aW9uO1xuICAgICAgICB0aGlzLnN0b3JlQ29tcG9uZW50ID0gc3RvcmVDb21wb25lbnQ7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHN0YXJ0KGFwcDogRXhwcmVzcywgcm91dGVyOiBSb3V0ZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgbGlzdGVuZXJzOiB7IFtwOiBzdHJpbmddOiBXZWJTb2NrZXRMaXN0ZW5lciB9ID0gdGhpcy5hcHBsaWNhdGlvbi5nZXRXZWJTb2NrZXRMaXN0ZW5lcnMoKTtcbiAgICAgICAgdGhpcy53c3MgPSBuZXcgV2ViU29ja2V0U2VydmVyKHtcbiAgICAgICAgICAgIHNlcnZlcjogdGhpcy5leHByZXNzQXBwQ29tcG9uZW50LmdldFNlcnZlcigpLFxuICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgICBMb2dnZXIuaW5mbyhgV2Vic29ja2V0IHNlcnZlciBzdGFydGVkIG92ZXIgd2Vic2VydmVyLmApO1xuICAgICAgICB9KS5vbignZXJyb3InLCAoZXJyKSA9PiB7XG4gICAgICAgICAgICBMb2dnZXIuZXJyb3IoZXJyLCAnQW4gZXJyb3Igb2NjdXJyZWQgaW4gdGhlIHdlYnNvY2tldCBzZXJ2ZXIuJyk7XG4gICAgICAgIH0pLm9uKCdjb25uZWN0aW9uJywgKHNvY2tldCwgcmVxdWVzdCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgbGlzdGVuZXIgPSByZXF1ZXN0LnVybCA/IGxpc3RlbmVyc1tyZXF1ZXN0LnVybF0gOiBudWxsO1xuXG4gICAgICAgICAgICBpZiAoIWxpc3RlbmVyKSB7XG4gICAgICAgICAgICAgICAgc29ja2V0LmNsb3NlKDEwMDIsIGBQYXRoIG5vdCBmb3VuZCAke3JlcXVlc3QudXJsfWApO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIXJlcXVlc3QuaGVhZGVycy5jb29raWUpIHtcbiAgICAgICAgICAgICAgICBzb2NrZXQuY2xvc2UoMTAwMiwgYENhbid0IHByb2Nlc3MgcmVxdWVzdCB3aXRob3V0IGNvb2tpZXMuYCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBMb2dnZXIuZGVidWcoYFdlYnNvY2tldCBvbiAke3JlcXVlc3QudXJsfWApO1xuXG4gICAgICAgICAgICBjb25zdCBjb29raWVzID0gY29va2llLnBhcnNlKHJlcXVlc3QuaGVhZGVycy5jb29raWUpO1xuICAgICAgICAgICAgY29uc3Qgc2lkID0gY29va2llUGFyc2VyLnNpZ25lZENvb2tpZShjb29raWVzWydjb25uZWN0LnNpZCddLCBjb25maWcuZ2V0KCdzZXNzaW9uLnNlY3JldCcpKTtcblxuICAgICAgICAgICAgaWYgKCFzaWQpIHtcbiAgICAgICAgICAgICAgICBzb2NrZXQuY2xvc2UoMTAwMik7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBzdG9yZSA9IHRoaXMuc3RvcmVDb21wb25lbnQuZ2V0U3RvcmUoKTtcbiAgICAgICAgICAgIHN0b3JlLmdldChzaWQsIChlcnIsIHNlc3Npb24pID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyIHx8ICFzZXNzaW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIExvZ2dlci5lcnJvcihlcnIsICdFcnJvciB3aGlsZSBpbml0aWFsaXppbmcgc2Vzc2lvbiBpbiB3ZWJzb2NrZXQuJyk7XG4gICAgICAgICAgICAgICAgICAgIHNvY2tldC5jbG9zZSgxMDExKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHNlc3Npb24uaWQgPSBzaWQ7XG5cbiAgICAgICAgICAgICAgICBzdG9yZS5jcmVhdGVTZXNzaW9uKDxSZXF1ZXN0PnJlcXVlc3QsIHNlc3Npb24pO1xuICAgICAgICAgICAgICAgIGxpc3RlbmVyLmhhbmRsZShzb2NrZXQsIHJlcXVlc3QsIHNlc3Npb24pLmNhdGNoKGVyciA9PiB7XG4gICAgICAgICAgICAgICAgICAgIExvZ2dlci5lcnJvcihlcnIsICdFcnJvciBpbiB3ZWJzb2NrZXQgbGlzdGVuZXIuJyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHN0b3AoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aGlzLndzcykge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5jbG9zZSgnV2ViU29ja2V0IHNlcnZlcicsIHRoaXMud3NzLCB0aGlzLndzcy5jbG9zZSk7XG4gICAgICAgIH1cbiAgICB9XG59Il19 \ No newline at end of file diff --git a/dist/db/Migration.d.ts b/dist/db/Migration.d.ts new file mode 100644 index 0000000..9a8bc39 --- /dev/null +++ b/dist/db/Migration.d.ts @@ -0,0 +1,7 @@ +export default abstract class Migration { + readonly version: number; + constructor(version: number); + shouldRun(currentVersion: number): Promise; + abstract install(): Promise; + abstract rollback(): Promise; +} diff --git a/dist/db/Migration.js b/dist/db/Migration.js new file mode 100644 index 0000000..a96fbf1 --- /dev/null +++ b/dist/db/Migration.js @@ -0,0 +1,20 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +export default class Migration { + constructor(version) { + this.version = version; + } + shouldRun(currentVersion) { + return __awaiter(this, void 0, void 0, function* () { + return this.version > currentVersion; + }); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWlncmF0aW9uLmpzIiwic291cmNlUm9vdCI6Ii4vIiwic291cmNlcyI6WyJkYi9NaWdyYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBQUEsTUFBTSxDQUFDLE9BQU8sT0FBZ0IsU0FBUztJQUduQyxZQUFZLE9BQWU7UUFDdkIsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7SUFDM0IsQ0FBQztJQUVLLFNBQVMsQ0FBQyxjQUFzQjs7WUFDbEMsT0FBTyxJQUFJLENBQUMsT0FBTyxHQUFHLGNBQWMsQ0FBQztRQUN6QyxDQUFDO0tBQUE7Q0FLSiIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBkZWZhdWx0IGFic3RyYWN0IGNsYXNzIE1pZ3JhdGlvbiB7XG4gICAgcHVibGljIHJlYWRvbmx5IHZlcnNpb246IG51bWJlcjtcblxuICAgIGNvbnN0cnVjdG9yKHZlcnNpb246IG51bWJlcikge1xuICAgICAgICB0aGlzLnZlcnNpb24gPSB2ZXJzaW9uO1xuICAgIH1cblxuICAgIGFzeW5jIHNob3VsZFJ1bihjdXJyZW50VmVyc2lvbjogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIHJldHVybiB0aGlzLnZlcnNpb24gPiBjdXJyZW50VmVyc2lvbjtcbiAgICB9XG5cbiAgICBhYnN0cmFjdCBhc3luYyBpbnN0YWxsKCk6IFByb21pc2U8dm9pZD47XG5cbiAgICBhYnN0cmFjdCBhc3luYyByb2xsYmFjaygpOiBQcm9taXNlPHZvaWQ+O1xufSJdfQ== \ No newline at end of file diff --git a/dist/db/Model.d.ts b/dist/db/Model.d.ts new file mode 100644 index 0000000..4f61055 --- /dev/null +++ b/dist/db/Model.d.ts @@ -0,0 +1,58 @@ +import Validator from "./Validator"; +import { Connection } from "mysql"; +import Query from "./Query"; +import { Request } from "express"; +export default abstract class Model { + static getById(id: number): Promise; + static paginate(request: Request, perPage?: number): Promise; + protected static select(...fields: string[]): Query; + protected static update(data: { + [key: string]: any; + }): Query; + protected static delete(): Query; + protected static models(query: Query): Promise; + static loadRelation(models: T[], relation: string, model: Function, localField: string): Promise; + private static getFactory; + protected readonly properties: ModelProperty[]; + private readonly relations; + id?: number; + [key: string]: any; + constructor(data: any); + protected abstract defineProperties(): void; + protected defineProperty(name: string, validator?: Validator | RegExp): void; + private updateWithData; + protected beforeSave(exists: boolean, connection: Connection): Promise; + protected afterSave(): Promise; + save(connection?: Connection, postHook?: (callback: () => Promise) => void): Promise; + private saveTransaction; + static get table(): string; + get table(): string; + exists(): Promise; + delete(): Promise; + validate(onlyFormat?: boolean, connection?: Connection): Promise; + private cache; + protected relation(name: string): T | null; +} +export interface ModelFactory { + (data: any): T; +} +declare class ModelProperty { + readonly name: string; + private readonly validator; + private val?; + constructor(name: string, validator: Validator); + validate(onlyFormat: boolean, connection?: Connection): Promise; + get value(): T | undefined; + set value(val: T | undefined); +} +export declare class ModelCache { + private static readonly caches; + static cache(instance: Model): void; + static forget(instance: Model): void; + static all(table: string): { + [key: number]: Model; + } | undefined; + static get(table: string, id: number): Model | undefined; +} +export declare const EMAIL_REGEX: RegExp; +export {}; diff --git a/dist/db/Model.js b/dist/db/Model.js new file mode 100644 index 0000000..cfa3221 --- /dev/null +++ b/dist/db/Model.js @@ -0,0 +1,291 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import MysqlConnectionManager, { query } from "./MysqlConnectionManager"; +import Validator from "./Validator"; +import Query from "./Query"; +import Pagination from "../Pagination"; +export default class Model { + constructor(data) { + this.properties = []; + this.relations = {}; + this.defineProperty('id', new Validator()); + this.defineProperties(); + this.updateWithData(data); + } + static getById(id) { + return __awaiter(this, void 0, void 0, function* () { + const cachedModel = ModelCache.get(this.table, id); + if ((cachedModel === null || cachedModel === void 0 ? void 0 : cachedModel.constructor) === this) { + return cachedModel; + } + const models = yield this.models(this.select().where('id', id).first()); + return models.length > 0 ? models[0] : null; + }); + } + static paginate(request, perPage = 20) { + return __awaiter(this, void 0, void 0, function* () { + let page = request.params.page ? parseInt(request.params.page) : 1; + let query = this.select().limit(perPage, (page - 1) * perPage).withTotalRowCount(); + if (request.params.sortBy) { + const dir = request.params.sortDirection; + query = query.sortBy(request.params.sortBy, dir === 'ASC' || dir === 'DESC' ? dir : undefined); + } + else { + query = query.sortBy('id'); + } + const models = yield this.models(query); + // @ts-ignore + models.pagination = new Pagination(models, page, perPage, models.totalCount); + return models; + }); + } + static select(...fields) { + return Query.select(this.table, ...fields); + } + static update(data) { + return Query.update(this.table, data); + } + static delete() { + return Query.delete(this.table); + } + static models(query) { + return __awaiter(this, void 0, void 0, function* () { + const results = yield query.execute(); + const models = []; + const factory = this.getFactory(); + for (const result of results.results) { + const cachedModel = ModelCache.get(this.table, result.id); + if (cachedModel && cachedModel.constructor === this) { + cachedModel.updateWithData(result); + models.push(cachedModel); + } + else { + models.push(factory(result)); + } + } + // @ts-ignore + models.totalCount = results.foundRows; + return models; + }); + } + static loadRelation(models, relation, model, localField) { + return __awaiter(this, void 0, void 0, function* () { + const loadMap = {}; + const ids = models.map(m => { + m.relations[relation] = null; + if (m[localField]) + loadMap[m[localField]] = v => m.relations[relation] = v; + return m[localField]; + }).filter(id => id); + for (const v of yield model.models(model.select().whereIn('id', ids))) { + loadMap[v.id](v); + } + }); + } + static getFactory(factory) { + if (factory === undefined) { + factory = this.FACTORY; + if (factory === undefined) + factory = data => new this(data); + } + return factory; + } + defineProperty(name, validator) { + if (validator === undefined) + validator = new Validator(); + if (validator instanceof RegExp) { + const regexp = validator; + validator = new Validator().regexp(regexp); + } + const prop = new ModelProperty(name, validator); + this.properties.push(prop); + Object.defineProperty(this, name, { + get: () => prop.value, + set: (value) => prop.value = value, + }); + } + updateWithData(data) { + this.id = data['id']; + for (const prop of this.properties) { + if (data[prop.name] !== undefined) { + this[prop.name] = data[prop.name]; + } + } + } + beforeSave(exists, connection) { + return __awaiter(this, void 0, void 0, function* () { + }); + } + afterSave() { + return __awaiter(this, void 0, void 0, function* () { + }); + } + save(connection, postHook) { + return __awaiter(this, void 0, void 0, function* () { + yield this.validate(false, connection); + const exists = yield this.exists(); + let needs_full_update = false; + if (connection) { + needs_full_update = yield this.saveTransaction(connection, exists, needs_full_update); + } + else { + needs_full_update = yield MysqlConnectionManager.wrapTransaction((connection) => __awaiter(this, void 0, void 0, function* () { return this.saveTransaction(connection, exists, needs_full_update); })); + } + const callback = () => __awaiter(this, void 0, void 0, function* () { + if (needs_full_update) { + this.updateWithData((yield this.constructor.select().where('id', this.id).first().execute()).results[0]); + } + if (!exists) { + this.cache(); + } + yield this.afterSave(); + }); + if (connection) { + postHook(callback); + } + else { + yield callback(); + } + }); + } + saveTransaction(connection, exists, needs_full_update) { + return __awaiter(this, void 0, void 0, function* () { + // Before save + yield this.beforeSave(exists, connection); + if (exists && this.hasOwnProperty('updated_at')) { + this.updated_at = new Date(); + } + const props = []; + const values = []; + if (exists) { + for (const prop of this.properties) { + if (prop.value !== undefined) { + props.push(prop.name + '=?'); + values.push(prop.value); + } + else { + needs_full_update = true; + } + } + values.push(this.id); + yield query(`UPDATE ${this.table} SET ${props.join(',')} WHERE id=?`, values, connection); + } + else { + const props_holders = []; + for (const prop of this.properties) { + if (prop.value !== undefined) { + props.push(prop.name); + props_holders.push('?'); + values.push(prop.value); + } + else { + needs_full_update = true; + } + } + const result = yield query(`INSERT INTO ${this.table} (${props.join(', ')}) VALUES(${props_holders.join(', ')})`, values, connection); + this.id = result.other.insertId; + } + return needs_full_update; + }); + } + static get table() { + return this.name + .replace(/(?:^|\.?)([A-Z])/g, (x, y) => '_' + y.toLowerCase()) + .replace(/^_/, '') + + 's'; + } + get table() { + // @ts-ignore + return this.constructor.table; + } + exists() { + return __awaiter(this, void 0, void 0, function* () { + if (!this.id) + return false; + const result = yield query(`SELECT 1 FROM ${this.table} WHERE id=? LIMIT 1`, [ + this.id, + ]); + return result.results.length > 0; + }); + } + delete() { + return __awaiter(this, void 0, void 0, function* () { + if (!(yield this.exists())) + throw new Error('This model instance doesn\'t exist in DB.'); + yield query(`DELETE FROM ${this.table} WHERE id=?`, [ + this.id, + ]); + ModelCache.forget(this); + this.id = undefined; + }); + } + validate(onlyFormat = false, connection) { + return __awaiter(this, void 0, void 0, function* () { + return yield Promise.all(this.properties.map(prop => prop.validate(onlyFormat, connection))); + }); + } + cache() { + ModelCache.cache(this); + } + relation(name) { + if (this.relations[name] === undefined) + throw new Error('Model not loaded'); + return this.relations[name]; + } +} +class ModelProperty { + constructor(name, validator) { + this.name = name; + this.validator = validator; + } + validate(onlyFormat, connection) { + return __awaiter(this, void 0, void 0, function* () { + return yield this.validator.execute(this.name, this.value, onlyFormat, connection); + }); + } + get value() { + return this.val; + } + set value(val) { + this.val = val; + } +} +export class ModelCache { + static cache(instance) { + if (instance.id === undefined) + throw new Error('Cannot cache an instance with an undefined id.'); + let tableCache = this.caches[instance.table]; + if (!tableCache) + tableCache = this.caches[instance.table] = {}; + if (!tableCache[instance.id]) + tableCache[instance.id] = instance; + } + static forget(instance) { + if (instance.id === undefined) + throw new Error('Cannot forget an instance with an undefined id.'); + let tableCache = this.caches[instance.table]; + if (!tableCache) + return; + if (tableCache[instance.id]) + delete tableCache[instance.id]; + } + static all(table) { + return this.caches[table]; + } + static get(table, id) { + const tableCache = this.all(table); + if (!tableCache) + return undefined; + return tableCache[id]; + } +} +ModelCache.caches = {}; +export const EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTW9kZWwuanMiLCJzb3VyY2VSb290IjoiLi8iLCJzb3VyY2VzIjpbImRiL01vZGVsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBLE9BQU8sc0JBQXNCLEVBQUUsRUFBQyxLQUFLLEVBQUMsTUFBTSwwQkFBMEIsQ0FBQztBQUN2RSxPQUFPLFNBQVMsTUFBTSxhQUFhLENBQUM7QUFFcEMsT0FBTyxLQUFLLE1BQU0sU0FBUyxDQUFDO0FBRTVCLE9BQU8sVUFBVSxNQUFNLGVBQWUsQ0FBQztBQUV2QyxNQUFNLENBQUMsT0FBTyxPQUFnQixLQUFLO0lBbUYvQixZQUFtQixJQUFTO1FBTlQsZUFBVSxHQUF5QixFQUFFLENBQUM7UUFDeEMsY0FBUyxHQUFvQyxFQUFFLENBQUM7UUFNN0QsSUFBSSxDQUFDLGNBQWMsQ0FBUyxJQUFJLEVBQUUsSUFBSSxTQUFTLEVBQUUsQ0FBQyxDQUFDO1FBQ25ELElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDOUIsQ0FBQztJQXRGTSxNQUFNLENBQU8sT0FBTyxDQUFrQixFQUFVOztZQUNuRCxNQUFNLFdBQVcsR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDbkQsSUFBSSxDQUFBLFdBQVcsYUFBWCxXQUFXLHVCQUFYLFdBQVcsQ0FBRSxXQUFXLE1BQUssSUFBSSxFQUFFO2dCQUNuQyxPQUFVLFdBQVcsQ0FBQzthQUN6QjtZQUVELE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQzNFLE9BQU8sTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENB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QUMsR0FBRyxDQUFDLEtBQWE7UUFHM0IsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzlCLENBQUM7SUFFTSxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQWEsRUFBRSxFQUFVO1FBQ3ZDLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDbkMsSUFBSSxDQUFDLFVBQVU7WUFBRSxPQUFPLFNBQVMsQ0FBQztRQUNsQyxPQUFPLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMxQixDQUFDOztBQWxDdUIsaUJBQU0sR0FJMUIsRUFBRSxDQUFDO0FBaUNYLE1BQU0sQ0FBQyxNQUFNLFdBQVcsR0FBRyx3SUFBd0ksQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBNeXNxbENvbm5lY3Rpb25NYW5hZ2VyLCB7cXVlcnl9IGZyb20gXCIuL015c3FsQ29ubmVjdGlvbk1hbmFnZXJcIjtcbmltcG9ydCBWYWxpZGF0b3IgZnJvbSBcIi4vVmFsaWRhdG9yXCI7XG5pbXBvcnQge0Nvbm5lY3Rpb259IGZyb20gXCJteXNxbFwiO1xuaW1wb3J0IFF1ZXJ5IGZyb20gXCIuL1F1ZXJ5XCI7XG5pbXBvcnQge1JlcXVlc3R9IGZyb20gXCJleHByZXNzXCI7XG5pbXBvcnQgUGFnaW5hdGlvbiBmcm9tIFwiLi4vUGFnaW5hdGlvblwiO1xuXG5leHBvcnQgZGVmYXVsdCBhYnN0cmFjdCBjbGFzcyBNb2RlbCB7XG4gICAgcHVibGljIHN0YXRpYyBhc3luYyBnZXRCeUlkPFQgZXh0ZW5kcyBNb2RlbD4oaWQ6IG51bWJlcik6IFByb21pc2U8VCB8IG51bGw+IHtcbiAgICAgICAgY29uc3QgY2FjaGVkTW9kZWwgPSBNb2RlbENhY2hlLmdldCh0aGlzLnRhYmxlLCBpZCk7XG4gICAgICAgIGlmIChjYWNoZWRNb2RlbD8uY29uc3RydWN0b3IgPT09IHRoaXMpIHtcbiAgICAgICAgICAgIHJldHVybiA8VD5jYWNoZWRNb2RlbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IG1vZGVscyA9IGF3YWl0IHRoaXMubW9kZWxzPFQ+KHRoaXMuc2VsZWN0KCkud2hlcmUoJ2lkJywgaWQpLmZpcnN0KCkpO1xuICAgICAgICByZXR1cm4gbW9kZWxzLmxlbmd0aCA+IDAgPyBtb2RlbHNbMF0gOiBudWxsO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgYXN5bmMgcGFnaW5hdGU8VCBleHRlbmRzIE1vZGVsPihyZXF1ZXN0OiBSZXF1ZXN0LCBwZXJQYWdlOiBudW1iZXIgPSAyMCk6IFByb21pc2U8VFtdPiB7XG4gICAgICAgIGxldCBwYWdlID0gcmVxdWVzdC5wYXJhbXMucGFnZSA/IHBhcnNlSW50KHJlcXVlc3QucGFyYW1zLnBhZ2UpIDogMTtcbiAgICAgICAgbGV0IHF1ZXJ5OiBRdWVyeSA9IHRoaXMuc2VsZWN0KCkubGltaXQocGVyUGFnZSwgKHBhZ2UgLSAxKSAqIHBlclBhZ2UpLndpdGhUb3RhbFJvd0NvdW50KCk7XG4gICAgICAgIGlmIChyZXF1ZXN0LnBhcmFtcy5zb3J0QnkpIHtcbiAgICAgICAgICAgIGNvbnN0IGRpciA9IHJlcXVlc3QucGFyYW1zLnNvcnREaXJlY3Rpb247XG4gICAgICAgICAgICBxdWVyeSA9IHF1ZXJ5LnNvcnRCeShyZXF1ZXN0LnBhcmFtcy5zb3J0QnksIGRpciA9PT0gJ0FTQycgfHwgZGlyID09PSAnREVTQycgPyBkaXIgOiB1bmRlZmluZWQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcXVlcnkgPSBxdWVyeS5zb3J0QnkoJ2lkJyk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgbW9kZWxzID0gYXdhaXQgdGhpcy5tb2RlbHM8VD4ocXVlcnkpO1xuICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgIG1vZGVscy5wYWdpbmF0aW9uID0gbmV3IFBhZ2luYXRpb24obW9kZWxzLCBwYWdlLCBwZXJQYWdlLCBtb2RlbHMudG90YWxDb3VudCk7XG4gICAgICAgIHJldHVybiBtb2RlbHM7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHN0YXRpYyBzZWxlY3QoLi4uZmllbGRzOiBzdHJpbmdbXSk6IFF1ZXJ5IHtcbiAgICAgICAgcmV0dXJuIFF1ZXJ5LnNlbGVjdCh0aGlzLnRhYmxlLCAuLi5maWVsZHMpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBzdGF0aWMgdXBkYXRlKGRhdGE6IHsgW2tleTogc3RyaW5nXTogYW55IH0pOiBRdWVyeSB7XG4gICAgICAgIHJldHVybiBRdWVyeS51cGRhdGUodGhpcy50YWJsZSwgZGF0YSk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHN0YXRpYyBkZWxldGUoKTogUXVlcnkge1xuICAgICAgICByZXR1cm4gUXVlcnkuZGVsZXRlKHRoaXMudGFibGUpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBzdGF0aWMgYXN5bmMgbW9kZWxzPFQgZXh0ZW5kcyBNb2RlbD4ocXVlcnk6IFF1ZXJ5KTogUHJvbWlzZTxUW10+IHtcbiAgICAgICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IHF1ZXJ5LmV4ZWN1dGUoKTtcbiAgICAgICAgY29uc3QgbW9kZWxzOiBUW10gPSBbXTtcbiAgICAgICAgY29uc3QgZmFjdG9yeSA9IHRoaXMuZ2V0RmFjdG9yeTxUPigpO1xuICAgICAgICBmb3IgKGNvbnN0IHJlc3VsdCBvZiByZXN1bHRzLnJlc3VsdHMpIHtcbiAgICAgICAgICAgIGNvbnN0IGNhY2hlZE1vZGVsID0gTW9kZWxDYWNoZS5nZXQodGhpcy50YWJsZSwgcmVzdWx0LmlkKTtcbiAgICAgICAgICAgIGlmIChjYWNoZWRNb2RlbCAmJiBjYWNoZWRNb2RlbC5jb25zdHJ1Y3RvciA9PT0gdGhpcykge1xuICAgICAgICAgICAgICAgIGNhY2hlZE1vZGVsLnVwZGF0ZVdpdGhEYXRhKHJlc3VsdCk7XG4gICAgICAgICAgICAgICAgbW9kZWxzLnB1c2goPFQ+Y2FjaGVkTW9kZWwpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBtb2RlbHMucHVzaChmYWN0b3J5KHJlc3VsdCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgICAgbW9kZWxzLnRvdGFsQ291bnQgPSByZXN1bHRzLmZvdW5kUm93cztcbiAgICAgICAgcmV0dXJuIG1vZGVscztcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGFzeW5jIGxvYWRSZWxhdGlvbjxUIGV4dGVuZHMgTW9kZWw+KG1vZGVsczogVFtdLCByZWxhdGlvbjogc3RyaW5nLCBtb2RlbDogRnVuY3Rpb24sIGxvY2FsRmllbGQ6IHN0cmluZykge1xuICAgICAgICBjb25zdCBsb2FkTWFwOiB7IFtwOiBudW1iZXJdOiAobW9kZWw6IFQpID0+IHZvaWQgfSA9IHt9O1xuICAgICAgICBjb25zdCBpZHMgPSBtb2RlbHMubWFwKG0gPT4ge1xuICAgICAgICAgICAgbS5yZWxhdGlvbnNbcmVsYXRpb25dID0gbnVsbDtcbiAgICAgICAgICAgIGlmIChtW2xvY2FsRmllbGRdKSBsb2FkTWFwW21bbG9jYWxGaWVsZF1dID0gdiA9PiBtLnJlbGF0aW9uc1tyZWxhdGlvbl0gPSB2O1xuICAgICAgICAgICAgcmV0dXJuIG1bbG9jYWxGaWVsZF07XG4gICAgICAgIH0pLmZpbHRlcihpZCA9PiBpZCk7XG4gICAgICAgIGZvciAoY29uc3QgdiBvZiBhd2FpdCAoPGFueT5tb2RlbCkubW9kZWxzKCg8YW55Pm1vZGVsKS5zZWxlY3QoKS53aGVyZUluKCdpZCcsIGlkcykpKSB7XG4gICAgICAgICAgICBsb2FkTWFwW3YuaWQhXSh2KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgc3RhdGljIGdldEZhY3Rvcnk8VCBleHRlbmRzIE1vZGVsPihmYWN0b3J5PzogTW9kZWxGYWN0b3J5PFQ+KTogTW9kZWxGYWN0b3J5PFQ+IHtcbiAgICAgICAgaWYgKGZhY3RvcnkgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgZmFjdG9yeSA9ICg8YW55PnRoaXMpLkZBQ1RPUlk7XG4gICAgICAgICAgICBpZiAoZmFjdG9yeSA9PT0gdW5kZWZpbmVkKSBmYWN0b3J5ID0gZGF0YSA9PiBuZXcgKDxhbnk+dGhpcykoZGF0YSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhY3Rvcnk7XG4gICAgfVxuXG5cbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgcHJvcGVydGllczogTW9kZWxQcm9wZXJ0eTxhbnk+W10gPSBbXTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHJlbGF0aW9uczogeyBbcDogc3RyaW5nXTogKE1vZGVsIHwgbnVsbCkgfSA9IHt9O1xuICAgIHB1YmxpYyBpZD86IG51bWJlcjtcblxuICAgIFtrZXk6IHN0cmluZ106IGFueTtcblxuICAgIHB1YmxpYyBjb25zdHJ1Y3RvcihkYXRhOiBhbnkpIHtcbiAgICAgICAgdGhpcy5kZWZpbmVQcm9wZXJ0eTxudW1iZXI+KCdpZCcsIG5ldyBWYWxpZGF0b3IoKSk7XG4gICAgICAgIHRoaXMuZGVmaW5lUHJvcGVydGllcygpO1xuICAgICAgICB0aGlzLnVwZGF0ZVdpdGhEYXRhKGRhdGEpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBhYnN0cmFjdCBkZWZpbmVQcm9wZXJ0aWVzKCk6IHZvaWQ7XG5cbiAgICBwcm90ZWN0ZWQgZGVmaW5lUHJvcGVydHk8VD4obmFtZTogc3RyaW5nLCB2YWxpZGF0b3I/OiBWYWxpZGF0b3I8VD4gfCBSZWdFeHApIHtcbiAgICAgICAgaWYgKHZhbGlkYXRvciA9PT0gdW5kZWZpbmVkKSB2YWxpZGF0b3IgPSBuZXcgVmFsaWRhdG9yKCk7XG4gICAgICAgIGlmICh2YWxpZGF0b3IgaW5zdGFuY2VvZiBSZWdFeHApIHtcbiAgICAgICAgICAgIGNvbnN0IHJlZ2V4cCA9IHZhbGlkYXRvcjtcbiAgICAgICAgICAgIHZhbGlkYXRvciA9IG5ldyBWYWxpZGF0b3IoKS5yZWdleHAocmVnZXhwKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHByb3AgPSBuZXcgTW9kZWxQcm9wZXJ0eTxUPihuYW1lLCB2YWxpZGF0b3IpO1xuICAgICAgICB0aGlzLnByb3BlcnRpZXMucHVzaChwcm9wKTtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsIG5hbWUsIHtcbiAgICAgICAgICAgIGdldDogKCkgPT4gcHJvcC52YWx1ZSxcbiAgICAgICAgICAgIHNldDogKHZhbHVlOiBUKSA9PiBwcm9wLnZhbHVlID0gdmFsdWUsXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgdXBkYXRlV2l0aERhdGEoZGF0YTogYW55KSB7XG4gICAgICAgIHRoaXMuaWQgPSBkYXRhWydpZCddO1xuXG4gICAgICAgIGZvciAoY29uc3QgcHJvcCBvZiB0aGlzLnByb3BlcnRpZXMpIHtcbiAgICAgICAgICAgIGlmIChkYXRhW3Byb3AubmFtZV0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHRoaXNbcHJvcC5uYW1lXSA9IGRhdGFbcHJvcC5uYW1lXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByb3RlY3RlZCBhc3luYyBiZWZvcmVTYXZlKGV4aXN0czogYm9vbGVhbiwgY29ubmVjdGlvbjogQ29ubmVjdGlvbik6IFByb21pc2U8dm9pZD4ge1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBhc3luYyBhZnRlclNhdmUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHNhdmUoY29ubmVjdGlvbj86IENvbm5lY3Rpb24sIHBvc3RIb29rPzogKGNhbGxiYWNrOiAoKSA9PiBQcm9taXNlPHZvaWQ+KSA9PiB2b2lkKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMudmFsaWRhdGUoZmFsc2UsIGNvbm5lY3Rpb24pO1xuXG4gICAgICAgIGNvbnN0IGV4aXN0cyA9IGF3YWl0IHRoaXMuZXhpc3RzKCk7XG4gICAgICAgIGxldCBuZWVkc19mdWxsX3VwZGF0ZSA9IGZhbHNlO1xuXG4gICAgICAgIGlmIChjb25uZWN0aW9uKSB7XG4gICAgICAgICAgICBuZWVkc19mdWxsX3VwZGF0ZSA9IGF3YWl0IHRoaXMuc2F2ZVRyYW5zYWN0aW9uKGNvbm5lY3Rpb24sIGV4aXN0cywgbmVlZHNfZnVsbF91cGRhdGUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbmVlZHNfZnVsbF91cGRhdGUgPSBhd2FpdCBNeXNxbENvbm5lY3Rpb25NYW5hZ2VyLndyYXBUcmFuc2FjdGlvbihhc3luYyBjb25uZWN0aW9uID0+IHRoaXMuc2F2ZVRyYW5zYWN0aW9uKGNvbm5lY3Rpb24sIGV4aXN0cywgbmVlZHNfZnVsbF91cGRhdGUpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNhbGxiYWNrID0gYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgaWYgKG5lZWRzX2Z1bGxfdXBkYXRlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy51cGRhdGVXaXRoRGF0YSgoYXdhaXQgKDxNb2RlbD48dW5rbm93bj50aGlzLmNvbnN0cnVjdG9yKS5zZWxlY3QoKS53aGVyZSgnaWQnLCB0aGlzLmlkISkuZmlyc3QoKS5leGVjdXRlKCkpLnJlc3VsdHNbMF0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIWV4aXN0cykge1xuICAgICAgICAgICAgICAgIHRoaXMuY2FjaGUoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgYXdhaXQgdGhpcy5hZnRlclNhdmUoKTtcbiAgICAgICAgfTtcblxuICAgICAgICBpZiAoY29ubmVjdGlvbikge1xuICAgICAgICAgICAgcG9zdEhvb2shKGNhbGxiYWNrKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGF3YWl0IGNhbGxiYWNrKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHNhdmVUcmFuc2FjdGlvbihjb25uZWN0aW9uOiBDb25uZWN0aW9uLCBleGlzdHM6IGJvb2xlYW4sIG5lZWRzX2Z1bGxfdXBkYXRlOiBib29sZWFuKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIC8vIEJlZm9yZSBzYXZlXG4gICAgICAgIGF3YWl0IHRoaXMuYmVmb3JlU2F2ZShleGlzdHMsIGNvbm5lY3Rpb24pO1xuICAgICAgICBpZiAoZXhpc3RzICYmIHRoaXMuaGFzT3duUHJvcGVydHkoJ3VwZGF0ZWRfYXQnKSkge1xuICAgICAgICAgICAgdGhpcy51cGRhdGVkX2F0ID0gbmV3IERhdGUoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHByb3BzID0gW107XG4gICAgICAgIGNvbnN0IHZhbHVlcyA9IFtdO1xuXG4gICAgICAgIGlmIChleGlzdHMpIHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgcHJvcCBvZiB0aGlzLnByb3BlcnRpZXMpIHtcbiAgICAgICAgICAgICAgICBpZiAocHJvcC52YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHByb3BzLnB1c2gocHJvcC5uYW1lICsgJz0/Jyk7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlcy5wdXNoKHByb3AudmFsdWUpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIG5lZWRzX2Z1bGxfdXBkYXRlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YWx1ZXMucHVzaCh0aGlzLmlkKTtcbiAgICAgICAgICAgIGF3YWl0IHF1ZXJ5KGBVUERBVEUgJHt0aGlzLnRhYmxlfSBTRVQgJHtwcm9wcy5qb2luKCcsJyl9IFdIRVJFIGlkPT9gLCB2YWx1ZXMsIGNvbm5lY3Rpb24pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3QgcHJvcHNfaG9sZGVycyA9IFtdO1xuICAgICAgICAgICAgZm9yIChjb25zdCBwcm9wIG9mIHRoaXMucHJvcGVydGllcykge1xuICAgICAgICAgICAgICAgIGlmIChwcm9wLnZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgcHJvcHMucHVzaChwcm9wLm5hbWUpO1xuICAgICAgICAgICAgICAgICAgICBwcm9wc19ob2xkZXJzLnB1c2goJz8nKTtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWVzLnB1c2gocHJvcC52YWx1ZSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgbmVlZHNfZnVsbF91cGRhdGUgPSB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHF1ZXJ5KGBJTlNFUlQgSU5UTyAke3RoaXMudGFibGV9ICgke3Byb3BzLmpvaW4oJywgJyl9KSBWQUxVRVMoJHtwcm9wc19ob2xkZXJzLmpvaW4oJywgJyl9KWAsIHZhbHVlcywgY29ubmVjdGlvbik7XG5cbiAgICAgICAgICAgIHRoaXMuaWQgPSByZXN1bHQub3RoZXIuaW5zZXJ0SWQ7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbmVlZHNfZnVsbF91cGRhdGU7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBnZXQgdGFibGUoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubmFtZVxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC8oPzpefFxcLj8pKFtBLVpdKS9nLCAoeCwgeSkgPT4gJ18nICsgeS50b0xvd2VyQ2FzZSgpKVxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9eXy8sICcnKVxuICAgICAgICAgICAgKyAncyc7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCB0YWJsZSgpOiBzdHJpbmcge1xuICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgIHJldHVybiB0aGlzLmNvbnN0cnVjdG9yLnRhYmxlO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBleGlzdHMoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIGlmICghdGhpcy5pZCkgcmV0dXJuIGZhbHNlO1xuXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHF1ZXJ5KGBTRUxFQ1QgMSBGUk9NICR7dGhpcy50YWJsZX0gV0hFUkUgaWQ9PyBMSU1JVCAxYCwgW1xuICAgICAgICAgICAgdGhpcy5pZCxcbiAgICAgICAgXSk7XG4gICAgICAgIHJldHVybiByZXN1bHQucmVzdWx0cy5sZW5ndGggPiAwO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBkZWxldGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICghKGF3YWl0IHRoaXMuZXhpc3RzKCkpKSB0aHJvdyBuZXcgRXJyb3IoJ1RoaXMgbW9kZWwgaW5zdGFuY2UgZG9lc25cXCd0IGV4aXN0IGluIERCLicpO1xuXG4gICAgICAgIGF3YWl0IHF1ZXJ5KGBERUxFVEUgRlJPTSAke3RoaXMudGFibGV9IFdIRVJFIGlkPT9gLCBbXG4gICAgICAgICAgICB0aGlzLmlkLFxuICAgICAgICBdKTtcbiAgICAgICAgTW9kZWxDYWNoZS5mb3JnZXQodGhpcyk7XG4gICAgICAgIHRoaXMuaWQgPSB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHZhbGlkYXRlKG9ubHlGb3JtYXQ6IGJvb2xlYW4gPSBmYWxzZSwgY29ubmVjdGlvbj86IENvbm5lY3Rpb24pOiBQcm9taXNlPHZvaWRbXT4ge1xuICAgICAgICByZXR1cm4gYXdhaXQgUHJvbWlzZS5hbGwodGhpcy5wcm9wZXJ0aWVzLm1hcChwcm9wID0+IHByb3AudmFsaWRhdGUob25seUZvcm1hdCwgY29ubmVjdGlvbikpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGNhY2hlKCkge1xuICAgICAgICBNb2RlbENhY2hlLmNhY2hlKHRoaXMpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCByZWxhdGlvbjxUIGV4dGVuZHMgTW9kZWw+KG5hbWU6IHN0cmluZyk6IFQgfCBudWxsIHtcbiAgICAgICAgaWYgKHRoaXMucmVsYXRpb25zW25hbWVdID09PSB1bmRlZmluZWQpIHRocm93IG5ldyBFcnJvcignTW9kZWwgbm90IGxvYWRlZCcpO1xuICAgICAgICByZXR1cm4gPFQgfCBudWxsPnRoaXMucmVsYXRpb25zW25hbWVdO1xuICAgIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBNb2RlbEZhY3Rvcnk8VCBleHRlbmRzIE1vZGVsPiB7XG4gICAgKGRhdGE6IGFueSk6IFQ7XG59XG5cbmNsYXNzIE1vZGVsUHJvcGVydHk8VD4ge1xuICAgIHB1YmxpYyByZWFkb25seSBuYW1lOiBzdHJpbmc7XG4gICAgcHJpdmF0ZSByZWFkb25seSB2YWxpZGF0b3I6IFZhbGlkYXRvcjxUPjtcbiAgICBwcml2YXRlIHZhbD86IFQ7XG5cbiAgICBjb25zdHJ1Y3RvcihuYW1lOiBzdHJpbmcsIHZhbGlkYXRvcjogVmFsaWRhdG9yPFQ+KSB7XG4gICAgICAgIHRoaXMubmFtZSA9IG5hbWU7XG4gICAgICAgIHRoaXMudmFsaWRhdG9yID0gdmFsaWRhdG9yO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyB2YWxpZGF0ZShvbmx5Rm9ybWF0OiBib29sZWFuLCBjb25uZWN0aW9uPzogQ29ubmVjdGlvbik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy52YWxpZGF0b3IuZXhlY3V0ZSh0aGlzLm5hbWUsIHRoaXMudmFsdWUsIG9ubHlGb3JtYXQsIGNvbm5lY3Rpb24pO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgdmFsdWUoKTogVCB8IHVuZGVmaW5lZCB7XG4gICAgICAgIHJldHVybiB0aGlzLnZhbDtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2V0IHZhbHVlKHZhbDogVCB8IHVuZGVmaW5lZCkge1xuICAgICAgICB0aGlzLnZhbCA9IHZhbDtcbiAgICB9XG59XG5cbmV4cG9ydCBjbGFzcyBNb2RlbENhY2hlIHtcbiAgICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBjYWNoZXM6IHtcbiAgICAgICAgW2tleTogc3RyaW5nXToge1xuICAgICAgICAgICAgW2tleTogbnVtYmVyXTogTW9kZWxcbiAgICAgICAgfVxuICAgIH0gPSB7fTtcblxuICAgIHB1YmxpYyBzdGF0aWMgY2FjaGUoaW5zdGFuY2U6IE1vZGVsKSB7XG4gICAgICAgIGlmIChpbnN0YW5jZS5pZCA9PT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBjYWNoZSBhbiBpbnN0YW5jZSB3aXRoIGFuIHVuZGVmaW5lZCBpZC4nKTtcblxuICAgICAgICBsZXQgdGFibGVDYWNoZSA9IHRoaXMuY2FjaGVzW2luc3RhbmNlLnRhYmxlXTtcbiAgICAgICAgaWYgKCF0YWJsZUNhY2hlKSB0YWJsZUNhY2hlID0gdGhpcy5jYWNoZXNbaW5zdGFuY2UudGFibGVdID0ge307XG5cbiAgICAgICAgaWYgKCF0YWJsZUNhY2hlW2luc3RhbmNlLmlkXSkgdGFibGVDYWNoZVtpbnN0YW5jZS5pZF0gPSBpbnN0YW5jZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGZvcmdldChpbnN0YW5jZTogTW9kZWwpIHtcbiAgICAgICAgaWYgKGluc3RhbmNlLmlkID09PSB1bmRlZmluZWQpIHRocm93IG5ldyBFcnJvcignQ2Fubm90IGZvcmdldCBhbiBpbnN0YW5jZSB3aXRoIGFuIHVuZGVmaW5lZCBpZC4nKTtcblxuICAgICAgICBsZXQgdGFibGVDYWNoZSA9IHRoaXMuY2FjaGVzW2luc3RhbmNlLnRhYmxlXTtcbiAgICAgICAgaWYgKCF0YWJsZUNhY2hlKSByZXR1cm47XG5cbiAgICAgICAgaWYgKHRhYmxlQ2FjaGVbaW5zdGFuY2UuaWRdKSBkZWxldGUgdGFibGVDYWNoZVtpbnN0YW5jZS5pZF07XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBhbGwodGFibGU6IHN0cmluZyk6IHtcbiAgICAgICAgW2tleTogbnVtYmVyXTogTW9kZWxcbiAgICB9IHwgdW5kZWZpbmVkIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2FjaGVzW3RhYmxlXTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGdldCh0YWJsZTogc3RyaW5nLCBpZDogbnVtYmVyKTogTW9kZWwgfCB1bmRlZmluZWQge1xuICAgICAgICBjb25zdCB0YWJsZUNhY2hlID0gdGhpcy5hbGwodGFibGUpO1xuICAgICAgICBpZiAoIXRhYmxlQ2FjaGUpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIHJldHVybiB0YWJsZUNhY2hlW2lkXTtcbiAgICB9XG59XG5cbmV4cG9ydCBjb25zdCBFTUFJTF9SRUdFWCA9IC9eW2EtekEtWjAtOS4hIyQlJicqK1xcXFwvPT9eX2B7fH1+LV0rQFthLXpBLVowLTldKD86W2EtekEtWjAtOS1dezAsNjF9W2EtekEtWjAtOV0pPyg/OlxcLlthLXpBLVowLTldKD86W2EtekEtWjAtOS1dezAsNjF9W2EtekEtWjAtOV0pPykrJC87Il19 \ No newline at end of file diff --git a/dist/db/MysqlConnectionManager.d.ts b/dist/db/MysqlConnectionManager.d.ts new file mode 100644 index 0000000..bc6eef0 --- /dev/null +++ b/dist/db/MysqlConnectionManager.d.ts @@ -0,0 +1,23 @@ +import { Connection, FieldInfo, Pool } from 'mysql'; +import Migration from "./Migration"; +export interface QueryResult { + readonly results: any[]; + readonly fields: FieldInfo[]; + readonly other?: any; + foundRows?: number; +} +export declare function query(queryString: string, values?: any, connection?: Connection): Promise; +export default class MysqlConnectionManager { + private static currentPool?; + private static databaseReady; + private static readonly migrations; + static registerMigration(migration: (version: number) => Migration): void; + static prepare(): Promise; + static get pool(): Pool; + private static createPool; + static endPool(): Promise; + static query(queryString: string, values?: any, connection?: Connection): Promise; + static wrapTransaction(transaction: (connection: Connection) => Promise): Promise; + private static rejectAndRollback; + private static handleMigrations; +} diff --git a/dist/db/MysqlConnectionManager.js b/dist/db/MysqlConnectionManager.js new file mode 100644 index 0000000..3353b4b --- /dev/null +++ b/dist/db/MysqlConnectionManager.js @@ -0,0 +1,168 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import mysql from 'mysql'; +import config from 'config'; +import Logger from "../Logger"; +export function query(queryString, values, connection) { + return __awaiter(this, void 0, void 0, function* () { + return yield MysqlConnectionManager.query(queryString, values, connection); + }); +} +export default class MysqlConnectionManager { + static registerMigration(migration) { + this.migrations.push(migration(this.migrations.length + 1)); + } + static prepare() { + return __awaiter(this, void 0, void 0, function* () { + if (config.get('mysql.create_database_automatically') === true) { + const dbName = config.get('mysql.database'); + Logger.info(`Creating database ${dbName}...`); + const connection = mysql.createConnection({ + host: config.get('mysql.host'), + user: config.get('mysql.user'), + password: config.get('mysql.password'), + }); + yield new Promise((resolve, reject) => { + connection.query(`CREATE DATABASE IF NOT EXISTS ${dbName}`, (error) => { + if (error !== null) { + reject(error); + } + else { + resolve(); + } + }); + }); + connection.end(); + Logger.info(`Database ${dbName} created!`); + } + this.databaseReady = true; + yield this.handleMigrations(); + }); + } + static get pool() { + if (this.currentPool === undefined) { + this.currentPool = this.createPool(); + } + return this.currentPool; + } + static createPool() { + return mysql.createPool({ + connectionLimit: config.get('mysql.connectionLimit'), + host: config.get('mysql.host'), + user: config.get('mysql.user'), + password: config.get('mysql.password'), + database: config.get('mysql.database'), + }); + } + static endPool() { + return __awaiter(this, void 0, void 0, function* () { + return new Promise(resolve => { + if (this.currentPool !== undefined) { + this.currentPool.end(() => { + Logger.info('Mysql connection pool ended.'); + resolve(); + }); + this.currentPool = undefined; + } + else { + resolve(); + } + }); + }); + } + static query(queryString, values, connection) { + return __awaiter(this, void 0, void 0, function* () { + return yield new Promise((resolve, reject) => { + Logger.dev('Mysql query:', queryString, '; values:', values); + (connection ? connection : this.pool).query(queryString, values, (error, results, fields) => { + if (error !== null) { + reject(error); + return; + } + resolve({ + results: Array.isArray(results) ? results : [], + fields: fields !== undefined ? fields : [], + other: Array.isArray(results) ? null : results + }); + }); + }); + }); + } + static wrapTransaction(transaction) { + return __awaiter(this, void 0, void 0, function* () { + return yield new Promise((resolve, reject) => { + this.pool.getConnection((err, connection) => { + if (err) { + reject(err); + return; + } + connection.beginTransaction((err) => { + if (err) { + reject(err); + this.pool.releaseConnection(connection); + return; + } + transaction(connection).then(val => { + connection.commit((err) => { + if (err) { + this.rejectAndRollback(connection, err, reject); + this.pool.releaseConnection(connection); + return; + } + this.pool.releaseConnection(connection); + resolve(val); + }); + }).catch(err => { + this.rejectAndRollback(connection, err, reject); + this.pool.releaseConnection(connection); + }); + }); + }); + }); + }); + } + static rejectAndRollback(connection, err, reject) { + connection.rollback((rollbackErr) => { + if (rollbackErr) { + reject(err + '\n' + rollbackErr); + } + else { + reject(err); + } + }); + } + static handleMigrations() { + return __awaiter(this, void 0, void 0, function* () { + let currentVersion = 0; + try { + const result = yield query('SELECT id FROM migrations ORDER BY id DESC LIMIT 1'); + currentVersion = result.results[0].id; + } + catch (e) { + if (e.code === 'ECONNREFUSED' || e.code !== 'ER_NO_SUCH_TABLE') { + throw new Error('Cannot run migrations: ' + e.code); + } + } + for (const migration of this.migrations) { + if (yield migration.shouldRun(currentVersion)) { + Logger.info('Running migration ', migration.version, migration.constructor.name); + yield migration.install(); + yield query('INSERT INTO migrations VALUES(?, ?, NOW())', [ + migration.version, + migration.constructor.name, + ]); + } + } + }); + } +} +MysqlConnectionManager.databaseReady = false; +MysqlConnectionManager.migrations = []; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTXlzcWxDb25uZWN0aW9uTWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIuLyIsInNvdXJjZXMiOlsiZGIvTXlzcWxDb25uZWN0aW9uTWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFBQSxPQUFPLEtBQW9DLE1BQU0sT0FBTyxDQUFDO0FBQ3pELE9BQU8sTUFBTSxNQUFNLFFBQVEsQ0FBQztBQUU1QixPQUFPLE1BQU0sTUFBTSxXQUFXLENBQUM7QUFTL0IsTUFBTSxVQUFnQixLQUFLLENBQUMsV0FBbUIsRUFBRSxNQUFZLEVBQUUsVUFBdUI7O1FBQ2xGLE9BQU8sTUFBTSxzQkFBc0IsQ0FBQyxLQUFLLENBQUMsV0FBVyxFQUFFLE1BQU0sRUFBRSxVQUFVLENBQUMsQ0FBQztJQUMvRSxDQUFDO0NBQUE7QUFFRCxNQUFNLENBQUMsT0FBTyxPQUFPLHNCQUFzQjtJQUtoQyxNQUFNLENBQUMsaUJBQWlCLENBQUMsU0FBeUM7UUFDckUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEUsQ0FBQztJQUVNLE1BQU0sQ0FBTyxPQUFPOztZQUN2QixJQUFJLE1BQU0sQ0FBQyxHQUFHLENBQUMscUNBQXFDLENBQUMsS0FBSyxJQUFJLEVBQUU7Z0JBQzVELE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztnQkFDNUMsTUFBTSxDQUFDLElBQUksQ0FBQyxxQkFBcUIsTUFBTSxLQUFLLENBQUMsQ0FBQztnQkFDOUMsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLGdCQUFnQixDQUFDO29CQUN0QyxJQUFJLEVBQUUsTUFBTSxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUM7b0JBQzlCLElBQUksRUFBRSxNQUFNLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQztvQkFDOUIsUUFBUSxFQUFFLE1B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QUMsSUFBSSxLQUFLLGtCQUFrQixFQUFFO29CQUM1RCxNQUFNLElBQUksS0FBSyxDQUFDLHlCQUF5QixHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztpQkFDdkQ7YUFDSjtZQUVELEtBQUssTUFBTSxTQUFTLElBQUksSUFBSSxDQUFDLFVBQVUsRUFBRTtnQkFDckMsSUFBSSxNQUFNLFNBQVMsQ0FBQyxTQUFTLENBQUMsY0FBYyxDQUFDLEVBQUU7b0JBQzNDLE1BQU0sQ0FBQyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsU0FBUyxDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDO29CQUNqRixNQUFNLFNBQVMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztvQkFDMUIsTUFBTSxLQUFLLENBQUMsNENBQTRDLEVBQUU7d0JBQ3RELFNBQVMsQ0FBQyxPQUFPO3dCQUNqQixTQUFTLENBQUMsV0FBVyxDQUFDLElBQUk7cUJBQzdCLENBQUMsQ0FBQztpQkFDTjthQUNKO1FBQ0wsQ0FBQztLQUFBOztBQXJKYyxvQ0FBYSxHQUFZLEtBQUssQ0FBQztBQUN0QixpQ0FBVSxHQUFnQixFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgbXlzcWwsIHtDb25uZWN0aW9uLCBGaWVsZEluZm8sIFBvb2x9IGZyb20gJ215c3FsJztcbmltcG9ydCBjb25maWcgZnJvbSAnY29uZmlnJztcbmltcG9ydCBNaWdyYXRpb24gZnJvbSBcIi4vTWlncmF0aW9uXCI7XG5pbXBvcnQgTG9nZ2VyIGZyb20gXCIuLi9Mb2dnZXJcIjtcblxuZXhwb3J0IGludGVyZmFjZSBRdWVyeVJlc3VsdCB7XG4gICAgcmVhZG9ubHkgcmVzdWx0czogYW55W107XG4gICAgcmVhZG9ubHkgZmllbGRzOiBGaWVsZEluZm9bXTtcbiAgICByZWFkb25seSBvdGhlcj86IGFueTtcbiAgICBmb3VuZFJvd3M/OiBudW1iZXI7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBxdWVyeShxdWVyeVN0cmluZzogc3RyaW5nLCB2YWx1ZXM/OiBhbnksIGNvbm5lY3Rpb24/OiBDb25uZWN0aW9uKTogUHJvbWlzZTxRdWVyeVJlc3VsdD4ge1xuICAgIHJldHVybiBhd2FpdCBNeXNxbENvbm5lY3Rpb25NYW5hZ2VyLnF1ZXJ5KHF1ZXJ5U3RyaW5nLCB2YWx1ZXMsIGNvbm5lY3Rpb24pO1xufVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNeXNxbENvbm5lY3Rpb25NYW5hZ2VyIHtcbiAgICBwcml2YXRlIHN0YXRpYyBjdXJyZW50UG9vbD86IFBvb2w7XG4gICAgcHJpdmF0ZSBzdGF0aWMgZGF0YWJhc2VSZWFkeTogYm9vbGVhbiA9IGZhbHNlO1xuICAgIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IG1pZ3JhdGlvbnM6IE1pZ3JhdGlvbltdID0gW107XG5cbiAgICBwdWJsaWMgc3RhdGljIHJlZ2lzdGVyTWlncmF0aW9uKG1pZ3JhdGlvbjogKHZlcnNpb246IG51bWJlcikgPT4gTWlncmF0aW9uKSB7XG4gICAgICAgIHRoaXMubWlncmF0aW9ucy5wdXNoKG1pZ3JhdGlvbih0aGlzLm1pZ3JhdGlvbnMubGVuZ3RoICsgMSkpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgYXN5bmMgcHJlcGFyZSgpIHtcbiAgICAgICAgaWYgKGNvbmZpZy5nZXQoJ215c3FsLmNyZWF0ZV9kYXRhYmFzZV9hdXRvbWF0aWNhbGx5JykgPT09IHRydWUpIHtcbiAgICAgICAgICAgIGNvbnN0IGRiTmFtZSA9IGNvbmZpZy5nZXQoJ215c3FsLmRhdGFiYXNlJyk7XG4gICAgICAgICAgICBMb2dnZXIuaW5mbyhgQ3JlYXRpbmcgZGF0YWJhc2UgJHtkYk5hbWV9Li4uYCk7XG4gICAgICAgICAgICBjb25zdCBjb25uZWN0aW9uID0gbXlzcWwuY3JlYXRlQ29ubmVjdGlvbih7XG4gICAgICAgICAgICAgICAgaG9zdDogY29uZmlnLmdldCgnbXlzcWwuaG9zdCcpLFxuICAgICAgICAgICAgICAgIHVzZXI6IGNvbmZpZy5nZXQoJ215c3FsLnVzZXInKSxcbiAgICAgICAgICAgICAgICBwYXNzd29yZDogY29uZmlnLmdldCgnbXlzcWwucGFzc3dvcmQnKSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24ucXVlcnkoYENSRUFURSBEQVRBQkFTRSBJRiBOT1QgRVhJU1RTICR7ZGJOYW1lfWAsIChlcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXJyb3IgIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY29ubmVjdGlvbi5lbmQoKTtcbiAgICAgICAgICAgIExvZ2dlci5pbmZvKGBEYXRhYmFzZSAke2RiTmFtZX0gY3JlYXRlZCFgKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmRhdGFiYXNlUmVhZHkgPSB0cnVlO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuaGFuZGxlTWlncmF0aW9ucygpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgZ2V0IHBvb2woKTogUG9vbCB7XG4gICAgICAgIGlmICh0aGlzLmN1cnJlbnRQb29sID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudFBvb2wgPSB0aGlzLmNyZWF0ZVBvb2woKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5jdXJyZW50UG9vbDtcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBjcmVhdGVQb29sKCk6IFBvb2wge1xuICAgICAgICByZXR1cm4gbXlzcWwuY3JlYXRlUG9vbCh7XG4gICAgICAgICAgICBjb25uZWN0aW9uTGltaXQ6IGNvbmZpZy5nZXQoJ215c3FsLmNvbm5lY3Rpb25MaW1pdCcpLFxuICAgICAgICAgICAgaG9zdDogY29uZmlnLmdldCgnbXlzcWwuaG9zdCcpLFxuICAgICAgICAgICAgdXNlcjogY29uZmlnLmdldCgnbXlzcWwudXNlcicpLFxuICAgICAgICAgICAgcGFzc3dvcmQ6IGNvbmZpZy5nZXQoJ215c3FsLnBhc3N3b3JkJyksXG4gICAgICAgICAgICBkYXRhYmFzZTogY29uZmlnLmdldCgnbXlzcWwuZGF0YWJhc2UnKSxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBhc3luYyBlbmRQb29sKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UocmVzb2x2ZSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5jdXJyZW50UG9vbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jdXJyZW50UG9vbC5lbmQoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBMb2dnZXIuaW5mbygnTXlzcWwgY29ubmVjdGlvbiBwb29sIGVuZGVkLicpO1xuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgdGhpcy5jdXJyZW50UG9vbCA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGFzeW5jIHF1ZXJ5KHF1ZXJ5U3RyaW5nOiBzdHJpbmcsIHZhbHVlcz86IGFueSwgY29ubmVjdGlvbj86IENvbm5lY3Rpb24pOiBQcm9taXNlPFF1ZXJ5UmVzdWx0PiB7XG4gICAgICAgIHJldHVybiBhd2FpdCBuZXcgUHJvbWlzZTxRdWVyeVJlc3VsdD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgTG9nZ2VyLmRldignTXlzcWwgcXVlcnk6JywgcXVlcnlTdHJpbmcsICc7IHZhbHVlczonLCB2YWx1ZXMpO1xuICAgICAgICAgICAgKGNvbm5lY3Rpb24gPyBjb25uZWN0aW9uIDogdGhpcy5wb29sKS5xdWVyeShxdWVyeVN0cmluZywgdmFsdWVzLCAoZXJyb3IsIHJlc3VsdHMsIGZpZWxkcykgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChlcnJvciAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmVzb2x2ZSh7XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdHM6IEFycmF5LmlzQXJyYXkocmVzdWx0cykgPyByZXN1bHRzIDogW10sXG4gICAgICAgICAgICAgICAgICAgIGZpZWxkczogZmllbGRzICE9PSB1bmRlZmluZWQgPyBmaWVsZHMgOiBbXSxcbiAgICAgICAgICAgICAgICAgICAgb3RoZXI6IEFycmF5LmlzQXJyYXkocmVzdWx0cykgPyBudWxsIDogcmVzdWx0c1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgYXN5bmMgd3JhcFRyYW5zYWN0aW9uPFQ+KHRyYW5zYWN0aW9uOiAoY29ubmVjdGlvbjogQ29ubmVjdGlvbikgPT4gUHJvbWlzZTxUPik6IFByb21pc2U8VD4ge1xuICAgICAgICByZXR1cm4gYXdhaXQgbmV3IFByb21pc2U8VD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5wb29sLmdldENvbm5lY3Rpb24oKGVyciwgY29ubmVjdGlvbikgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVqZWN0KGVycik7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjb25uZWN0aW9uLmJlZ2luVHJhbnNhY3Rpb24oKGVycikgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWplY3QoZXJyKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucG9vbC5yZWxlYXNlQ29ubmVjdGlvbihjb25uZWN0aW9uKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zYWN0aW9uKGNvbm5lY3Rpb24pLnRoZW4odmFsID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24uY29tbWl0KChlcnIpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVqZWN0QW5kUm9sbGJhY2soY29ubmVjdGlvbiwgZXJyLCByZWplY3QpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBvb2wucmVsZWFzZUNvbm5lY3Rpb24oY29ubmVjdGlvbik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBvb2wucmVsZWFzZUNvbm5lY3Rpb24oY29ubmVjdGlvbik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZSh2YWwpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH0pLmNhdGNoKGVyciA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJlamVjdEFuZFJvbGxiYWNrKGNvbm5lY3Rpb24sIGVyciwgcmVqZWN0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucG9vbC5yZWxlYXNlQ29ubmVjdGlvbihjb25uZWN0aW9uKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdGF0aWMgcmVqZWN0QW5kUm9sbGJhY2soY29ubmVjdGlvbjogQ29ubmVjdGlvbiwgZXJyOiBhbnksIHJlamVjdDogKGVycjogYW55KSA9PiB2b2lkKSB7XG4gICAgICAgIGNvbm5lY3Rpb24ucm9sbGJhY2soKHJvbGxiYWNrRXJyKSA9PiB7XG4gICAgICAgICAgICBpZiAocm9sbGJhY2tFcnIpIHtcbiAgICAgICAgICAgICAgICByZWplY3QoZXJyICsgJ1xcbicgKyByb2xsYmFja0Vycik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJlamVjdChlcnIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBhc3luYyBoYW5kbGVNaWdyYXRpb25zKCkge1xuICAgICAgICBsZXQgY3VycmVudFZlcnNpb24gPSAwO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBxdWVyeSgnU0VMRUNUIGlkIEZST00gbWlncmF0aW9ucyBPUkRFUiBCWSBpZCBERVNDIExJTUlUIDEnKTtcbiAgICAgICAgICAgIGN1cnJlbnRWZXJzaW9uID0gcmVzdWx0LnJlc3VsdHNbMF0uaWQ7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGlmIChlLmNvZGUgPT09ICdFQ09OTlJFRlVTRUQnIHx8IGUuY29kZSAhPT0gJ0VSX05PX1NVQ0hfVEFCTEUnKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgcnVuIG1pZ3JhdGlvbnM6ICcgKyBlLmNvZGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgZm9yIChjb25zdCBtaWdyYXRpb24gb2YgdGhpcy5taWdyYXRpb25zKSB7XG4gICAgICAgICAgICBpZiAoYXdhaXQgbWlncmF0aW9uLnNob3VsZFJ1bihjdXJyZW50VmVyc2lvbikpIHtcbiAgICAgICAgICAgICAgICBMb2dnZXIuaW5mbygnUnVubmluZyBtaWdyYXRpb24gJywgbWlncmF0aW9uLnZlcnNpb24sIG1pZ3JhdGlvbi5jb25zdHJ1Y3Rvci5uYW1lKTtcbiAgICAgICAgICAgICAgICBhd2FpdCBtaWdyYXRpb24uaW5zdGFsbCgpO1xuICAgICAgICAgICAgICAgIGF3YWl0IHF1ZXJ5KCdJTlNFUlQgSU5UTyBtaWdyYXRpb25zIFZBTFVFUyg/LCA/LCBOT1coKSknLCBbXG4gICAgICAgICAgICAgICAgICAgIG1pZ3JhdGlvbi52ZXJzaW9uLFxuICAgICAgICAgICAgICAgICAgICBtaWdyYXRpb24uY29uc3RydWN0b3IubmFtZSxcbiAgICAgICAgICAgICAgICBdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn0iXX0= \ No newline at end of file diff --git a/dist/db/Query.d.ts b/dist/db/Query.d.ts new file mode 100644 index 0000000..72cd517 --- /dev/null +++ b/dist/db/Query.d.ts @@ -0,0 +1,47 @@ +import { QueryResult } from "./MysqlConnectionManager"; +import { Connection } from "mysql"; +export default class Query { + static select(table: string, ...fields: string[]): Query; + static update(table: string, data: { + [key: string]: any; + }): Query; + static delete(table: string): Query; + private readonly type; + private readonly table; + private readonly fields; + private _where; + private _limit?; + private _offset?; + private _sortBy?; + private _sortDirection?; + private _foundRows; + private constructor(); + where(field: string, value: string | Date | Query | any, operator?: WhereOperator, test?: WhereTest): Query; + whereNot(field: string, value: string | Date | Query | any, operator?: WhereOperator): Query; + orWhere(field: string, value: string | Date | Query | any): Query; + whereIn(field: string, value: any[]): Query; + limit(limit: number, offset?: number): Query; + first(): Query; + sortBy(field: string, direction?: 'ASC' | 'DESC'): Query; + withTotalRowCount(): Query; + toString(final?: boolean): string; + build(): string; + get variables(): any[]; + isCacheable(): boolean; + execute(connection?: Connection): Promise; +} +export declare enum QueryType { + SELECT = 0, + UPDATE = 1, + DELETE = 2 +} +declare enum WhereOperator { + AND = "AND", + OR = "OR" +} +declare enum WhereTest { + EQUALS = "=", + DIFFERENT = "!=", + IN = " IN " +} +export {}; diff --git a/dist/db/Query.js b/dist/db/Query.js new file mode 100644 index 0000000..ece3d18 --- /dev/null +++ b/dist/db/Query.js @@ -0,0 +1,176 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import { query } from "./MysqlConnectionManager"; +export default class Query { + constructor(type, table, fields) { + this._where = []; + this._foundRows = false; + this.type = type; + this.table = table; + this.fields = fields || []; + } + static select(table, ...fields) { + return new Query(QueryType.SELECT, table, fields.length > 0 ? fields : ['*']); + } + static update(table, data) { + const fields = []; + for (let key in data) { + if (data.hasOwnProperty(key)) { + fields.push(new UpdateFieldValue(key, data[key])); + } + } + return new Query(QueryType.UPDATE, table, fields); + } + static delete(table) { + return new Query(QueryType.DELETE, table); + } + where(field, value, operator = WhereOperator.AND, test = WhereTest.EQUALS) { + this._where.push(new WhereFieldValue(field, value, operator, test)); + return this; + } + whereNot(field, value, operator = WhereOperator.AND) { + return this.where(field, value, operator, WhereTest.DIFFERENT); + } + orWhere(field, value) { + return this.where(field, value, WhereOperator.OR); + } + whereIn(field, value) { + return this.where(field, value, WhereOperator.AND, WhereTest.IN); + } + limit(limit, offset = 0) { + this._limit = limit; + this._offset = offset; + return this; + } + first() { + return this.limit(1); + } + sortBy(field, direction = 'ASC') { + this._sortBy = field; + this._sortDirection = direction; + return this; + } + withTotalRowCount() { + this._foundRows = true; + return this; + } + toString(final = false) { + var _a; + let query = ''; + let fields = (_a = this.fields) === null || _a === void 0 ? void 0 : _a.join(','); + let where = ''; + if (this._where.length > 0) { + where = `WHERE ${this._where[0]}`; + for (let i = 1; i < this._where.length; i++) { + where += this._where[i].toString(false); + } + } + let limit = ''; + if (typeof this._limit === 'number') { + limit = `LIMIT ${this._limit}`; + if (typeof this._offset === 'number' && this._offset !== 0) { + limit += ` OFFSET ${this._offset}`; + } + } + let orderBy = ''; + if (typeof this._sortBy === 'string') { + orderBy = `ORDER BY ${this._sortBy} ${this._sortDirection}`; + } + switch (this.type) { + case QueryType.SELECT: + query = `SELECT ${this._foundRows ? 'SQL_CALC_FOUND_ROWS' : ''} ${fields} FROM ${this.table} ${where} ${orderBy} ${limit}`; + break; + case QueryType.UPDATE: + query = `UPDATE ${this.table} SET ${fields} ${where} ${orderBy} ${limit}`; + break; + case QueryType.DELETE: + query = `DELETE FROM ${this.table} ${where} ${orderBy} ${limit}`; + break; + } + return final ? query : `(${query})`; + } + build() { + return this.toString(true); + } + get variables() { + var _a; + const variables = []; + (_a = this.fields) === null || _a === void 0 ? void 0 : _a.filter(v => v instanceof FieldValue).flatMap(v => v.variables).forEach(v => variables.push(v)); + this._where.flatMap(v => v.variables) + .forEach(v => variables.push(v)); + return variables; + } + isCacheable() { + return this.type === QueryType.SELECT && this.fields.length === 1 && this.fields[0] === '*'; + } + execute(connection) { + return __awaiter(this, void 0, void 0, function* () { + const queryResult = yield query(this.build(), this.variables, connection); + if (this._foundRows) { + const foundRows = yield query('SELECT FOUND_ROWS() as r', undefined, connection); + queryResult.foundRows = foundRows.results[0].r; + } + return queryResult; + }); + } +} +export var QueryType; +(function (QueryType) { + QueryType[QueryType["SELECT"] = 0] = "SELECT"; + QueryType[QueryType["UPDATE"] = 1] = "UPDATE"; + QueryType[QueryType["DELETE"] = 2] = "DELETE"; +})(QueryType || (QueryType = {})); +var WhereOperator; +(function (WhereOperator) { + WhereOperator["AND"] = "AND"; + WhereOperator["OR"] = "OR"; +})(WhereOperator || (WhereOperator = {})); +var WhereTest; +(function (WhereTest) { + WhereTest["EQUALS"] = "="; + WhereTest["DIFFERENT"] = "!="; + WhereTest["IN"] = " IN "; +})(WhereTest || (WhereTest = {})); +class FieldValue { + constructor(field, value) { + this.field = field; + this.value = value; + } + toString(first = true) { + return `${!first ? ',' : ''}${this.field}${this.test}${this.value instanceof Query ? this.value : (Array.isArray(this.value) ? '(?)' : '?')}`; + } + get test() { + return '='; + } + get variables() { + return this.value instanceof Query ? this.value.variables : [this.value]; + } +} +class SelectFieldValue extends FieldValue { + toString(first = true) { + return `(${this.value instanceof Query ? this.value : '?'}) AS ${this.field}`; + } +} +class UpdateFieldValue extends FieldValue { +} +class WhereFieldValue extends FieldValue { + constructor(field, value, operator, test) { + super(field, value); + this.operator = operator; + this._test = test; + } + toString(first = true) { + return (!first ? ` ${this.operator} ` : '') + super.toString(true); + } + get test() { + return this._test; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUXVlcnkuanMiLCJzb3VyY2VSb290IjoiLi8iLCJzb3VyY2VzIjpbImRiL1F1ZXJ5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBLE9BQU8sRUFBQyxLQUFLLEVBQWMsTUFBTSwwQkFBMEIsQ0FBQztBQUc1RCxNQUFNLENBQUMsT0FBTyxPQUFPLEtBQUs7SUErQnRCLFlBQW9CLElBQWUsRUFBRSxLQUFhLEVBQUUsTUFBeUQ7UUFQckcsV0FBTSxHQUFzQixFQUFFLENBQUM7UUFLL0IsZUFBVSxHQUFZLEtBQUssQ0FBQztRQUdoQyxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztRQUNqQixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUNuQixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sSUFBSSxFQUFFLENBQUM7SUFDL0IsQ0FBQztJQWxDTSxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQWEsRUFBRSxHQUFHLE1BQWdCO1FBQ25ELE9BQU8sSUFBSSxLQUFLLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ2xGLENBQUM7SUFFTSxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQWEsRUFBRSxJQUVuQztRQUNHLE1BQU0sTUFBTSxHQUFHLEVBQUUsQ0FBQztRQUNsQixLQUFLLElBQUksR0FBRyxJQUFJLElBQUksRUFBRTtZQUNsQixJQUFJLElBQUksQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLEVBQUU7Z0JBQzFCLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxnQkFBZ0IsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQzthQUNyRDtTQUNKO1FBQ0QsT0FBTyxJQUFJLEtBQUssQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLEtB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Q0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDN0UsQ0FBQztDQUNKO0FBRUQsTUFBTSxnQkFBaUIsU0FBUSxVQUFVO0lBQzlCLFFBQVEsQ0FBQyxRQUFpQixJQUFJO1FBQ2pDLE9BQU8sSUFBSSxJQUFJLENBQUMsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxRQUFRLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNsRixDQUFDO0NBQ0o7QUFFRCxNQUFNLGdCQUFpQixTQUFRLFVBQVU7Q0FDeEM7QUFFRCxNQUFNLGVBQWdCLFNBQVEsVUFBVTtJQUlwQyxZQUFZLEtBQWEsRUFBRSxLQUFVLEVBQUUsUUFBdUIsRUFBRSxJQUFlO1FBQzNFLEtBQUssQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDcEIsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFDekIsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUM7SUFDdEIsQ0FBQztJQUVNLFFBQVEsQ0FBQyxRQUFpQixJQUFJO1FBQ2pDLE9BQU8sQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsUUFBUSxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkUsQ0FBQztJQUVELElBQWMsSUFBSTtRQUNkLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQztJQUN0QixDQUFDO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge3F1ZXJ5LCBRdWVyeVJlc3VsdH0gZnJvbSBcIi4vTXlzcWxDb25uZWN0aW9uTWFuYWdlclwiO1xuaW1wb3J0IHtDb25uZWN0aW9ufSBmcm9tIFwibXlzcWxcIjtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgUXVlcnkge1xuICAgIHB1YmxpYyBzdGF0aWMgc2VsZWN0KHRhYmxlOiBzdHJpbmcsIC4uLmZpZWxkczogc3RyaW5nW10pOiBRdWVyeSB7XG4gICAgICAgIHJldHVybiBuZXcgUXVlcnkoUXVlcnlUeXBlLlNFTEVDVCwgdGFibGUsIGZpZWxkcy5sZW5ndGggPiAwID8gZmllbGRzIDogWycqJ10pO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgdXBkYXRlKHRhYmxlOiBzdHJpbmcsIGRhdGE6IHtcbiAgICAgICAgW2tleTogc3RyaW5nXTogYW55XG4gICAgfSkge1xuICAgICAgICBjb25zdCBmaWVsZHMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQga2V5IGluIGRhdGEpIHtcbiAgICAgICAgICAgIGlmIChkYXRhLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgICAgICBmaWVsZHMucHVzaChuZXcgVXBkYXRlRmllbGRWYWx1ZShrZXksIGRhdGFba2V5XSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgUXVlcnkoUXVlcnlUeXBlLlVQREFURSwgdGFibGUsIGZpZWxkcyk7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBkZWxldGUodGFibGU6IHN0cmluZykge1xuICAgICAgICByZXR1cm4gbmV3IFF1ZXJ5KFF1ZXJ5VHlwZS5ERUxFVEUsIHRhYmxlKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlYWRvbmx5IHR5cGU6IFF1ZXJ5VHlwZTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHRhYmxlOiBzdHJpbmc7XG4gICAgcHJpdmF0ZSByZWFkb25seSBmaWVsZHM6IChzdHJpbmcgfCBTZWxlY3RGaWVsZFZhbHVlIHwgVXBkYXRlRmllbGRWYWx1ZSlbXTtcbiAgICBwcml2YXRlIF93aGVyZTogV2hlcmVGaWVsZFZhbHVlW10gPSBbXTtcbiAgICBwcml2YXRlIF9saW1pdD86IG51bWJlcjtcbiAgICBwcml2YXRlIF9vZmZzZXQ/OiBudW1iZXI7XG4gICAgcHJpdmF0ZSBfc29ydEJ5Pzogc3RyaW5nO1xuICAgIHByaXZhdGUgX3NvcnREaXJlY3Rpb24/OiAnQVNDJyB8ICdERVNDJztcbiAgICBwcml2YXRlIF9mb3VuZFJvd3M6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIHByaXZhdGUgY29uc3RydWN0b3IodHlwZTogUXVlcnlUeXBlLCB0YWJsZTogc3RyaW5nLCBmaWVsZHM/OiAoc3RyaW5nIHwgU2VsZWN0RmllbGRWYWx1ZSB8IFVwZGF0ZUZpZWxkVmFsdWUpW10pIHtcbiAgICAgICAgdGhpcy50eXBlID0gdHlwZTtcbiAgICAgICAgdGhpcy50YWJsZSA9IHRhYmxlO1xuICAgICAgICB0aGlzLmZpZWxkcyA9IGZpZWxkcyB8fCBbXTtcbiAgICB9XG5cbiAgICBwdWJsaWMgd2hlcmUoZmllbGQ6IHN0cmluZywgdmFsdWU6IHN0cmluZyB8IERhdGUgfCBRdWVyeSB8IGFueSwgb3BlcmF0b3I6IFdoZXJlT3BlcmF0b3IgPSBXaGVyZU9wZXJhdG9yLkFORCwgdGVzdDogV2hlcmVUZXN0ID0gV2hlcmVUZXN0LkVRVUFMUyk6IFF1ZXJ5IHtcbiAgICAgICAgdGhpcy5fd2hlcmUucHVzaChuZXcgV2hlcmVGaWVsZFZhbHVlKGZpZWxkLCB2YWx1ZSwgb3BlcmF0b3IsIHRlc3QpKTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgcHVibGljIHdoZXJlTm90KGZpZWxkOiBzdHJpbmcsIHZhbHVlOiBzdHJpbmcgfCBEYXRlIHwgUXVlcnkgfCBhbnksIG9wZXJhdG9yOiBXaGVyZU9wZXJhdG9yID0gV2hlcmVPcGVyYXRvci5BTkQpOiBRdWVyeSB7XG4gICAgICAgIHJldHVybiB0aGlzLndoZXJlKGZpZWxkLCB2YWx1ZSwgb3BlcmF0b3IsIFdoZXJlVGVzdC5ESUZGRVJFTlQpO1xuICAgIH1cblxuICAgIHB1YmxpYyBvcldoZXJlKGZpZWxkOiBzdHJpbmcsIHZhbHVlOiBzdHJpbmcgfCBEYXRlIHwgUXVlcnkgfCBhbnkpOiBRdWVyeSB7XG4gICAgICAgIHJldHVybiB0aGlzLndoZXJlKGZpZWxkLCB2YWx1ZSwgV2hlcmVPcGVyYXRvci5PUik7XG4gICAgfVxuXG4gICAgcHVibGljIHdoZXJlSW4oZmllbGQ6IHN0cmluZywgdmFsdWU6IGFueVtdKTogUXVlcnkge1xuICAgICAgICByZXR1cm4gdGhpcy53aGVyZShmaWVsZCwgdmFsdWUsIFdoZXJlT3BlcmF0b3IuQU5ELCBXaGVyZVRlc3QuSU4pO1xuICAgIH1cblxuICAgIHB1YmxpYyBsaW1pdChsaW1pdDogbnVtYmVyLCBvZmZzZXQ6IG51bWJlciA9IDApOiBRdWVyeSB7XG4gICAgICAgIHRoaXMuX2xpbWl0ID0gbGltaXQ7XG4gICAgICAgIHRoaXMuX29mZnNldCA9IG9mZnNldDtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgcHVibGljIGZpcnN0KCk6IFF1ZXJ5IHtcbiAgICAgICAgcmV0dXJuIHRoaXMubGltaXQoMSk7XG4gICAgfVxuXG4gICAgcHVibGljIHNvcnRCeShmaWVsZDogc3RyaW5nLCBkaXJlY3Rpb246ICdBU0MnIHwgJ0RFU0MnID0gJ0FTQycpOiBRdWVyeSB7XG4gICAgICAgIHRoaXMuX3NvcnRCeSA9IGZpZWxkO1xuICAgICAgICB0aGlzLl9zb3J0RGlyZWN0aW9uID0gZGlyZWN0aW9uO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBwdWJsaWMgd2l0aFRvdGFsUm93Q291bnQoKTogUXVlcnkge1xuICAgICAgICB0aGlzLl9mb3VuZFJvd3MgPSB0cnVlO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBwdWJsaWMgdG9TdHJpbmcoZmluYWw6IGJvb2xlYW4gPSBmYWxzZSk6IHN0cmluZyB7XG4gICAgICAgIGxldCBxdWVyeSA9ICcnO1xuXG4gICAgICAgIGxldCBmaWVsZHMgPSB0aGlzLmZpZWxkcz8uam9pbignLCcpO1xuXG4gICAgICAgIGxldCB3aGVyZSA9ICcnO1xuICAgICAgICBpZiAodGhpcy5fd2hlcmUubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgd2hlcmUgPSBgV0hFUkUgJHt0aGlzLl93aGVyZVswXX1gO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDE7IGkgPCB0aGlzLl93aGVyZS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHdoZXJlICs9IHRoaXMuX3doZXJlW2ldLnRvU3RyaW5nKGZhbHNlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBsaW1pdCA9ICcnO1xuICAgICAgICBpZiAodHlwZW9mIHRoaXMuX2xpbWl0ID09PSAnbnVtYmVyJykge1xuICAgICAgICAgICAgbGltaXQgPSBgTElNSVQgJHt0aGlzLl9saW1pdH1gO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiB0aGlzLl9vZmZzZXQgPT09ICdudW1iZXInICYmIHRoaXMuX29mZnNldCAhPT0gMCkge1xuICAgICAgICAgICAgICAgIGxpbWl0ICs9IGAgT0ZGU0VUICR7dGhpcy5fb2Zmc2V0fWA7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgb3JkZXJCeSA9ICcnO1xuICAgICAgICBpZiAodHlwZW9mIHRoaXMuX3NvcnRCeSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIG9yZGVyQnkgPSBgT1JERVIgQlkgJHt0aGlzLl9zb3J0Qnl9ICR7dGhpcy5fc29ydERpcmVjdGlvbn1gO1xuICAgICAgICB9XG5cbiAgICAgICAgc3dpdGNoICh0aGlzLnR5cGUpIHtcbiAgICAgICAgICAgIGNhc2UgUXVlcnlUeXBlLlNFTEVDVDpcbiAgICAgICAgICAgICAgICBxdWVyeSA9IGBTRUxFQ1QgJHt0aGlzLl9mb3VuZFJvd3MgPyAnU1FMX0NBTENfRk9VTkRfUk9XUycgOiAnJ30gJHtmaWVsZHN9IEZST00gJHt0aGlzLnRhYmxlfSAke3doZXJlfSAke29yZGVyQnl9ICR7bGltaXR9YDtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgUXVlcnlUeXBlLlVQREFURTpcbiAgICAgICAgICAgICAgICBxdWVyeSA9IGBVUERBVEUgJHt0aGlzLnRhYmxlfSBTRVQgJHtmaWVsZHN9ICR7d2hlcmV9ICR7b3JkZXJCeX0gJHtsaW1pdH1gO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBRdWVyeVR5cGUuREVMRVRFOlxuICAgICAgICAgICAgICAgIHF1ZXJ5ID0gYERFTEVURSBGUk9NICR7dGhpcy50YWJsZX0gJHt3aGVyZX0gJHtvcmRlckJ5fSAke2xpbWl0fWA7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBmaW5hbCA/IHF1ZXJ5IDogYCgke3F1ZXJ5fSlgO1xuICAgIH1cblxuICAgIHB1YmxpYyBidWlsZCgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy50b1N0cmluZyh0cnVlKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IHZhcmlhYmxlcygpOiBhbnlbXSB7XG4gICAgICAgIGNvbnN0IHZhcmlhYmxlczogYW55W10gPSBbXTtcbiAgICAgICAgdGhpcy5maWVsZHM/LmZpbHRlcih2ID0+IHYgaW5zdGFuY2VvZiBGaWVsZFZhbHVlKVxuICAgICAgICAgICAgLmZsYXRNYXAodiA9PiAoPEZpZWxkVmFsdWU+dikudmFyaWFibGVzKVxuICAgICAgICAgICAgLmZvckVhY2godiA9PiB2YXJpYWJsZXMucHVzaCh2KSk7XG4gICAgICAgIHRoaXMuX3doZXJlLmZsYXRNYXAodiA9PiB2LnZhcmlhYmxlcylcbiAgICAgICAgICAgIC5mb3JFYWNoKHYgPT4gdmFyaWFibGVzLnB1c2godikpO1xuICAgICAgICByZXR1cm4gdmFyaWFibGVzO1xuICAgIH1cblxuICAgIHB1YmxpYyBpc0NhY2hlYWJsZSgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudHlwZSA9PT0gUXVlcnlUeXBlLlNFTEVDVCAmJiB0aGlzLmZpZWxkcy5sZW5ndGggPT09IDEgJiYgdGhpcy5maWVsZHNbMF0gPT09ICcqJztcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZXhlY3V0ZShjb25uZWN0aW9uPzogQ29ubmVjdGlvbik6IFByb21pc2U8UXVlcnlSZXN1bHQ+IHtcbiAgICAgICAgY29uc3QgcXVlcnlSZXN1bHQgPSBhd2FpdCBxdWVyeSh0aGlzLmJ1aWxkKCksIHRoaXMudmFyaWFibGVzLCBjb25uZWN0aW9uKTtcbiAgICAgICAgaWYgKHRoaXMuX2ZvdW5kUm93cykge1xuICAgICAgICAgICAgY29uc3QgZm91bmRSb3dzID0gYXdhaXQgcXVlcnkoJ1NFTEVDVCBGT1VORF9ST1dTKCkgYXMgcicsIHVuZGVmaW5lZCwgY29ubmVjdGlvbik7XG4gICAgICAgICAgICBxdWVyeVJlc3VsdC5mb3VuZFJvd3MgPSBmb3VuZFJvd3MucmVzdWx0c1swXS5yO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBxdWVyeVJlc3VsdDtcbiAgICB9XG59XG5cbmV4cG9ydCBlbnVtIFF1ZXJ5VHlwZSB7XG4gICAgU0VMRUNULFxuICAgIFVQREFURSxcbiAgICBERUxFVEUsXG59XG5cbmVudW0gV2hlcmVPcGVyYXRvciB7XG4gICAgQU5EID0gJ0FORCcsXG4gICAgT1IgPSAnT1InLFxufVxuXG5lbnVtIFdoZXJlVGVzdCB7XG4gICAgRVFVQUxTID0gJz0nLFxuICAgIERJRkZFUkVOVCA9ICchPScsXG4gICAgSU4gPSAnIElOICcsXG59XG5cbmNsYXNzIEZpZWxkVmFsdWUge1xuICAgIHByb3RlY3RlZCByZWFkb25seSBmaWVsZDogc3RyaW5nO1xuICAgIHByb3RlY3RlZCB2YWx1ZTogYW55O1xuXG4gICAgY29uc3RydWN0b3IoZmllbGQ6IHN0cmluZywgdmFsdWU6IGFueSkge1xuICAgICAgICB0aGlzLmZpZWxkID0gZmllbGQ7XG4gICAgICAgIHRoaXMudmFsdWUgPSB2YWx1ZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgdG9TdHJpbmcoZmlyc3Q6IGJvb2xlYW4gPSB0cnVlKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIGAkeyFmaXJzdCA/ICcsJyA6ICcnfSR7dGhpcy5maWVsZH0ke3RoaXMudGVzdH0ke3RoaXMudmFsdWUgaW5zdGFuY2VvZiBRdWVyeSA/IHRoaXMudmFsdWUgOiAoQXJyYXkuaXNBcnJheSh0aGlzLnZhbHVlKSA/ICcoPyknIDogJz8nKX1gO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBnZXQgdGVzdCgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gJz0nO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgdmFyaWFibGVzKCk6IGFueVtdIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWUgaW5zdGFuY2VvZiBRdWVyeSA/IHRoaXMudmFsdWUudmFyaWFibGVzIDogW3RoaXMudmFsdWVdO1xuICAgIH1cbn1cblxuY2xhc3MgU2VsZWN0RmllbGRWYWx1ZSBleHRlbmRzIEZpZWxkVmFsdWUge1xuICAgIHB1YmxpYyB0b1N0cmluZyhmaXJzdDogYm9vbGVhbiA9IHRydWUpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gYCgke3RoaXMudmFsdWUgaW5zdGFuY2VvZiBRdWVyeSA/IHRoaXMudmFsdWUgOiAnPyd9KSBBUyAke3RoaXMuZmllbGR9YDtcbiAgICB9XG59XG5cbmNsYXNzIFVwZGF0ZUZpZWxkVmFsdWUgZXh0ZW5kcyBGaWVsZFZhbHVlIHtcbn1cblxuY2xhc3MgV2hlcmVGaWVsZFZhbHVlIGV4dGVuZHMgRmllbGRWYWx1ZSB7XG4gICAgcHJpdmF0ZSByZWFkb25seSBvcGVyYXRvcjogV2hlcmVPcGVyYXRvcjtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF90ZXN0OiBXaGVyZVRlc3Q7XG5cbiAgICBjb25zdHJ1Y3RvcihmaWVsZDogc3RyaW5nLCB2YWx1ZTogYW55LCBvcGVyYXRvcjogV2hlcmVPcGVyYXRvciwgdGVzdDogV2hlcmVUZXN0KSB7XG4gICAgICAgIHN1cGVyKGZpZWxkLCB2YWx1ZSk7XG4gICAgICAgIHRoaXMub3BlcmF0b3IgPSBvcGVyYXRvcjtcbiAgICAgICAgdGhpcy5fdGVzdCA9IHRlc3Q7XG4gICAgfVxuXG4gICAgcHVibGljIHRvU3RyaW5nKGZpcnN0OiBib29sZWFuID0gdHJ1ZSk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiAoIWZpcnN0ID8gYCAke3RoaXMub3BlcmF0b3J9IGAgOiAnJykgKyBzdXBlci50b1N0cmluZyh0cnVlKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgZ2V0IHRlc3QoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3Rlc3Q7XG4gICAgfVxufSJdfQ== \ No newline at end of file diff --git a/dist/db/Validator.d.ts b/dist/db/Validator.d.ts new file mode 100644 index 0000000..e5a2edd --- /dev/null +++ b/dist/db/Validator.d.ts @@ -0,0 +1,86 @@ +import Model from "./Model"; +import Query from "./Query"; +import { Connection } from "mysql"; +export default class Validator { + private readonly steps; + private readonly validationAttributes; + private _min?; + private _max?; + /** + * @param thingName The name of the thing to validate. + * @param value The value to verify. + * @param onlyFormat {@code true} to only validate format properties, {@code false} otherwise. + * @param connection A connection to use in case of wrapped transactions. + */ + execute(thingName: string, value: T | undefined, onlyFormat: boolean, connection?: Connection): Promise; + defined(): Validator; + acceptUndefined(): Validator; + equals(other?: T): Validator; + regexp(regexp: RegExp): Validator; + length(length: number): Validator; + /** + * @param minLength included + * @param maxLength included + */ + between(minLength: number, maxLength: number): Validator; + /** + * @param min included + */ + min(min: number): Validator; + /** + * @param max included + */ + max(max: number): Validator; + unique(model: Model, querySupplier?: () => Query): Validator; + exists(modelClass: Function, foreignKey?: string): Validator; + private addStep; + getValidationAttributes(): string[]; + step(step: number): Validator; +} +export declare class ValidationBag extends Error { + private readonly messages; + addMessage(err: ValidationError): void; + hasMessages(): boolean; + getMessages(): { + [p: string]: ValidationError; + }; +} +export declare abstract class ValidationError extends Error { + thingName?: string; + value?: any; + get name(): string; +} +export declare class BadLengthValidationError extends ValidationError { + private readonly expectedLength; + private readonly maxLength?; + constructor(expectedLength: number, maxLength?: number); + get message(): string; +} +export declare class BadValueValidationError extends ValidationError { + private readonly expectedValue; + constructor(expectedValue: any); + get message(): string; +} +export declare class OutOfRangeValidationError extends ValidationError { + private readonly min?; + private readonly max?; + constructor(min?: number, max?: number); + get message(): string; +} +export declare class InvalidFormatValidationError extends ValidationError { + get message(): string; +} +export declare class UndefinedValueValidationError extends ValidationError { + get message(): string; +} +export declare class AlreadyExistsValidationError extends ValidationError { + private readonly table; + constructor(table: string); + get message(): string; +} +export declare class UnknownRelationValidationError extends ValidationError { + private readonly table; + private readonly foreignKey?; + constructor(table: string, foreignKey?: string); + get message(): string; +} diff --git a/dist/db/Validator.js b/dist/db/Validator.js new file mode 100644 index 0000000..6766235 --- /dev/null +++ b/dist/db/Validator.js @@ -0,0 +1,261 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +export default class Validator { + constructor() { + this.steps = []; + this.validationAttributes = []; + } + /** + * @param thingName The name of the thing to validate. + * @param value The value to verify. + * @param onlyFormat {@code true} to only validate format properties, {@code false} otherwise. + * @param connection A connection to use in case of wrapped transactions. + */ + execute(thingName, value, onlyFormat, connection) { + return __awaiter(this, void 0, void 0, function* () { + const bag = new ValidationBag(); + for (const step of this.steps) { + if (onlyFormat && !step.isFormat) + continue; + const result = step.verifyStep(value, thingName, connection); + if ((result === false || result instanceof Promise && (yield result) === false) && step.throw) { + const error = step.throw(); + error.thingName = thingName; + error.value = value; + bag.addMessage(error); + } + else if (step.interrupt !== undefined && step.interrupt(value)) { + break; + } + } + if (bag.hasMessages()) { + throw bag; + } + }); + } + defined() { + this.validationAttributes.push('required'); + this.addStep({ + verifyStep: val => val !== undefined, + throw: () => new UndefinedValueValidationError(), + isFormat: true, + }); + return this; + } + acceptUndefined() { + this.addStep({ + verifyStep: () => true, + throw: null, + interrupt: val => val === undefined || val === null, + isFormat: true, + }); + return this; + } + equals(other) { + this.addStep({ + verifyStep: val => val === other, + throw: () => new BadValueValidationError(other), + isFormat: true, + }); + return this; + } + regexp(regexp) { + this.validationAttributes.push(`pattern="${regexp}"`); + this.addStep({ + verifyStep: val => regexp.test(val), + throw: () => new InvalidFormatValidationError(), + isFormat: true, + }); + return this; + } + length(length) { + this.addStep({ + verifyStep: val => val.length === length, + throw: () => new BadLengthValidationError(length), + isFormat: true, + }); + return this; + } + /** + * @param minLength included + * @param maxLength included + */ + between(minLength, maxLength) { + this.addStep({ + verifyStep: val => { + const length = val.length; + return length >= minLength && length <= maxLength; + }, + throw: () => new BadLengthValidationError(minLength, maxLength), + isFormat: true, + }); + return this; + } + /** + * @param min included + */ + min(min) { + this.validationAttributes.push(`min="${min}"`); + this._min = min; + this.addStep({ + verifyStep: val => { + return val >= min; + }, + throw: () => new OutOfRangeValidationError(this._min, this._max), + isFormat: true, + }); + return this; + } + /** + * @param max included + */ + max(max) { + this.validationAttributes.push(`max="${max}"`); + this._max = max; + this.addStep({ + verifyStep: val => { + return val <= max; + }, + throw: () => new OutOfRangeValidationError(this._min, this._max), + isFormat: true, + }); + return this; + } + unique(model, querySupplier) { + this.addStep({ + verifyStep: (val, thingName, c) => __awaiter(this, void 0, void 0, function* () { + let query; + if (querySupplier) { + query = querySupplier().where(thingName, val); + } + else { + query = model.constructor.select('1').where(thingName, val); + } + if (typeof model.id === 'number') + query = query.whereNot('id', model.id); + return (yield query.execute(c)).results.length === 0; + }), + throw: () => new AlreadyExistsValidationError(model.table), + isFormat: false, + }); + return this; + } + exists(modelClass, foreignKey) { + this.addStep({ + verifyStep: (val, thingName, c) => __awaiter(this, void 0, void 0, function* () { return (yield modelClass.select('1').where(foreignKey !== undefined ? foreignKey : thingName, val).execute(c)).results.length >= 1; }), + throw: () => new UnknownRelationValidationError(modelClass.table, foreignKey), + isFormat: false, + }); + return this; + } + addStep(step) { + this.steps.push(step); + } + getValidationAttributes() { + return this.validationAttributes; + } + step(step) { + this.validationAttributes.push(`step="${step}"`); + return this; + } +} +export class ValidationBag extends Error { + constructor() { + super(...arguments); + this.messages = {}; + } + addMessage(err) { + if (!err.thingName) { + throw new Error('Null thing name'); + } + this.messages[err.thingName] = { + name: err.name, + message: err.message, + value: err.value, + }; + } + hasMessages() { + return Object.keys(this.messages).length > 0; + } + getMessages() { + return this.messages; + } +} +export class ValidationError extends Error { + get name() { + return this.constructor.name; + } +} +export class BadLengthValidationError extends ValidationError { + constructor(expectedLength, maxLength) { + super(); + this.expectedLength = expectedLength; + this.maxLength = maxLength; + } + get message() { + return `${this.thingName} expected length: ${this.expectedLength}${this.maxLength !== undefined ? ` to ${this.maxLength}` : ''}; ` + + `actual length: ${this.value.length}.`; + } +} +export class BadValueValidationError extends ValidationError { + constructor(expectedValue) { + super(); + this.expectedValue = expectedValue; + } + get message() { + return `Expected: ${this.expectedValue}; got: ${this.value}.`; + } +} +export class OutOfRangeValidationError extends ValidationError { + constructor(min, max) { + super(); + this.min = min; + this.max = max; + } + get message() { + if (this.min === undefined) { + return `${this.thingName} must be at most ${this.max}`; + } + else if (this.max === undefined) { + return `${this.thingName} must be at least ${this.min}`; + } + return `${this.thingName} must be between ${this.min} and ${this.max}.`; + } +} +export class InvalidFormatValidationError extends ValidationError { + get message() { + return `"${this.value}" is not a valid ${this.thingName}.`; + } +} +export class UndefinedValueValidationError extends ValidationError { + get message() { + return `${this.thingName} is required.`; + } +} +export class AlreadyExistsValidationError extends ValidationError { + constructor(table) { + super(); + this.table = table; + } + get message() { + return `${this.value} already exists in ${this.table}.${this.thingName}.`; + } +} +export class UnknownRelationValidationError extends ValidationError { + constructor(table, foreignKey) { + super(); + this.table = table; + this.foreignKey = foreignKey; + } + get message() { + return `${this.thingName}=${this.value} relation was not found in ${this.table}${this.foreignKey !== undefined ? `.${this.foreignKey}` : ''}.`; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVmFsaWRhdG9yLmpzIiwic291cmNlUm9vdCI6Ii4vIiwic291cmNlcyI6WyJkYi9WYWxpZGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBSUEsTUFBTSxDQUFDLE9BQU8sT0FBTyxTQUFTO0lBQTlCO1FBQ3FCLFVBQUssR0FBd0IsRUFBRSxDQUFDO1FBQ2hDLHlCQUFvQixHQUFhLEVBQUUsQ0FBQztJQXlLekQsQ0FBQztJQXBLRzs7Ozs7T0FLRztJQUNHLE9BQU8sQ0FBQyxTQUFpQixFQUFFLEtBQW9CLEVBQUUsVUFBbUIsRUFBRSxVQUF1Qjs7WUFDL0YsTUFBTSxHQUFHLEdBQUcsSUFBSSxhQUFhLEVBQUUsQ0FBQztZQUVoQyxLQUFLLE1BQU0sSUFBSSxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUU7Z0JBQzNCLElBQUksVUFBVSxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVE7b0JBQUUsU0FBUztnQkFFM0MsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLEVBQUUsU0FBUyxFQUFFLFVBQVUsQ0FBQyxDQUFDO2dCQUM3RCxJQUFJLENBQUMsTUFBTSxLQUFLLEtBQUssSUFBSSxNQUFNLFlBQVksT0FBTyxJQUFJLENBQUMsTUFBTSxNQUFNLENBQUMsS0FBSyxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFO29CQUMzRixNQUFNLEtBQUssR0FBb0IsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO29CQUM1QyxLQUFLLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztvQkFDNUIsS0FBSyxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7b0JBQ3BCLEdBQUcsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7aUJBQ3pCO3FCQUFNLElBQUksSUFBSSxDQUFDLFNBQVMsS0FBSyxTQUFTLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsRUFBRTtvQkFDOUQsTUFBTTtpQkFDVDthQUNKO1lBRUQsSUFB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LEVBQUUsR0FBRyxDQUFDO0lBQ25KLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBNb2RlbCBmcm9tIFwiLi9Nb2RlbFwiO1xuaW1wb3J0IFF1ZXJ5IGZyb20gXCIuL1F1ZXJ5XCI7XG5pbXBvcnQge0Nvbm5lY3Rpb259IGZyb20gXCJteXNxbFwiO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBWYWxpZGF0b3I8VD4ge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgc3RlcHM6IFZhbGlkYXRpb25TdGVwPFQ+W10gPSBbXTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHZhbGlkYXRpb25BdHRyaWJ1dGVzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgcHJpdmF0ZSBfbWluPzogbnVtYmVyO1xuICAgIHByaXZhdGUgX21heD86IG51bWJlcjtcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSB0aGluZ05hbWUgVGhlIG5hbWUgb2YgdGhlIHRoaW5nIHRvIHZhbGlkYXRlLlxuICAgICAqIEBwYXJhbSB2YWx1ZSBUaGUgdmFsdWUgdG8gdmVyaWZ5LlxuICAgICAqIEBwYXJhbSBvbmx5Rm9ybWF0IHtAY29kZSB0cnVlfSB0byBvbmx5IHZhbGlkYXRlIGZvcm1hdCBwcm9wZXJ0aWVzLCB7QGNvZGUgZmFsc2V9IG90aGVyd2lzZS5cbiAgICAgKiBAcGFyYW0gY29ubmVjdGlvbiBBIGNvbm5lY3Rpb24gdG8gdXNlIGluIGNhc2Ugb2Ygd3JhcHBlZCB0cmFuc2FjdGlvbnMuXG4gICAgICovXG4gICAgYXN5bmMgZXhlY3V0ZSh0aGluZ05hbWU6IHN0cmluZywgdmFsdWU6IFQgfCB1bmRlZmluZWQsIG9ubHlGb3JtYXQ6IGJvb2xlYW4sIGNvbm5lY3Rpb24/OiBDb25uZWN0aW9uKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IGJhZyA9IG5ldyBWYWxpZGF0aW9uQmFnKCk7XG5cbiAgICAgICAgZm9yIChjb25zdCBzdGVwIG9mIHRoaXMuc3RlcHMpIHtcbiAgICAgICAgICAgIGlmIChvbmx5Rm9ybWF0ICYmICFzdGVwLmlzRm9ybWF0KSBjb250aW51ZTtcblxuICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gc3RlcC52ZXJpZnlTdGVwKHZhbHVlLCB0aGluZ05hbWUsIGNvbm5lY3Rpb24pO1xuICAgICAgICAgICAgaWYgKChyZXN1bHQgPT09IGZhbHNlIHx8IHJlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UgJiYgKGF3YWl0IHJlc3VsdCkgPT09IGZhbHNlKSAmJiBzdGVwLnRocm93KSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZXJyb3I6IFZhbGlkYXRpb25FcnJvciA9IHN0ZXAudGhyb3coKTtcbiAgICAgICAgICAgICAgICBlcnJvci50aGluZ05hbWUgPSB0aGluZ05hbWU7XG4gICAgICAgICAgICAgICAgZXJyb3IudmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgICAgICAgICBiYWcuYWRkTWVzc2FnZShlcnJvcik7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHN0ZXAuaW50ZXJydXB0ICE9PSB1bmRlZmluZWQgJiYgc3RlcC5pbnRlcnJ1cHQodmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoYmFnLmhhc01lc3NhZ2VzKCkpIHtcbiAgICAgICAgICAgIHRocm93IGJhZztcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBkZWZpbmVkKCk6IFZhbGlkYXRvcjxUPiB7XG4gICAgICAgIHRoaXMudmFsaWRhdGlvbkF0dHJpYnV0ZXMucHVzaCgncmVxdWlyZWQnKTtcblxuICAgICAgICB0aGlzLmFkZFN0ZXAoe1xuICAgICAgICAgICAgdmVyaWZ5U3RlcDogdmFsID0+IHZhbCAhPT0gdW5kZWZpbmVkLFxuICAgICAgICAgICAgdGhyb3c6ICgpID0+IG5ldyBVbmRlZmluZWRWYWx1ZVZhbGlkYXRpb25FcnJvcigpLFxuICAgICAgICAgICAgaXNGb3JtYXQ6IHRydWUsXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBwdWJsaWMgYWNjZXB0VW5kZWZpbmVkKCk6IFZhbGlkYXRvcjxUPiB7XG4gICAgICAgIHRoaXMuYWRkU3RlcCh7XG4gICAgICAgICAgICB2ZXJpZnlTdGVwOiAoKSA9PiB0cnVlLFxuICAgICAgICAgICAgdGhyb3c6IG51bGwsXG4gICAgICAgICAgICBpbnRlcnJ1cHQ6IHZhbCA9PiB2YWwgPT09IHVuZGVmaW5lZCB8fCB2YWwgPT09IG51bGwsXG4gICAgICAgICAgICBpc0Zvcm1hdDogdHJ1ZSxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIHB1YmxpYyBlcXVhbHMob3RoZXI/OiBUKTogVmFsaWRhdG9yPFQ+IHtcbiAgICAgICAgdGhpcy5hZGRTdGVwKHtcbiAgICAgICAgICAgIHZlcmlmeVN0ZXA6IHZhbCA9PiB2YWwgPT09IG90aGVyLFxuICAgICAgICAgICAgdGhyb3c6ICgpID0+IG5ldyBCYWRWYWx1ZVZhbGlkYXRpb25FcnJvcihvdGhlciksXG4gICAgICAgICAgICBpc0Zvcm1hdDogdHJ1ZSxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIHB1YmxpYyByZWdleHAocmVnZXhwOiBSZWdFeHApOiBWYWxpZGF0b3I8VD4ge1xuICAgICAgICB0aGlzLnZhbGlkYXRpb25BdHRyaWJ1dGVzLnB1c2goYHBhdHRlcm49XCIke3JlZ2V4cH1cImApO1xuICAgICAgICB0aGlzLmFkZFN0ZXAoe1xuICAgICAgICAgICAgdmVyaWZ5U3RlcDogdmFsID0+IHJlZ2V4cC50ZXN0KDxzdHJpbmc+PHVua25vd24+dmFsKSxcbiAgICAgICAgICAgIHRocm93OiAoKSA9PiBuZXcgSW52YWxpZEZvcm1hdFZhbGlkYXRpb25FcnJvcigpLFxuICAgICAgICAgICAgaXNGb3JtYXQ6IHRydWUsXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBwdWJsaWMgbGVuZ3RoKGxlbmd0aDogbnVtYmVyKTogVmFsaWRhdG9yPFQ+IHtcbiAgICAgICAgdGhpcy5hZGRTdGVwKHtcbiAgICAgICAgICAgIHZlcmlmeVN0ZXA6IHZhbCA9PiAoPGFueT52YWwpLmxlbmd0aCA9PT0gbGVuZ3RoLFxuICAgICAgICAgICAgdGhyb3c6ICgpID0+IG5ldyBCYWRMZW5ndGhWYWxpZGF0aW9uRXJyb3IobGVuZ3RoKSxcbiAgICAgICAgICAgIGlzRm9ybWF0OiB0cnVlLFxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHBhcmFtIG1pbkxlbmd0aCBpbmNsdWRlZFxuICAgICAqIEBwYXJhbSBtYXhMZW5ndGggaW5jbHVkZWRcbiAgICAgKi9cbiAgICBwdWJsaWMgYmV0d2VlbihtaW5MZW5ndGg6IG51bWJlciwgbWF4TGVuZ3RoOiBudW1iZXIpOiBWYWxpZGF0b3I8VD4ge1xuICAgICAgICB0aGlzLmFkZFN0ZXAoe1xuICAgICAgICAgICAgdmVyaWZ5U3RlcDogdmFsID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBsZW5ndGggPSAoPGFueT52YWwpLmxlbmd0aDtcbiAgICAgICAgICAgICAgICByZXR1cm4gbGVuZ3RoID49IG1pbkxlbmd0aCAmJiBsZW5ndGggPD0gbWF4TGVuZ3RoO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHRocm93OiAoKSA9PiBuZXcgQmFkTGVuZ3RoVmFsaWRhdGlvbkVycm9yKG1pbkxlbmd0aCwgbWF4TGVuZ3RoKSxcbiAgICAgICAgICAgIGlzRm9ybWF0OiB0cnVlLFxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHBhcmFtIG1pbiBpbmNsdWRlZFxuICAgICAqL1xuICAgIHB1YmxpYyBtaW4obWluOiBudW1iZXIpOiBWYWxpZGF0b3I8VD4ge1xuICAgICAgICB0aGlzLnZhbGlkYXRpb25BdHRyaWJ1dGVzLnB1c2goYG1pbj1cIiR7bWlufVwiYCk7XG4gICAgICAgIHRoaXMuX21pbiA9IG1pbjtcbiAgICAgICAgdGhpcy5hZGRTdGVwKHtcbiAgICAgICAgICAgIHZlcmlmeVN0ZXA6IHZhbCA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICg8YW55PnZhbCkgPj0gbWluO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHRocm93OiAoKSA9PiBuZXcgT3V0T2ZSYW5nZVZhbGlkYXRpb25FcnJvcih0aGlzLl9taW4sIHRoaXMuX21heCksXG4gICAgICAgICAgICBpc0Zvcm1hdDogdHJ1ZSxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSBtYXggaW5jbHVkZWRcbiAgICAgKi9cbiAgICBwdWJsaWMgbWF4KG1heDogbnVtYmVyKTogVmFsaWRhdG9yPFQ+IHtcbiAgICAgICAgdGhpcy52YWxpZGF0aW9uQXR0cmlidXRlcy5wdXNoKGBtYXg9XCIke21heH1cImApO1xuICAgICAgICB0aGlzLl9tYXggPSBtYXg7XG4gICAgICAgIHRoaXMuYWRkU3RlcCh7XG4gICAgICAgICAgICB2ZXJpZnlTdGVwOiB2YWwgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiAoPGFueT52YWwpIDw9IG1heDtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB0aHJvdzogKCkgPT4gbmV3IE91dE9mUmFuZ2VWYWxpZGF0aW9uRXJyb3IodGhpcy5fbWluLCB0aGlzLl9tYXgpLFxuICAgICAgICAgICAgaXNGb3JtYXQ6IHRydWUsXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBwdWJsaWMgdW5pcXVlKG1vZGVsOiBNb2RlbCwgcXVlcnlTdXBwbGllcj86ICgpID0+IFF1ZXJ5KTogVmFsaWRhdG9yPFQ+IHtcbiAgICAgICAgdGhpcy5hZGRTdGVwKHtcbiAgICAgICAgICAgIHZlcmlmeVN0ZXA6IGFzeW5jICh2YWwsIHRoaW5nTmFtZSwgYykgPT4ge1xuICAgICAgICAgICAgICAgIGxldCBxdWVyeTogUXVlcnk7XG4gICAgICAgICAgICAgICAgaWYgKHF1ZXJ5U3VwcGxpZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgcXVlcnkgPSBxdWVyeVN1cHBsaWVyKCkud2hlcmUodGhpbmdOYW1lLCB2YWwpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHF1ZXJ5ID0gKDxhbnk+bW9kZWwuY29uc3RydWN0b3IpLnNlbGVjdCgnMScpLndoZXJlKHRoaW5nTmFtZSwgdmFsKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBtb2RlbC5pZCA9PT0gJ251bWJlcicpIHF1ZXJ5ID0gcXVlcnkud2hlcmVOb3QoJ2lkJywgbW9kZWwuaWQpO1xuICAgICAgICAgICAgICAgIHJldHVybiAoYXdhaXQgcXVlcnkuZXhlY3V0ZShjKSkucmVzdWx0cy5sZW5ndGggPT09IDA7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgdGhyb3c6ICgpID0+IG5ldyBBbHJlYWR5RXhpc3RzVmFsaWRhdGlvbkVycm9yKG1vZGVsLnRhYmxlKSxcbiAgICAgICAgICAgIGlzRm9ybWF0OiBmYWxzZSxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIHB1YmxpYyBleGlzdHMobW9kZWxDbGFzczogRnVuY3Rpb24sIGZvcmVpZ25LZXk/OiBzdHJpbmcpOiBWYWxpZGF0b3I8VD4ge1xuICAgICAgICB0aGlzLmFkZFN0ZXAoe1xuICAgICAgICAgICAgdmVyaWZ5U3RlcDogYXN5bmMgKHZhbCwgdGhpbmdOYW1lLCBjKSA9PiAoYXdhaXQgKDxhbnk+bW9kZWxDbGFzcykuc2VsZWN0KCcxJykud2hlcmUoZm9yZWlnbktleSAhPT0gdW5kZWZpbmVkID8gZm9yZWlnbktleSA6IHRoaW5nTmFtZSwgdmFsKS5leGVjdXRlKGMpKS5yZXN1bHRzLmxlbmd0aCA+PSAxLFxuICAgICAgICAgICAgdGhyb3c6ICgpID0+IG5ldyBVbmtub3duUmVsYXRpb25WYWxpZGF0aW9uRXJyb3IoKDxhbnk+bW9kZWxDbGFzcykudGFibGUsIGZvcmVpZ25LZXkpLFxuICAgICAgICAgICAgaXNGb3JtYXQ6IGZhbHNlLFxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhZGRTdGVwKHN0ZXA6IFZhbGlkYXRpb25TdGVwPFQ+KSB7XG4gICAgICAgIHRoaXMuc3RlcHMucHVzaChzdGVwKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0VmFsaWRhdGlvbkF0dHJpYnV0ZXMoKTogc3RyaW5nW10ge1xuICAgICAgICByZXR1cm4gdGhpcy52YWxpZGF0aW9uQXR0cmlidXRlcztcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RlcChzdGVwOiBudW1iZXIpOiBWYWxpZGF0b3I8VD4ge1xuICAgICAgICB0aGlzLnZhbGlkYXRpb25BdHRyaWJ1dGVzLnB1c2goYHN0ZXA9XCIke3N0ZXB9XCJgKTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxufVxuXG5pbnRlcmZhY2UgVmFsaWRhdGlvblN0ZXA8VD4ge1xuICAgIGludGVycnVwdD86ICh2YWw/OiBUKSA9PiBib29sZWFuO1xuXG4gICAgdmVyaWZ5U3RlcCh2YWw6IFQgfCB1bmRlZmluZWQsIHRoaW5nTmFtZTogc3RyaW5nLCBjb25uZWN0aW9uPzogQ29ubmVjdGlvbik6IGJvb2xlYW4gfCBQcm9taXNlPGJvb2xlYW4+O1xuXG4gICAgdGhyb3c6ICgodmFsPzogVCkgPT4gVmFsaWRhdGlvbkVycm9yKSB8IG51bGw7XG5cbiAgICByZWFkb25seSBpc0Zvcm1hdDogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGNsYXNzIFZhbGlkYXRpb25CYWcgZXh0ZW5kcyBFcnJvciB7XG4gICAgcHJpdmF0ZSByZWFkb25seSBtZXNzYWdlczogeyBbcDogc3RyaW5nXTogYW55IH0gPSB7fTtcblxuICAgIHB1YmxpYyBhZGRNZXNzYWdlKGVycjogVmFsaWRhdGlvbkVycm9yKSB7XG4gICAgICAgIGlmICghZXJyLnRoaW5nTmFtZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdOdWxsIHRoaW5nIG5hbWUnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMubWVzc2FnZXNbZXJyLnRoaW5nTmFtZV0gPSB7XG4gICAgICAgICAgICBuYW1lOiBlcnIubmFtZSxcbiAgICAgICAgICAgIG1lc3NhZ2U6IGVyci5tZXNzYWdlLFxuICAgICAgICAgICAgdmFsdWU6IGVyci52YWx1ZSxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaGFzTWVzc2FnZXMoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBPYmplY3Qua2V5cyh0aGlzLm1lc3NhZ2VzKS5sZW5ndGggPiAwO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRNZXNzYWdlcygpOiB7IFtwOiBzdHJpbmddOiBWYWxpZGF0aW9uRXJyb3IgfSB7XG4gICAgICAgIHJldHVybiB0aGlzLm1lc3NhZ2VzO1xuICAgIH1cbn1cblxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFZhbGlkYXRpb25FcnJvciBleHRlbmRzIEVycm9yIHtcbiAgICBwdWJsaWMgdGhpbmdOYW1lPzogc3RyaW5nO1xuICAgIHB1YmxpYyB2YWx1ZT86IGFueTtcblxuICAgIHB1YmxpYyBnZXQgbmFtZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5jb25zdHJ1Y3Rvci5uYW1lO1xuICAgIH1cbn1cblxuZXhwb3J0IGNsYXNzIEJhZExlbmd0aFZhbGlkYXRpb25FcnJvciBleHRlbmRzIFZhbGlkYXRpb25FcnJvciB7XG4gICAgcHJpdmF0ZSByZWFkb25seSBleHBlY3RlZExlbmd0aDogbnVtYmVyO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgbWF4TGVuZ3RoPzogbnVtYmVyO1xuXG4gICAgY29uc3RydWN0b3IoZXhwZWN0ZWRMZW5ndGg6IG51bWJlciwgbWF4TGVuZ3RoPzogbnVtYmVyKSB7XG4gICAgICAgIHN1cGVyKCk7XG4gICAgICAgIHRoaXMuZXhwZWN0ZWRMZW5ndGggPSBleHBlY3RlZExlbmd0aDtcbiAgICAgICAgdGhpcy5tYXhMZW5ndGggPSBtYXhMZW5ndGg7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCBtZXNzYWdlKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiBgJHt0aGlzLnRoaW5nTmFtZX0gZXhwZWN0ZWQgbGVuZ3RoOiAke3RoaXMuZXhwZWN0ZWRMZW5ndGh9JHt0aGlzLm1heExlbmd0aCAhPT0gdW5kZWZpbmVkID8gYCB0byAke3RoaXMubWF4TGVuZ3RofWAgOiAnJ307IGAgK1xuICAgICAgICAgICAgYGFjdHVhbCBsZW5ndGg6ICR7dGhpcy52YWx1ZS5sZW5ndGh9LmA7XG4gICAgfVxufVxuXG5leHBvcnQgY2xhc3MgQmFkVmFsdWVWYWxpZGF0aW9uRXJyb3IgZXh0ZW5kcyBWYWxpZGF0aW9uRXJyb3Ige1xuICAgIHByaXZhdGUgcmVhZG9ubHkgZXhwZWN0ZWRWYWx1ZTogYW55O1xuXG4gICAgY29uc3RydWN0b3IoZXhwZWN0ZWRWYWx1ZTogYW55KSB7XG4gICAgICAgIHN1cGVyKCk7XG4gICAgICAgIHRoaXMuZXhwZWN0ZWRWYWx1ZSA9IGV4cGVjdGVkVmFsdWU7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCBtZXNzYWdlKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiBgRXhwZWN0ZWQ6ICR7dGhpcy5leHBlY3RlZFZhbHVlfTsgZ290OiAke3RoaXMudmFsdWV9LmBcbiAgICB9XG59XG5cbmV4cG9ydCBjbGFzcyBPdXRPZlJhbmdlVmFsaWRhdGlvbkVycm9yIGV4dGVuZHMgVmFsaWRhdGlvbkVycm9yIHtcbiAgICBwcml2YXRlIHJlYWRvbmx5IG1pbj86IG51bWJlcjtcbiAgICBwcml2YXRlIHJlYWRvbmx5IG1heD86IG51bWJlcjtcblxuICAgIGNvbnN0cnVjdG9yKG1pbj86IG51bWJlciwgbWF4PzogbnVtYmVyKSB7XG4gICAgICAgIHN1cGVyKCk7XG4gICAgICAgIHRoaXMubWluID0gbWluO1xuICAgICAgICB0aGlzLm1heCA9IG1heDtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IG1lc3NhZ2UoKTogc3RyaW5nIHtcbiAgICAgICAgaWYgKHRoaXMubWluID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHJldHVybiBgJHt0aGlzLnRoaW5nTmFtZX0gbXVzdCBiZSBhdCBtb3N0ICR7dGhpcy5tYXh9YDtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLm1heCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICByZXR1cm4gYCR7dGhpcy50aGluZ05hbWV9IG11c3QgYmUgYXQgbGVhc3QgJHt0aGlzLm1pbn1gO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBgJHt0aGlzLnRoaW5nTmFtZX0gbXVzdCBiZSBiZXR3ZWVuICR7dGhpcy5taW59IGFuZCAke3RoaXMubWF4fS5gO1xuICAgIH1cbn1cblxuZXhwb3J0IGNsYXNzIEludmFsaWRGb3JtYXRWYWxpZGF0aW9uRXJyb3IgZXh0ZW5kcyBWYWxpZGF0aW9uRXJyb3Ige1xuICAgIHB1YmxpYyBnZXQgbWVzc2FnZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gYFwiJHt0aGlzLnZhbHVlfVwiIGlzIG5vdCBhIHZhbGlkICR7dGhpcy50aGluZ05hbWV9LmA7XG4gICAgfVxufVxuXG5leHBvcnQgY2xhc3MgVW5kZWZpbmVkVmFsdWVWYWxpZGF0aW9uRXJyb3IgZXh0ZW5kcyBWYWxpZGF0aW9uRXJyb3Ige1xuICAgIHB1YmxpYyBnZXQgbWVzc2FnZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gYCR7dGhpcy50aGluZ05hbWV9IGlzIHJlcXVpcmVkLmA7XG4gICAgfVxufVxuXG5leHBvcnQgY2xhc3MgQWxyZWFkeUV4aXN0c1ZhbGlkYXRpb25FcnJvciBleHRlbmRzIFZhbGlkYXRpb25FcnJvciB7XG4gICAgcHJpdmF0ZSByZWFkb25seSB0YWJsZTogc3RyaW5nO1xuXG4gICAgY29uc3RydWN0b3IodGFibGU6IHN0cmluZykge1xuICAgICAgICBzdXBlcigpO1xuICAgICAgICB0aGlzLnRhYmxlID0gdGFibGU7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCBtZXNzYWdlKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiBgJHt0aGlzLnZhbHVlfSBhbHJlYWR5IGV4aXN0cyBpbiAke3RoaXMudGFibGV9LiR7dGhpcy50aGluZ05hbWV9LmA7XG4gICAgfVxufVxuXG5leHBvcnQgY2xhc3MgVW5rbm93blJlbGF0aW9uVmFsaWRhdGlvbkVycm9yIGV4dGVuZHMgVmFsaWRhdGlvbkVycm9yIHtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHRhYmxlOiBzdHJpbmc7XG4gICAgcHJpdmF0ZSByZWFkb25seSBmb3JlaWduS2V5Pzogc3RyaW5nO1xuXG4gICAgY29uc3RydWN0b3IodGFibGU6IHN0cmluZywgZm9yZWlnbktleT86IHN0cmluZykge1xuICAgICAgICBzdXBlcigpO1xuICAgICAgICB0aGlzLnRhYmxlID0gdGFibGU7XG4gICAgICAgIHRoaXMuZm9yZWlnbktleSA9IGZvcmVpZ25LZXk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCBtZXNzYWdlKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiBgJHt0aGlzLnRoaW5nTmFtZX09JHt0aGlzLnZhbHVlfSByZWxhdGlvbiB3YXMgbm90IGZvdW5kIGluICR7dGhpcy50YWJsZX0ke3RoaXMuZm9yZWlnbktleSAhPT0gdW5kZWZpbmVkID8gYC4ke3RoaXMuZm9yZWlnbktleX1gIDogJyd9LmA7XG4gICAgfVxufSJdfQ== \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..ad2c08b --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1 @@ +export { default as Application } from "./Application"; diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..a699cc9 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,2 @@ +export { default as Application } from "./Application"; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiLi8iLCJzb3VyY2VzIjpbImluZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBQyxPQUFPLElBQUksV0FBVyxFQUFDLE1BQU0sZUFBZSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IHtkZWZhdWx0IGFzIEFwcGxpY2F0aW9ufSBmcm9tIFwiLi9BcHBsaWNhdGlvblwiOyJdfQ== \ No newline at end of file diff --git a/dist/migrations/CreateLogsTable.d.ts b/dist/migrations/CreateLogsTable.d.ts new file mode 100644 index 0000000..1feed20 --- /dev/null +++ b/dist/migrations/CreateLogsTable.d.ts @@ -0,0 +1,8 @@ +import Migration from "../db/Migration"; +/** + * Must be the first migration + */ +export default class CreateLogsTable extends Migration { + install(): Promise; + rollback(): Promise; +} diff --git a/dist/migrations/CreateLogsTable.js b/dist/migrations/CreateLogsTable.js new file mode 100644 index 0000000..37b968a --- /dev/null +++ b/dist/migrations/CreateLogsTable.js @@ -0,0 +1,37 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import Migration from "../db/Migration"; +import { query } from "../db/MysqlConnectionManager"; +/** + * Must be the first migration + */ +export default class CreateLogsTable extends Migration { + install() { + return __awaiter(this, void 0, void 0, function* () { + yield query('CREATE TABLE logs(' + + 'id INT NOT NULL AUTO_INCREMENT,' + + 'level TINYINT UNSIGNED NOT NULL,' + + 'message TEXT NOT NULL,' + + 'log_id BINARY(16),' + + 'error_name VARCHAR(128),' + + 'error_message VARCHAR(512),' + + 'error_stack TEXT,' + + 'created_at DATETIME NOT NULL DEFAULT NOW(),' + + 'PRIMARY KEY (id)' + + ')'); + }); + } + rollback() { + return __awaiter(this, void 0, void 0, function* () { + yield query('DROP TABLE logs'); + }); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ3JlYXRlTG9nc1RhYmxlLmpzIiwic291cmNlUm9vdCI6Ii4vIiwic291cmNlcyI6WyJtaWdyYXRpb25zL0NyZWF0ZUxvZ3NUYWJsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFBQSxPQUFPLFNBQVMsTUFBTSxpQkFBaUIsQ0FBQztBQUN4QyxPQUFPLEVBQUMsS0FBSyxFQUFDLE1BQU0sOEJBQThCLENBQUM7QUFFbkQ7O0dBRUc7QUFDSCxNQUFNLENBQUMsT0FBTyxPQUFPLGVBQWdCLFNBQVEsU0FBUztJQUM1QyxPQUFPOztZQUNULE1BQU0sS0FBSyxDQUFDLG9CQUFvQjtnQkFDNUIsaUNBQWlDO2dCQUNqQyxrQ0FBa0M7Z0JBQ2xDLHdCQUF3QjtnQkFDeEIsb0JBQW9CO2dCQUNwQiwwQkFBMEI7Z0JBQzFCLDZCQUE2QjtnQkFDN0IsbUJBQW1CO2dCQUNuQiw2Q0FBNkM7Z0JBQzdDLGtCQUFrQjtnQkFDbEIsR0FBRyxDQUFDLENBQUM7UUFDYixDQUFDO0tBQUE7SUFFSyxRQUFROztZQUNWLE1BQU0sS0FBSyxDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFDbkMsQ0FBQztLQUFBO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgTWlncmF0aW9uIGZyb20gXCIuLi9kYi9NaWdyYXRpb25cIjtcbmltcG9ydCB7cXVlcnl9IGZyb20gXCIuLi9kYi9NeXNxbENvbm5lY3Rpb25NYW5hZ2VyXCI7XG5cbi8qKlxuICogTXVzdCBiZSB0aGUgZmlyc3QgbWlncmF0aW9uXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIENyZWF0ZUxvZ3NUYWJsZSBleHRlbmRzIE1pZ3JhdGlvbiB7XG4gICAgYXN5bmMgaW5zdGFsbCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgcXVlcnkoJ0NSRUFURSBUQUJMRSBsb2dzKCcgK1xuICAgICAgICAgICAgJ2lkIElOVCBOT1QgTlVMTCBBVVRPX0lOQ1JFTUVOVCwnICtcbiAgICAgICAgICAgICdsZXZlbCBUSU5ZSU5UIFVOU0lHTkVEIE5PVCBOVUxMLCcgK1xuICAgICAgICAgICAgJ21lc3NhZ2UgVEVYVCBOT1QgTlVMTCwnICtcbiAgICAgICAgICAgICdsb2dfaWQgQklOQVJZKDE2KSwnICtcbiAgICAgICAgICAgICdlcnJvcl9uYW1lIFZBUkNIQVIoMTI4KSwnICtcbiAgICAgICAgICAgICdlcnJvcl9tZXNzYWdlIFZBUkNIQVIoNTEyKSwnICtcbiAgICAgICAgICAgICdlcnJvcl9zdGFjayBURVhULCcgK1xuICAgICAgICAgICAgJ2NyZWF0ZWRfYXQgREFURVRJTUUgTk9UIE5VTEwgREVGQVVMVCBOT1coKSwnICtcbiAgICAgICAgICAgICdQUklNQVJZIEtFWSAoaWQpJyArXG4gICAgICAgICAgICAnKScpO1xuICAgIH1cblxuICAgIGFzeW5jIHJvbGxiYWNrKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCBxdWVyeSgnRFJPUCBUQUJMRSBsb2dzJyk7XG4gICAgfVxufSJdfQ== \ No newline at end of file diff --git a/dist/migrations/CreateMigrationsTable.d.ts b/dist/migrations/CreateMigrationsTable.d.ts new file mode 100644 index 0000000..9d00a58 --- /dev/null +++ b/dist/migrations/CreateMigrationsTable.d.ts @@ -0,0 +1,9 @@ +import Migration from "../db/Migration"; +/** + * Must be the first migration + */ +export default class CreateMigrationsTable extends Migration { + shouldRun(currentVersion: number): Promise; + install(): Promise; + rollback(): Promise; +} diff --git a/dist/migrations/CreateMigrationsTable.js b/dist/migrations/CreateMigrationsTable.js new file mode 100644 index 0000000..cda8f45 --- /dev/null +++ b/dist/migrations/CreateMigrationsTable.js @@ -0,0 +1,48 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import Migration from "../db/Migration"; +import { query } from "../db/MysqlConnectionManager"; +/** + * Must be the first migration + */ +export default class CreateMigrationsTable extends Migration { + shouldRun(currentVersion) { + const _super = Object.create(null, { + shouldRun: { get: () => super.shouldRun } + }); + return __awaiter(this, void 0, void 0, function* () { + try { + yield query('SELECT 1 FROM migrations LIMIT 1'); + } + catch (e) { + if (e.code !== 'ER_NO_SUCH_TABLE') { + return false; + } + } + return yield _super.shouldRun.call(this, currentVersion); + }); + } + install() { + return __awaiter(this, void 0, void 0, function* () { + yield query('CREATE TABLE migrations(' + + 'id INT NOT NULL,' + + 'name VARCHAR(64) NOT NULL,' + + 'migration_date DATE,' + + 'PRIMARY KEY (id)' + + ')'); + }); + } + rollback() { + return __awaiter(this, void 0, void 0, function* () { + yield query('DROP TABLE migrations'); + }); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ3JlYXRlTWlncmF0aW9uc1RhYmxlLmpzIiwic291cmNlUm9vdCI6Ii4vIiwic291cmNlcyI6WyJtaWdyYXRpb25zL0NyZWF0ZU1pZ3JhdGlvbnNUYWJsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFBQSxPQUFPLFNBQVMsTUFBTSxpQkFBaUIsQ0FBQztBQUN4QyxPQUFPLEVBQUMsS0FBSyxFQUFDLE1BQU0sOEJBQThCLENBQUM7QUFFbkQ7O0dBRUc7QUFDSCxNQUFNLENBQUMsT0FBTyxPQUFPLHFCQUFzQixTQUFRLFNBQVM7SUFDbEQsU0FBUyxDQUFDLGNBQXNCOzs7OztZQUNsQyxJQUFJO2dCQUNBLE1BQU0sS0FBSyxDQUFDLGtDQUFrQyxDQUFDLENBQUM7YUFDbkQ7WUFBQyxPQUFPLENBQUMsRUFBRTtnQkFDUixJQUFJLENBQUMsQ0FBQyxJQUFJLEtBQUssa0JBQWtCLEVBQUU7b0JBQy9CLE9BQU8sS0FBSyxDQUFDO2lCQUNoQjthQUNKO1lBRUQsT0FBTyxNQUFNLE9BQU0sU0FBUyxZQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ2pELENBQUM7S0FBQTtJQUVLLE9BQU87O1lBQ1QsTUFBTSxLQUFLLENBQUMsMEJBQTBCO2dCQUNsQyxrQkFBa0I7Z0JBQ2xCLDRCQUE0QjtnQkFDNUIsc0JBQXNCO2dCQUN0QixrQkFBa0I7Z0JBQ2xCLEdBQUcsQ0FBQyxDQUFDO1FBQ2IsQ0FBQztLQUFBO0lBRUssUUFBUTs7WUFDVixNQUFNLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO1FBQ3pDLENBQUM7S0FBQTtDQUNKIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IE1pZ3JhdGlvbiBmcm9tIFwiLi4vZGIvTWlncmF0aW9uXCI7XG5pbXBvcnQge3F1ZXJ5fSBmcm9tIFwiLi4vZGIvTXlzcWxDb25uZWN0aW9uTWFuYWdlclwiO1xuXG4vKipcbiAqIE11c3QgYmUgdGhlIGZpcnN0IG1pZ3JhdGlvblxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBDcmVhdGVNaWdyYXRpb25zVGFibGUgZXh0ZW5kcyBNaWdyYXRpb24ge1xuICAgIGFzeW5jIHNob3VsZFJ1bihjdXJyZW50VmVyc2lvbjogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBxdWVyeSgnU0VMRUNUIDEgRlJPTSBtaWdyYXRpb25zIExJTUlUIDEnKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgaWYgKGUuY29kZSAhPT0gJ0VSX05PX1NVQ0hfVEFCTEUnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGF3YWl0IHN1cGVyLnNob3VsZFJ1bihjdXJyZW50VmVyc2lvbik7XG4gICAgfVxuXG4gICAgYXN5bmMgaW5zdGFsbCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgcXVlcnkoJ0NSRUFURSBUQUJMRSBtaWdyYXRpb25zKCcgK1xuICAgICAgICAgICAgJ2lkIElOVCBOT1QgTlVMTCwnICtcbiAgICAgICAgICAgICduYW1lIFZBUkNIQVIoNjQpIE5PVCBOVUxMLCcgK1xuICAgICAgICAgICAgJ21pZ3JhdGlvbl9kYXRlIERBVEUsJyArXG4gICAgICAgICAgICAnUFJJTUFSWSBLRVkgKGlkKScgK1xuICAgICAgICAgICAgJyknKTtcbiAgICB9XG5cbiAgICBhc3luYyByb2xsYmFjaygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgcXVlcnkoJ0RST1AgVEFCTEUgbWlncmF0aW9ucycpO1xuICAgIH1cbn0iXX0= \ No newline at end of file diff --git a/dist/models/Log.d.ts b/dist/models/Log.d.ts new file mode 100644 index 0000000..46553bf --- /dev/null +++ b/dist/models/Log.d.ts @@ -0,0 +1,21 @@ +/// +import Model from "../db/Model"; +import { LogLevelKeys } from "../Logger"; +export default class Log extends Model { + private level?; + message?: string; + private log_id?; + private error_name?; + private error_message?; + private error_stack?; + private created_at?; + protected defineProperties(): void; + getLevel(): LogLevelKeys; + setLevel(level: LogLevelKeys): void; + getLogID(): string | null; + setLogID(buffer: Buffer): void; + getErrorName(): string; + getErrorMessage(): string; + getErrorStack(): string; + setError(error?: Error): void; +} diff --git a/dist/models/Log.js b/dist/models/Log.js new file mode 100644 index 0000000..e1929e2 --- /dev/null +++ b/dist/models/Log.js @@ -0,0 +1,56 @@ +import Model from "../db/Model"; +import { LogLevel } from "../Logger"; +import Validator from "../db/Validator"; +export default class Log extends Model { + defineProperties() { + this.defineProperty('level', new Validator().defined()); + this.defineProperty('message', new Validator().defined().between(0, 65535)); + this.defineProperty('log_id', new Validator().acceptUndefined().length(16)); + this.defineProperty('error_name', new Validator().acceptUndefined().between(0, 128)); + this.defineProperty('error_message', new Validator().acceptUndefined().between(0, 512)); + this.defineProperty('error_stack', new Validator().acceptUndefined().between(0, 65535)); + this.defineProperty('created_at', new Validator()); + } + getLevel() { + if (typeof this.level !== 'number') + return 'ERROR'; + return LogLevel[this.level]; + } + setLevel(level) { + this.level = LogLevel[level]; + } + getLogID() { + if (!this.log_id) + return null; + const chars = this.log_id.toString('hex'); + let out = ''; + let i = 0; + for (const l of [8, 4, 4, 4, 12]) { + if (i > 0) + out += '-'; + out += chars.substr(i, l); + i += l; + } + return out; + } + setLogID(buffer) { + this.log_id = buffer; + } + getErrorName() { + return this.error_name || ''; + } + getErrorMessage() { + return this.error_message || ''; + } + getErrorStack() { + return this.error_stack || ''; + } + setError(error) { + if (!error) + return; + this.error_name = error.name; + this.error_message = error.message; + this.error_stack = error.stack; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTG9nLmpzIiwic291cmNlUm9vdCI6Ii4vIiwic291cmNlcyI6WyJtb2RlbHMvTG9nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxNQUFNLGFBQWEsQ0FBQztBQUNoQyxPQUFPLEVBQUMsUUFBUSxFQUFlLE1BQU0sV0FBVyxDQUFDO0FBQ2pELE9BQU8sU0FBUyxNQUFNLGlCQUFpQixDQUFDO0FBRXhDLE1BQU0sQ0FBQyxPQUFPLE9BQU8sR0FBSSxTQUFRLEtBQUs7SUFTeEIsZ0JBQWdCO1FBQ3RCLElBQUksQ0FBQyxjQUFjLENBQVMsT0FBTyxFQUFFLElBQUksU0FBUyxFQUFVLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUN4RSxJQUFJLENBQUMsY0FBYyxDQUFTLFNBQVMsRUFBRSxJQUFJLFNBQVMsRUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUM1RixJQUFJLENBQUMsY0FBYyxDQUFTLFFBQVEsRUFBRSxJQUFJLFNBQVMsRUFBVSxDQUFDLGVBQWUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzVGLElBQUksQ0FBQyxjQUFjLENBQVMsWUFBWSxFQUFFLElBQUksU0FBUyxFQUFVLENBQUMsZUFBZSxFQUFFLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ3JHLElBQUksQ0FBQyxjQUFjLENBQVMsZUFBZSxFQUFFLElBQUksU0FBUyxFQUFVLENBQUMsZUFBZSxFQUFFLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ3hHLElBQUksQ0FBQyxjQUFjLENBQVMsYUFBYSxFQUFFLElBQUksU0FBUyxFQUFVLENBQUMsZUFBZSxFQUFFLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQ3hHLElBQUksQ0FBQyxjQUFjLENBQU8sWUFBWSxFQUFFLElBQUksU0FBUyxFQUFRLENBQUMsQ0FBQztJQUNuRSxDQUFDO0lBRU0sUUFBUTtRQUNYLElBQUksT0FBTyxJQUFJLENBQUMsS0FBSyxLQUFLLFFBQVE7WUFBRSxPQUFPLE9BQU8sQ0FBQztRQUNuRCxPQUFxQixRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzlDLENBQUM7SUFFTSxRQUFRLENBQUMsS0FBbUI7UUFDL0IsSUFBSSxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDakMsQ0FBQztJQUVNLFFBQVE7UUFDWCxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU07WUFBRSxPQUFPLElBQUksQ0FBQztRQUM5QixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMzQyxJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUM7UUFDYixJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDVixLQUFLLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxFQUFFO1lBQzlCLElBQUksQ0FBQyxHQUFHLENBQUM7Z0JBQUUsR0FBRyxJQUFJLEdBQUcsQ0FBQztZQUN0QixHQUFHLElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDMUIsQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUNWO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDZixDQUFDO0lBRU0sUUFBUSxDQUFDLE1BQWM7UUFDMUIsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7SUFDekIsQ0FBQztJQUVNLFlBQVk7UUFDZixPQUFPLElBQUksQ0FBQyxVQUFVLElBQUksRUFBRSxDQUFDO0lBQ2pDLENBQUM7SUFFTSxlQUFlO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLGFBQWEsSUFBSSxFQUFFLENBQUM7SUFDcEMsQ0FBQztJQUVNLGFBQWE7UUFDaEIsT0FBTyxJQUFJLENBQUMsV0FBVyxJQUFJLEVBQUUsQ0FBQztJQUNsQyxDQUFDO0lBRU0sUUFBUSxDQUFDLEtBQWE7UUFDekIsSUFBSSxDQUFDLEtBQUs7WUFBRSxPQUFPO1FBRW5CLElBQUksQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQztRQUM3QixJQUFJLENBQUMsYUFBYSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUM7UUFDbkMsSUFBSSxDQUFDLFdBQVcsR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO0lBQ25DLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBNb2RlbCBmcm9tIFwiLi4vZGIvTW9kZWxcIjtcbmltcG9ydCB7TG9nTGV2ZWwsIExvZ0xldmVsS2V5c30gZnJvbSBcIi4uL0xvZ2dlclwiO1xuaW1wb3J0IFZhbGlkYXRvciBmcm9tIFwiLi4vZGIvVmFsaWRhdG9yXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIExvZyBleHRlbmRzIE1vZGVsIHtcbiAgICBwcml2YXRlIGxldmVsPzogbnVtYmVyO1xuICAgIHB1YmxpYyBtZXNzYWdlPzogc3RyaW5nO1xuICAgIHByaXZhdGUgbG9nX2lkPzogQnVmZmVyO1xuICAgIHByaXZhdGUgZXJyb3JfbmFtZT86IHN0cmluZztcbiAgICBwcml2YXRlIGVycm9yX21lc3NhZ2U/OiBzdHJpbmc7XG4gICAgcHJpdmF0ZSBlcnJvcl9zdGFjaz86IHN0cmluZztcbiAgICBwcml2YXRlIGNyZWF0ZWRfYXQ/OiBEYXRlO1xuXG4gICAgcHJvdGVjdGVkIGRlZmluZVByb3BlcnRpZXMoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZGVmaW5lUHJvcGVydHk8bnVtYmVyPignbGV2ZWwnLCBuZXcgVmFsaWRhdG9yPG51bWJlcj4oKS5kZWZpbmVkKCkpO1xuICAgICAgICB0aGlzLmRlZmluZVByb3BlcnR5PHN0cmluZz4oJ21lc3NhZ2UnLCBuZXcgVmFsaWRhdG9yPHN0cmluZz4oKS5kZWZpbmVkKCkuYmV0d2VlbigwLCA2NTUzNSkpO1xuICAgICAgICB0aGlzLmRlZmluZVByb3BlcnR5PEJ1ZmZlcj4oJ2xvZ19pZCcsIG5ldyBWYWxpZGF0b3I8QnVmZmVyPigpLmFjY2VwdFVuZGVmaW5lZCgpLmxlbmd0aCgxNikpO1xuICAgICAgICB0aGlzLmRlZmluZVByb3BlcnR5PHN0cmluZz4oJ2Vycm9yX25hbWUnLCBuZXcgVmFsaWRhdG9yPHN0cmluZz4oKS5hY2NlcHRVbmRlZmluZWQoKS5iZXR3ZWVuKDAsIDEyOCkpO1xuICAgICAgICB0aGlzLmRlZmluZVByb3BlcnR5PHN0cmluZz4oJ2Vycm9yX21lc3NhZ2UnLCBuZXcgVmFsaWRhdG9yPHN0cmluZz4oKS5hY2NlcHRVbmRlZmluZWQoKS5iZXR3ZWVuKDAsIDUxMikpO1xuICAgICAgICB0aGlzLmRlZmluZVByb3BlcnR5PHN0cmluZz4oJ2Vycm9yX3N0YWNrJywgbmV3IFZhbGlkYXRvcjxzdHJpbmc+KCkuYWNjZXB0VW5kZWZpbmVkKCkuYmV0d2VlbigwLCA2NTUzNSkpO1xuICAgICAgICB0aGlzLmRlZmluZVByb3BlcnR5PERhdGU+KCdjcmVhdGVkX2F0JywgbmV3IFZhbGlkYXRvcjxEYXRlPigpKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0TGV2ZWwoKTogTG9nTGV2ZWxLZXlzIHtcbiAgICAgICAgaWYgKHR5cGVvZiB0aGlzLmxldmVsICE9PSAnbnVtYmVyJykgcmV0dXJuICdFUlJPUic7XG4gICAgICAgIHJldHVybiA8TG9nTGV2ZWxLZXlzPkxvZ0xldmVsW3RoaXMubGV2ZWxdO1xuICAgIH1cblxuICAgIHB1YmxpYyBzZXRMZXZlbChsZXZlbDogTG9nTGV2ZWxLZXlzKSB7XG4gICAgICAgIHRoaXMubGV2ZWwgPSBMb2dMZXZlbFtsZXZlbF07XG4gICAgfVxuXG4gICAgcHVibGljIGdldExvZ0lEKCk6IHN0cmluZyB8IG51bGwge1xuICAgICAgICBpZiAoIXRoaXMubG9nX2lkKSByZXR1cm4gbnVsbDtcbiAgICAgICAgY29uc3QgY2hhcnMgPSB0aGlzLmxvZ19pZCEudG9TdHJpbmcoJ2hleCcpO1xuICAgICAgICBsZXQgb3V0ID0gJyc7XG4gICAgICAgIGxldCBpID0gMDtcbiAgICAgICAgZm9yIChjb25zdCBsIG9mIFs4LCA0LCA0LCA0LCAxMl0pIHtcbiAgICAgICAgICAgIGlmIChpID4gMCkgb3V0ICs9ICctJztcbiAgICAgICAgICAgIG91dCArPSBjaGFycy5zdWJzdHIoaSwgbCk7XG4gICAgICAgICAgICBpICs9IGw7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG91dDtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2V0TG9nSUQoYnVmZmVyOiBCdWZmZXIpIHtcbiAgICAgICAgdGhpcy5sb2dfaWQgPSBidWZmZXI7XG4gICAgfVxuXG4gICAgcHVibGljIGdldEVycm9yTmFtZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5lcnJvcl9uYW1lIHx8ICcnO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRFcnJvck1lc3NhZ2UoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZXJyb3JfbWVzc2FnZSB8fCAnJztcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0RXJyb3JTdGFjaygpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5lcnJvcl9zdGFjayB8fCAnJztcbiAgICB9XG5cbiAgICBwdWJsaWMgc2V0RXJyb3IoZXJyb3I/OiBFcnJvcikge1xuICAgICAgICBpZiAoIWVycm9yKSByZXR1cm47XG5cbiAgICAgICAgdGhpcy5lcnJvcl9uYW1lID0gZXJyb3IubmFtZTtcbiAgICAgICAgdGhpcy5lcnJvcl9tZXNzYWdlID0gZXJyb3IubWVzc2FnZTtcbiAgICAgICAgdGhpcy5lcnJvcl9zdGFjayA9IGVycm9yLnN0YWNrO1xuICAgIH1cbn1cbiJdfQ== \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..eacf4c9 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "wms-core", + "version": "0.1.0", + "description": "Node web framework", + "repository": "git@gitlab.com:ArisuOngaku/wms-core.git", + "author": "Alice Gaudon ", + "license": "MIT", + "private": true, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "prepublishOnly": "yarn build" + }, + "devDependencies": { + "typescript": "^3.8.3" + }, + "dependencies": { + "@types/express": "^4.17.6", + "express": "^4.17.1", + "ws": "^7.2.3" + } +} diff --git a/src/Application.ts b/src/Application.ts new file mode 100644 index 0000000..518327a --- /dev/null +++ b/src/Application.ts @@ -0,0 +1,157 @@ +import express, {NextFunction, Request, Response, Router} from 'express'; +import { + BadRequestError, + HttpError, + NotFoundHttpError, + ServerError, + ServiceUnavailableHttpError +} from "./HttpError"; +import {lib} from "nunjucks"; +import Logger from "./Logger"; +import WebSocketListener from "./WebSocketListener"; +import ApplicationComponent from "./ApplicationComponent"; +import TemplateError = lib.TemplateError; +import Controller from "./Controller"; + +export default abstract class Application { + private readonly version: string; + private readonly controllers: Controller[] = []; + private readonly webSocketListeners: { [p: string]: WebSocketListener } = {}; + private readonly components: ApplicationComponent[] = []; + + private ready: boolean = false; + + protected constructor(version: string) { + this.version = version; + } + + protected abstract async init(): Promise; + + protected use(thing: Controller | WebSocketListener | ApplicationComponent) { + if (thing instanceof Controller) { + this.controllers.push(thing); + } else if (thing instanceof WebSocketListener) { + const path = thing.path(); + this.webSocketListeners[path] = thing; + Logger.info(`Added websocket listener on ${path}`); + } else { + this.components.push(thing); + } + } + + public async start(): Promise { + Logger.info(`${this.constructor.name} v${this.version} - hi`); + process.once('SIGINT', () => { + this.stop().catch(console.error); + }); + + // Register all components and alike + await this.init(); + + // Init express + const app = express(); + const router = express.Router({}); + app.use(router); + + // Error handler + app.use((err: any, req: Request, res: Response, next: NextFunction) => { + if (res.headersSent) { + return next(err); + } + + let errorID: string; + + let logStr = `${req.method} ${req.originalUrl} - `; + if (err instanceof BadRequestError || err instanceof ServiceUnavailableHttpError) { + logStr += `${err.errorCode} ${err.name}`; + errorID = Logger.silentError(err, logStr); + } else { + errorID = Logger.error(err, logStr + `500 Internal Error`, err); + } + + let httpError: HttpError; + + if (err instanceof HttpError) { + httpError = err; + } else if (err instanceof TemplateError && err.cause instanceof HttpError) { + httpError = err.cause; + } else { + httpError = new ServerError('Internal server error.', err); + } + + res.status(httpError.errorCode); + res.format({ + html: () => { + res.render('errors/' + httpError.errorCode + '.njk', { + error_code: httpError.errorCode, + error_message: httpError.message, + error_instructions: httpError.instructions, + error_id: errorID, + }); + }, + json: () => { + res.json({ + status: 'error', + code: httpError.errorCode, + message: httpError.message, + instructions: httpError.instructions, + error_id: errorID, + }); + }, + default: () => { + res.type('txt').send(`${httpError.errorCode} - ${httpError.message}\n\n${httpError.instructions}\n\nError ID: ${errorID}`); + } + }); + }); + + // Start all components + for (const component of this.components) { + await component.start(app, router); + } + + // Routes + this.routes(router); + + this.ready = true; + } + + async stop(): Promise { + Logger.info('Stopping application...'); + + for (const component of this.components) { + await component.stop(); + } + + Logger.info(`${this.constructor.name} v${this.version} - bye`); + } + + private routes(rootRouter: Router) { + for (const controller of this.controllers) { + if (controller.hasGlobalHandlers()) { + controller.setupGlobalHandlers(rootRouter); + + Logger.info(`Registered global middlewares for controller ${controller.constructor.name}`); + } + } + + for (const controller of this.controllers) { + const router = express.Router(); + controller.setupRoutes(router); + rootRouter.use(controller.getRoutesPrefix(), router); + + Logger.info(`> Registered routes for controller ${controller.constructor.name}`); + } + + rootRouter.use((req: Request) => { + throw new NotFoundHttpError('page', req.originalUrl); + }); + } + + public getWebSocketListeners(): { [p: string]: WebSocketListener } { + return this.webSocketListeners; + } + + public isReady(): boolean { + return this.ready; + } +} \ No newline at end of file diff --git a/src/ApplicationComponent.ts b/src/ApplicationComponent.ts new file mode 100644 index 0000000..183303e --- /dev/null +++ b/src/ApplicationComponent.ts @@ -0,0 +1,48 @@ +import {Express, Router} from "express"; +import Logger from "./Logger"; +import {sleep} from "./Utils"; + +export default abstract class ApplicationComponent { + private val?: T; + + public abstract async start(app: Express, router: Router): Promise; + + public abstract async stop(): Promise; + + protected export(val: T) { + this.val = val; + } + + public import(): T { + if (!this.val) throw 'Cannot import if nothing was exported.'; + return this.val; + } + + protected async prepare(name: string, prepare: () => Promise): Promise { + let err; + do { + try { + await prepare(); + err = null; + } catch (e) { + err = e; + Logger.error(err, `${name} failed to prepare; retrying in 5s...`) + await sleep(5000); + } + } while (err); + Logger.info(`${name} ready!`); + } + + protected async close(thingName: string, thing: any, fn: Function): Promise { + try { + await new Promise((resolve, reject) => fn.call(thing, (err: any) => { + if (err) reject(err); + else resolve(); + })); + + Logger.info(`${thingName} closed.`); + } catch (e) { + Logger.error(e, `An error occurred while closing the ${thingName}.`); + } + } +} \ No newline at end of file diff --git a/src/Controller.ts b/src/Controller.ts new file mode 100644 index 0000000..9304438 --- /dev/null +++ b/src/Controller.ts @@ -0,0 +1,120 @@ +import {RequestHandler, Router} from "express"; +import {PathParams} from "express-serve-static-core"; +import config from "config"; +import Logger from "./Logger"; + +export default abstract class Controller { + private static readonly routes: { [p: string]: string } = {}; + + public static route(route: string, params: RouteParams = [], absolute: boolean = false): string { + let path = this.routes[route]; + if (path === undefined) throw new Error(`Unknown route for name ${route}.`); + + if (typeof params === 'string' || typeof params === 'number') { + path = path.replace(/:[a-zA-Z_-]+\??/, '' + params); + } else if (Array.isArray(params)) { + let i = 0; + for (const match of path.matchAll(/:[a-zA-Z_-]+\??/)) { + if (match.length > 0) { + path = path.replace(match[0], typeof params[i] !== 'undefined' ? params[i] : ''); + } + i++; + } + path = path.replace(/\/+/, '/'); + } else { + for (const key in params) { + if (params.hasOwnProperty(key)) { + path = path.replace(new RegExp(`:${key}\\??`), params[key]); + } + } + } + + return `${absolute ? config.get('public_url') : ''}${path}`; + } + + private router?: Router; + + public getGlobalHandlers(): RequestHandler[] { + return []; + } + + public hasGlobalHandlers(): boolean { + return this.getGlobalHandlers().length > 0; + } + + public setupGlobalHandlers(router: Router): void { + for (const globalHandler of this.getGlobalHandlers()) { + router.use(this.wrap(globalHandler)); + } + } + + public getRoutesPrefix(): string { + return '/'; + } + + public abstract routes(): void; + + public setupRoutes(router: Router): void { + this.router = router; + this.routes(); + } + + protected use(handler: RequestHandler) { + this.router?.use(this.wrap(handler)); + } + + protected get(path: PathParams, handler: RequestHandler, routeName?: string, ...middlewares: RequestHandler[]) { + this.registerRoutes(path, handler, routeName); + for (const middleware of middlewares) { + this.router?.get(path, this.wrap(middleware)); + } + this.router?.get(path, this.wrap(handler)); + } + + protected post(path: PathParams, handler: RequestHandler, routeName?: string, ...middlewares: RequestHandler[]) { + this.registerRoutes(path, handler, routeName); + for (const middleware of middlewares) { + this.router?.post(path, this.wrap(middleware)); + } + this.router?.post(path, this.wrap(handler)); + } + + private wrap(handler: RequestHandler): RequestHandler { + return (req, res, next) => { + const promise = handler.call(this, req, res, next); + if (promise instanceof Promise) { + promise.catch(err => next(err)); + } + }; + } + + private registerRoutes(path: PathParams, handler: RequestHandler, routeName?: string) { + if (typeof routeName !== 'string') { + routeName = handler.name + .replace(/(?:^|\.?)([A-Z])/g, (x, y) => '_' + y.toLowerCase()) + .replace(/(^_|get_|post_)/g, ''); + } + + if (routeName.length === 0) return; + + let routePath = null; + if (path instanceof Array && path.length > 0) { + path = path[0]; + } + if (typeof path === 'string') { + const prefix = this.getRoutesPrefix(); + routePath = (prefix !== '/' ? prefix : '') + path; + } + + if (!Controller.routes[routeName]) { + if (typeof routePath === 'string') { + Logger.info(`Route ${routeName} has path ${routePath}`); + Controller.routes[routeName] = routePath; + } else { + Logger.warn(`Cannot assign path to route ${routeName}.`); + } + } + } +} + +export type RouteParams = { [p: string]: string } | string[] | string | number; \ No newline at end of file diff --git a/src/HttpError.ts b/src/HttpError.ts new file mode 100644 index 0000000..de03928 --- /dev/null +++ b/src/HttpError.ts @@ -0,0 +1,79 @@ +import {WrappingError} from "./Utils"; + +export abstract class HttpError extends WrappingError { + public readonly instructions: string; + + constructor(message: string, instructions: string, cause?: Error) { + super(message, cause); + this.instructions = instructions; + } + + get name(): string { + return this.constructor.name; + } + + abstract get errorCode(): number; +} + +export class BadRequestError extends HttpError { + public readonly url: string; + + constructor(message: string, instructions: string, url: string, cause?: Error) { + super(message, instructions, cause); + this.url = url; + } + + get errorCode(): number { + return 400; + } +} + +export class ForbiddenHttpError extends BadRequestError { + constructor(thing: string, url: string, cause?: Error) { + super( + `You don't have access to this ${thing}.`, + `${url} doesn't belong to *you*.`, + url, + cause + ); + } + + get errorCode(): number { + return 403; + } +} + +export class NotFoundHttpError extends BadRequestError { + constructor(thing: string, url: string, cause?: Error) { + super( + `${thing.charAt(0).toUpperCase()}${thing.substr(1)} not found.`, + `${url} doesn't exist or was deleted.`, + url, + cause + ); + } + + get errorCode(): number { + return 404; + } +} + +export class ServerError extends HttpError { + constructor(message: string, cause?: Error) { + super(message, `Maybe you should contact us; see instructions below.`, cause); + } + + get errorCode(): number { + return 500; + } +} + +export class ServiceUnavailableHttpError extends ServerError { + constructor(message: string, cause?: Error) { + super(message, cause); + } + + get errorCode(): number { + return 503; + } +} \ No newline at end of file diff --git a/src/Logger.ts b/src/Logger.ts new file mode 100644 index 0000000..9736e21 --- /dev/null +++ b/src/Logger.ts @@ -0,0 +1,121 @@ +import config from "config"; +import {v4 as uuid} from "uuid"; +import Log from "./models/Log"; + +const LOG_LEVEL: LogLevelKeys = config.get('log_level'); +const DB_LOG_LEVEL: LogLevelKeys = config.get('db_log_level'); + +export default class Logger { + public static silentError(error: Error, ...message: any[]): string { + return this.log('ERROR', message, error, true) || ''; + } + + public static error(error: Error, ...message: any[]): string { + return this.log('ERROR', message, error) || ''; + } + + public static warn(...message: any[]) { + this.log('WARN', message); + } + + public static info(...message: any[]) { + this.log('INFO', message); + } + + public static debug(...message: any[]) { + this.log('DEBUG', message); + } + + public static dev(...message: any[]) { + this.log('DEV', message); + } + + private static log(level: LogLevelKeys, message: any[], error?: Error, silent: boolean = false): string | null { + const levelIndex = LogLevel[level]; + if (levelIndex <= LogLevel[LOG_LEVEL]) { + if (error) { + if (levelIndex > LogLevel.ERROR) this.warn(`Wrong log level ${level} with attached error.`); + } else { + if (levelIndex <= LogLevel.ERROR) this.warn(`No error attached with log level ${level}.`); + } + + const computedMsg = message.map(v => { + if (typeof v === 'string') { + return v; + } else { + return JSON.stringify(v, (key: string, value: any) => { + if (value instanceof Object) { + if (value.type === 'Buffer') { + return `Buffer<${Buffer.from(value.data).toString('hex')}>`; + } else if (value !== v) { + return `[object Object]`; + } + } + if (typeof value === 'string' && value.length > 96) { + return value.substr(0, 96) + '...'; + } + return value; + }, 4); + } + }).join(' '); + + const log = new Log({}); + log.setLevel(level); + log.message = computedMsg; + log.setError(error); + + let logID = Buffer.alloc(16); + uuid({}, logID); + log.setLogID(logID); + + + let output = `[${level}] `; + let pad = output.length; + if (levelIndex <= LogLevel[DB_LOG_LEVEL]) output += `${log.getLogID()} - `; + output += computedMsg.replace(/\n/g, '\n' + ' '.repeat(pad)); + + switch (level) { + case "ERROR": + if (silent || !error) { + console.error(output); + } else { + console.error(output, error); + } + break; + case "WARN": + console.warn(output); + break; + case "INFO": + console.info(output); + break; + case "DEBUG": + case "DEV": + console.debug(output); + break; + } + + if (levelIndex <= LogLevel[DB_LOG_LEVEL]) { + log.save().catch(err => { + if (!silent && err.message.indexOf('ECONNREFUSED') < 0) { + console.error({save_err: err, error}); + } + }); + } + return log.getLogID(); + } + return null; + } + + private constructor() { + } +} + +export enum LogLevel { + ERROR, + WARN, + INFO, + DEBUG, + DEV, +} + +export type LogLevelKeys = keyof typeof LogLevel; diff --git a/src/Mail.ts b/src/Mail.ts new file mode 100644 index 0000000..3ce28e0 --- /dev/null +++ b/src/Mail.ts @@ -0,0 +1,139 @@ +import nodemailer, {SentMessageInfo, Transporter} from "nodemailer"; +import config from "config"; +import {Options} from "nodemailer/lib/mailer"; +import nunjucks from 'nunjucks'; +import * as util from "util"; +import {WrappingError} from "./Utils"; +import mjml2html from "mjml"; +import * as querystring from "querystring"; +import Logger from "./Logger"; + +export function mailRoute(template: string): string { + return `/mail/${template}`; +} + +export default class Mail { + private static transporter: Transporter; + + private static getTransporter(): Transporter { + if (!this.transporter) throw new MailError('Mail system was not prepared.'); + return this.transporter; + } + + public static async prepare(): Promise { + const transporter = nodemailer.createTransport({ + host: config.get('mail.host'), + port: config.get('mail.port'), + secure: config.get('mail.secure'), + auth: { + user: config.get('mail.username'), + pass: config.get('mail.password'), + }, + tls: { + rejectUnauthorized: !config.get('mail.allow_invalid_tls') + } + }); + + try { + await util.promisify(transporter.verify)(); + this.transporter = transporter; + } catch (e) { + throw new MailError('Connection to mail service unsuccessful.', e); + } + + Logger.info(`Mail ready to be distributed via ${config.get('mail.host')}:${config.get('mail.port')}`); + } + + public static end() { + this.transporter.close(); + } + + public static parse(template: string, data: any, textOnly: boolean): string { + data.text = textOnly; + const nunjucksResult = nunjucks.render(template, data); + if (textOnly) return nunjucksResult; + + const mjmlResult = mjml2html(nunjucksResult, {}); + + if (mjmlResult.errors.length > 0) { + throw new MailError(`Error while parsing mail template ${template}: ${JSON.stringify(mjmlResult.errors, null, 4)}`); + } + + return mjmlResult.html; + } + + private readonly template: MailTemplate; + private readonly options: Options = {}; + private readonly data: { [p: string]: any }; + + constructor(template: MailTemplate, data: { [p: string]: any } = {}) { + this.template = template; + this.data = data; + this.options.subject = this.template.getSubject(data); + + this.verifyData(); + } + + private verifyData() { + for (const forbiddenField of [ + 'to', + ]) { + if (this.data[forbiddenField] !== undefined) { + throw new MailError(`Can't use reserved data.${forbiddenField}.`); + } + } + } + + public async send(...to: string[]): Promise { + const results = []; + + for (const destEmail of to) { + // Reset options + this.options.html = this.options.text = undefined; + + // Set options + this.options.to = destEmail; + + // Set data + this.data.mail_subject = this.options.subject; + this.data.mail_to = this.options.to; + this.data.mail_link = `${config.get('public_url')}${mailRoute(this.template.template)}?${querystring.stringify(this.data)}`; + + // Log + Logger.dev('Send mail', this.options); + + // Render email + this.options.html = Mail.parse('mails/' + this.template.template + '.mjml.njk', this.data, false); + this.options.text = Mail.parse('mails/' + this.template.template + '.mjml.njk', this.data, true); + + // Send email + results.push(await Mail.getTransporter().sendMail(this.options)); + } + + return results; + } +} + +export class MailTemplate { + private readonly _template: string; + private readonly subject: (data: any) => string; + + constructor(template: string, subject: (data: any) => string) { + this._template = template; + this.subject = subject; + } + + public get template(): string { + return this._template; + } + + public getSubject(data: any): string { + return 'Watch My Stream - ' + this.subject(data); + } +} + +class MailError extends WrappingError { + constructor(message: string = 'An error occurred while sending mail.', cause?: Error) { + super(message, cause); + } +} \ No newline at end of file diff --git a/src/Pagination.ts b/src/Pagination.ts new file mode 100644 index 0000000..1cb0539 --- /dev/null +++ b/src/Pagination.ts @@ -0,0 +1,24 @@ +import Model from "./db/Model"; + +export default class Pagination { + private readonly models: T[]; + public readonly page: number; + public readonly perPage: number; + public readonly totalCount: number; + + constructor(models: T[], page: number, perPage: number, totalCount: number) { + this.models = models; + this.page = page; + this.perPage = perPage; + this.totalCount = totalCount; + } + + public hasPrevious(): boolean { + return this.page > 1; + } + + public hasNext(): boolean { + return this.models.length >= this.perPage && this.page * this.perPage < this.totalCount; + } + +} \ No newline at end of file diff --git a/src/Utils.ts b/src/Utils.ts new file mode 100644 index 0000000..c63593b --- /dev/null +++ b/src/Utils.ts @@ -0,0 +1,35 @@ +import * as crypto from "crypto"; + +export async function sleep(ms: number): Promise { + return await new Promise(resolve => { + setTimeout(() => resolve(), ms); + }); +} + +export abstract class WrappingError extends Error { + public readonly cause?: Error; + + protected constructor(message: string, cause?: Error) { + super(message); + this.cause = cause; + + if (cause !== undefined) { + this.stack = (this.stack || '') + `\n> Caused by: ${cause.stack}`; + } + } + + get name(): string { + return this.constructor.name; + } +} + +export function cryptoRandomDictionary(size: number, dictionary: string): string { + const randomBytes = crypto.randomBytes(size); + const output = new Array(size); + + for (let i = 0; i < size; i++) { + output[i] = dictionary[Math.floor((randomBytes[i] / 255) * dictionary.length)]; + } + + return output.join(''); +} \ No newline at end of file diff --git a/src/WebSocketListener.ts b/src/WebSocketListener.ts new file mode 100644 index 0000000..abe1ef9 --- /dev/null +++ b/src/WebSocketListener.ts @@ -0,0 +1,8 @@ +import WebSocket from "ws"; +import {IncomingMessage} from "http"; + +export default abstract class WebSocketListener { + public abstract path(): string; + + public abstract async handle(socket: WebSocket, request: IncomingMessage, session: Express.SessionData): Promise; +} \ No newline at end of file diff --git a/src/components/CsrfProtectionComponent.ts b/src/components/CsrfProtectionComponent.ts new file mode 100644 index 0000000..5db4074 --- /dev/null +++ b/src/components/CsrfProtectionComponent.ts @@ -0,0 +1,54 @@ +import ApplicationComponent from "../ApplicationComponent"; +import {Express, Router} from "express"; +import crypto from "crypto"; +import {BadRequestError} from "../HttpError"; + +export default class CsrfProtectionComponent extends ApplicationComponent { + public async start(app: Express, router: Router): Promise { + router.use((req, res, next) => { + if (!req.session) { + throw new Error('Session is unavailable.'); + } + + res.locals.getCSRFToken = () => { + if (typeof req.session!.csrf !== 'string') { + req.session!.csrf = crypto.randomBytes(64).toString('base64'); + } + return req.session!.csrf; + }; + + if (!['GET', 'HEAD', 'OPTIONS'].find(s => s === req.method)) { + if (req.session.csrf === undefined) { + throw new InvalidCsrfTokenError(req.baseUrl, `You weren't assigned any CSRF token.`); + } else if (req.body.csrf === undefined) { + throw new InvalidCsrfTokenError(req.baseUrl, `You didn't provide any CSRF token.`); + } else if (req.session.csrf !== req.body.csrf) { + throw new InvalidCsrfTokenError(req.baseUrl, `Tokens don't match.`); + } + } + next(); + }); + } + + public async stop(): Promise { + } +} + +class InvalidCsrfTokenError extends BadRequestError { + constructor(url: string, details: string, cause?: Error) { + super( + `Invalid CSRF token`, + `${details} We can't process this request. Please try again.`, + url, + cause + ); + } + + get name(): string { + return 'Invalid CSRF Token'; + } + + get errorCode(): number { + return 401; + } +} diff --git a/src/components/ExpressAppComponent.ts b/src/components/ExpressAppComponent.ts new file mode 100644 index 0000000..ce4a57b --- /dev/null +++ b/src/components/ExpressAppComponent.ts @@ -0,0 +1,40 @@ +import ApplicationComponent from "../ApplicationComponent"; +import express, {Express, Router} from "express"; +import Logger from "../Logger"; +import {Server} from "http"; + +export default class ExpressAppComponent extends ApplicationComponent { + private readonly port: number; + private server?: Server; + + constructor(port: number) { + super(); + this.port = port; + } + + public async start(app: Express, router: Router): Promise { + this.server = app.listen(this.port, 'localhost', () => { + Logger.info(`Web server running on localhost:${this.port}.`); + }); + + router.use(express.json()); + router.use(express.urlencoded()); + + router.use((req, res, next) => { + req.models = {}; + req.modelCollections = {}; + next(); + }); + } + + public async stop(): Promise { + if (this.server) { + await this.close('Webserver', this.server, this.server.close); + } + } + + public getServer(): Server { + if (!this.server) throw 'Server was not initialized.'; + return this.server; + } +} \ No newline at end of file diff --git a/src/components/FormHelperComponent.ts b/src/components/FormHelperComponent.ts new file mode 100644 index 0000000..607e223 --- /dev/null +++ b/src/components/FormHelperComponent.ts @@ -0,0 +1,48 @@ +import ApplicationComponent from "../ApplicationComponent"; +import {Express, Router} from "express"; + +export default class FormHelperComponent extends ApplicationComponent { + public async start(app: Express, router: Router): Promise { + router.use((req, res, next) => { + if (!req.session) { + throw new Error('Session is unavailable.'); + } + + res.locals.query = req.query; + + let _validation: any = null; + res.locals.validation = () => { + if (!_validation) { + const v = req.flash('validation'); + _validation = v.length > 0 ? v[0] : null; + } + + return _validation; + } + + let _previousFormData: any = null; + res.locals.previousFormData = () => { + if (!_previousFormData) { + const v = req.flash('previousFormData'); + _previousFormData = v.length > 0 ? v [0] : null; + } + + return _previousFormData; + }; + next(); + }); + + router.use((req, res, next) => { + if (['GET', 'POST'].find(m => m === req.method)) { + if (typeof req.body === 'object') { + req.flash('previousFormData', req.body); + } + } + next(); + }); + } + + public async stop(): Promise { + } + +} \ No newline at end of file diff --git a/src/components/LogRequestsComponent.ts b/src/components/LogRequestsComponent.ts new file mode 100644 index 0000000..a77c4f2 --- /dev/null +++ b/src/components/LogRequestsComponent.ts @@ -0,0 +1,21 @@ +import ApplicationComponent from "../ApplicationComponent"; +import onFinished from "on-finished"; +import Logger from "../Logger"; +import {Express, Router} from "express"; + +export default class LogRequestsComponent extends ApplicationComponent { + public async start(app: Express, router: Router): Promise { + router.use((req, res, next) => { + onFinished(res, (err) => { + if (!err) { + Logger.info(`${req.method} ${req.originalUrl} - ${res.statusCode}`); + } + }); + next(); + }); + } + + public async stop(): Promise { + } + +} \ No newline at end of file diff --git a/src/components/MailComponent.ts b/src/components/MailComponent.ts new file mode 100644 index 0000000..e204b14 --- /dev/null +++ b/src/components/MailComponent.ts @@ -0,0 +1,14 @@ +import ApplicationComponent from "../ApplicationComponent"; +import {Express, Router} from "express"; +import Mail from "../Mail"; + +export default class MailComponent extends ApplicationComponent { + public async start(app: Express, router: Router): Promise { + await this.prepare('Mail connection', () => Mail.prepare()); + } + + public async stop(): Promise { + Mail.end(); + } + +} \ No newline at end of file diff --git a/src/components/MaintenanceComponent.ts b/src/components/MaintenanceComponent.ts new file mode 100644 index 0000000..76a18d7 --- /dev/null +++ b/src/components/MaintenanceComponent.ts @@ -0,0 +1,40 @@ +import ApplicationComponent from "../ApplicationComponent"; +import {Express, NextFunction, Request, Response, Router} from "express"; +import {ServiceUnavailableHttpError} from "../HttpError"; +import Application from "../Application"; + +export default class MaintenanceComponent extends ApplicationComponent { + private readonly application: Application; + private readonly canServe: () => boolean; + + constructor(application: Application, canServe: () => boolean) { + super(); + this.application = application; + this.canServe = canServe; + } + + public async start(app: Express, router: Router): Promise { + router.use((req: Request, res: Response, next: NextFunction) => { + if (res.headersSent) { + return next(); + } + + if (!this.application.isReady()) { + res.header({'Retry-After': 60}); + res.locals.refresh_after = 5; + throw new ServiceUnavailableHttpError('Watch My Stream is readying up. Please wait a few seconds...'); + } + + if (!this.canServe()) { + res.locals.refresh_after = 30; + throw new ServiceUnavailableHttpError('Watch My Stream is unavailable due to failure of dependent services.'); + } + + next(); + }); + } + + public async stop(): Promise { + } + +} \ No newline at end of file diff --git a/src/components/MysqlComponent.ts b/src/components/MysqlComponent.ts new file mode 100644 index 0000000..0bf03e6 --- /dev/null +++ b/src/components/MysqlComponent.ts @@ -0,0 +1,18 @@ +import ApplicationComponent from "../ApplicationComponent"; +import {Express, Router} from "express"; +import MysqlConnectionManager from "../db/MysqlConnectionManager"; + +export default class MysqlComponent extends ApplicationComponent { + public async start(app: Express, router: Router): Promise { + await this.prepare('Mysql connection', () => MysqlConnectionManager.prepare()); + } + + public async stop(): Promise { + await MysqlConnectionManager.endPool(); + } + + public canServe(): boolean { + return MysqlConnectionManager.pool !== undefined; + } + +} \ No newline at end of file diff --git a/src/components/RedirectBackComponent.ts b/src/components/RedirectBackComponent.ts new file mode 100644 index 0000000..c3b9712 --- /dev/null +++ b/src/components/RedirectBackComponent.ts @@ -0,0 +1,43 @@ +import ApplicationComponent from "../ApplicationComponent"; +import {Express, Router} from "express"; +import onFinished from "on-finished"; +import Logger from "../Logger"; +import {ServerError} from "../HttpError"; + +export default class RedirectBackComponent extends ApplicationComponent { + public async start(app: Express, router: Router): Promise { + router.use((req, res, next) => { + if (!req.session) { + throw new Error('Session is unavailable.'); + } + + onFinished(res, (err) => { + if (!err && res.statusCode === 200) { + req.session!.previousUrl = req.originalUrl; + Logger.debug('Prev url set to', req.session!.previousUrl); + req.session!.save((err) => { + if (err) { + Logger.error(err, 'Error while saving session'); + } + }); + } + }); + + res.redirectBack = (defaultUrl?: string) => { + if (req.session && typeof req.session.previousUrl === 'string') { + res.redirect(req.session.previousUrl); + } else if (typeof defaultUrl === 'string') { + res.redirect(defaultUrl); + } else { + throw new ServerError('There is no previous url and no default redirection url was provided.'); + } + }; + + next(); + }); + } + + public async stop(): Promise { + } + +} \ No newline at end of file diff --git a/src/components/RedisComponent.ts b/src/components/RedisComponent.ts new file mode 100644 index 0000000..f0efd3c --- /dev/null +++ b/src/components/RedisComponent.ts @@ -0,0 +1,40 @@ +import ApplicationComponent from "../ApplicationComponent"; +import {Express, Router} from "express"; +import redis, {RedisClient} from "redis"; +import config from "config"; +import Logger from "../Logger"; +import session, {Store} from "express-session"; +import connect_redis from "connect-redis"; + +const RedisStore = connect_redis(session); + +export default class RedisComponent extends ApplicationComponent { + private redisClient?: RedisClient; + private store?: Store; + + public async start(app: Express, router: Router): Promise { + this.redisClient = redis.createClient(config.get('redis.port'), config.get('redis.host'), {}); + this.redisClient.on('error', (err: any) => { + Logger.error(err, 'An error occurred with redis.'); + }); + this.store = new RedisStore({ + client: this.redisClient, + prefix: 'wms-sess:', + }); + } + + public async stop(): Promise { + if (this.redisClient) { + await this.close('Redis connection', this.redisClient, this.redisClient.quit); + } + } + + public getStore(): Store { + if (!this.store) throw `Redis store was not initialized.`; + return this.store; + } + + public canServe(): boolean { + return this.redisClient !== undefined && this.redisClient.connected; + } +} \ No newline at end of file diff --git a/src/components/ServeStaticDirectoryComponent.ts b/src/components/ServeStaticDirectoryComponent.ts new file mode 100644 index 0000000..5573c37 --- /dev/null +++ b/src/components/ServeStaticDirectoryComponent.ts @@ -0,0 +1,26 @@ +import ApplicationComponent from "../ApplicationComponent"; +import express, {Express, Router} from "express"; +import {PathParams} from "express-serve-static-core"; + +export default class ServeStaticDirectoryComponent extends ApplicationComponent { + private readonly root: string; + private readonly path?: PathParams; + + constructor(root: string, routePath?: PathParams) { + super(); + this.root = root; + this.path = routePath; + } + + public async start(app: Express, router: Router): Promise { + if (typeof this.path !== 'undefined') { + router.use(this.path, express.static(this.root, {maxAge: 1000 * 3600 * 72})); + } else { + router.use(express.static(this.root, {maxAge: 1000 * 3600 * 72})); + } + } + + public async stop(): Promise { + } + +} \ No newline at end of file diff --git a/src/components/SessionComponent.ts b/src/components/SessionComponent.ts new file mode 100644 index 0000000..696be18 --- /dev/null +++ b/src/components/SessionComponent.ts @@ -0,0 +1,57 @@ +import ApplicationComponent from "../ApplicationComponent"; +import session from "express-session"; +import config from "config"; +import RedisComponent from "./RedisComponent"; +import flash from "connect-flash"; +import {Express, Router} from "express"; + +export default class SessionComponent extends ApplicationComponent { + private readonly storeComponent: RedisComponent; + + + public constructor(storeComponent: RedisComponent) { + super(); + this.storeComponent = storeComponent; + } + + public async start(app: Express, router: Router): Promise { + router.use(session({ + saveUninitialized: true, + secret: config.get('session.secret'), + store: this.storeComponent.getStore(), + resave: true, + cookie: { + httpOnly: true, + secure: config.get('session.cookie.secure'), + }, + rolling: true, + })); + + router.use(flash()); + + router.use((req, res, next) => { + if (!req.session) { + throw new Error('Session is unavailable.'); + } + + res.locals.session = req.session; + + let _flash: any = null; + res.locals.flash = () => { + if (!_flash) { + _flash = { + info: req.flash('info'), + success: req.flash('success'), + warning: req.flash('warning'), + error: req.flash('error'), + }; + } + return _flash; + }; + next(); + }); + } + + public async stop(): Promise { + } +} \ No newline at end of file diff --git a/src/components/WebSocketServerComponent.ts b/src/components/WebSocketServerComponent.ts new file mode 100644 index 0000000..4081e96 --- /dev/null +++ b/src/components/WebSocketServerComponent.ts @@ -0,0 +1,79 @@ +import ApplicationComponent from "../ApplicationComponent"; +import {Express, Request, Router} from "express"; +import WebSocket, {Server as WebSocketServer} from "ws"; +import Logger from "../Logger"; +import cookie from "cookie"; +import cookieParser from "cookie-parser"; +import config from "config"; +import ExpressAppComponent from "./ExpressAppComponent"; +import Application from "../Application"; +import RedisComponent from "./RedisComponent"; +import WebSocketListener from "../WebSocketListener"; + +export default class WebSocketServerComponent extends ApplicationComponent { + private readonly application: Application; + private readonly expressAppComponent: ExpressAppComponent; + private readonly storeComponent: RedisComponent; + + private wss?: WebSocket.Server; + + constructor(application: Application, expressAppComponent: ExpressAppComponent, storeComponent: RedisComponent) { + super(); + this.expressAppComponent = expressAppComponent; + this.application = application; + this.storeComponent = storeComponent; + } + + public async start(app: Express, router: Router): Promise { + const listeners: { [p: string]: WebSocketListener } = this.application.getWebSocketListeners(); + this.wss = new WebSocketServer({ + server: this.expressAppComponent.getServer(), + }, () => { + Logger.info(`Websocket server started over webserver.`); + }).on('error', (err) => { + Logger.error(err, 'An error occurred in the websocket server.'); + }).on('connection', (socket, request) => { + const listener = request.url ? listeners[request.url] : null; + + if (!listener) { + socket.close(1002, `Path not found ${request.url}`); + return; + } else if (!request.headers.cookie) { + socket.close(1002, `Can't process request without cookies.`); + return; + } + + Logger.debug(`Websocket on ${request.url}`); + + const cookies = cookie.parse(request.headers.cookie); + const sid = cookieParser.signedCookie(cookies['connect.sid'], config.get('session.secret')); + + if (!sid) { + socket.close(1002); + return; + } + + const store = this.storeComponent.getStore(); + store.get(sid, (err, session) => { + if (err || !session) { + Logger.error(err, 'Error while initializing session in websocket.'); + socket.close(1011); + return; + } + + session.id = sid; + + store.createSession(request, session); + listener.handle(socket, request, session).catch(err => { + Logger.error(err, 'Error in websocket listener.'); + }); + }); + }); + } + + public async stop(): Promise { + if (this.wss) { + await this.close('WebSocket server', this.wss, this.wss.close); + } + } +} \ No newline at end of file diff --git a/src/db/Migration.ts b/src/db/Migration.ts new file mode 100644 index 0000000..34b3c4a --- /dev/null +++ b/src/db/Migration.ts @@ -0,0 +1,15 @@ +export default abstract class Migration { + public readonly version: number; + + constructor(version: number) { + this.version = version; + } + + async shouldRun(currentVersion: number): Promise { + return this.version > currentVersion; + } + + abstract async install(): Promise; + + abstract async rollback(): Promise; +} \ No newline at end of file diff --git a/src/db/Model.ts b/src/db/Model.ts new file mode 100644 index 0000000..ea0ef37 --- /dev/null +++ b/src/db/Model.ts @@ -0,0 +1,311 @@ +import MysqlConnectionManager, {query} from "./MysqlConnectionManager"; +import Validator from "./Validator"; +import {Connection} from "mysql"; +import Query from "./Query"; +import {Request} from "express"; +import Pagination from "../Pagination"; + +export default abstract class Model { + public static async getById(id: number): Promise { + const cachedModel = ModelCache.get(this.table, id); + if (cachedModel?.constructor === this) { + return cachedModel; + } + + const models = await this.models(this.select().where('id', id).first()); + return models.length > 0 ? models[0] : null; + } + + public static async paginate(request: Request, perPage: number = 20): Promise { + let page = request.params.page ? parseInt(request.params.page) : 1; + let query: Query = this.select().limit(perPage, (page - 1) * perPage).withTotalRowCount(); + if (request.params.sortBy) { + const dir = request.params.sortDirection; + query = query.sortBy(request.params.sortBy, dir === 'ASC' || dir === 'DESC' ? dir : undefined); + } else { + query = query.sortBy('id'); + } + const models = await this.models(query); + // @ts-ignore + models.pagination = new Pagination(models, page, perPage, models.totalCount); + return models; + } + + protected static select(...fields: string[]): Query { + return Query.select(this.table, ...fields); + } + + protected static update(data: { [key: string]: any }): Query { + return Query.update(this.table, data); + } + + protected static delete(): Query { + return Query.delete(this.table); + } + + protected static async models(query: Query): Promise { + const results = await query.execute(); + const models: T[] = []; + const factory = this.getFactory(); + for (const result of results.results) { + const cachedModel = ModelCache.get(this.table, result.id); + if (cachedModel && cachedModel.constructor === this) { + cachedModel.updateWithData(result); + models.push(cachedModel); + } else { + models.push(factory(result)); + } + } + // @ts-ignore + models.totalCount = results.foundRows; + return models; + } + + public static async loadRelation(models: T[], relation: string, model: Function, localField: string) { + const loadMap: { [p: number]: (model: T) => void } = {}; + const ids = models.map(m => { + m.relations[relation] = null; + if (m[localField]) loadMap[m[localField]] = v => m.relations[relation] = v; + return m[localField]; + }).filter(id => id); + for (const v of await (model).models((model).select().whereIn('id', ids))) { + loadMap[v.id!](v); + } + } + + private static getFactory(factory?: ModelFactory): ModelFactory { + if (factory === undefined) { + factory = (this).FACTORY; + if (factory === undefined) factory = data => new (this)(data); + } + return factory; + } + + + protected readonly properties: ModelProperty[] = []; + private readonly relations: { [p: string]: (Model | null) } = {}; + public id?: number; + + [key: string]: any; + + public constructor(data: any) { + this.defineProperty('id', new Validator()); + this.defineProperties(); + this.updateWithData(data); + } + + protected abstract defineProperties(): void; + + protected defineProperty(name: string, validator?: Validator | RegExp) { + if (validator === undefined) validator = new Validator(); + if (validator instanceof RegExp) { + const regexp = validator; + validator = new Validator().regexp(regexp); + } + + const prop = new ModelProperty(name, validator); + this.properties.push(prop); + Object.defineProperty(this, name, { + get: () => prop.value, + set: (value: T) => prop.value = value, + }); + } + + private updateWithData(data: any) { + this.id = data['id']; + + for (const prop of this.properties) { + if (data[prop.name] !== undefined) { + this[prop.name] = data[prop.name]; + } + } + } + + protected async beforeSave(exists: boolean, connection: Connection): Promise { + } + + protected async afterSave(): Promise { + } + + public async save(connection?: Connection, postHook?: (callback: () => Promise) => void): Promise { + await this.validate(false, connection); + + const exists = await this.exists(); + let needs_full_update = false; + + if (connection) { + needs_full_update = await this.saveTransaction(connection, exists, needs_full_update); + } else { + needs_full_update = await MysqlConnectionManager.wrapTransaction(async connection => this.saveTransaction(connection, exists, needs_full_update)); + } + + const callback = async () => { + if (needs_full_update) { + this.updateWithData((await (this.constructor).select().where('id', this.id!).first().execute()).results[0]); + } + + if (!exists) { + this.cache(); + } + + await this.afterSave(); + }; + + if (connection) { + postHook!(callback); + } else { + await callback(); + } + } + + private async saveTransaction(connection: Connection, exists: boolean, needs_full_update: boolean): Promise { + // Before save + await this.beforeSave(exists, connection); + if (exists && this.hasOwnProperty('updated_at')) { + this.updated_at = new Date(); + } + + const props = []; + const values = []; + + if (exists) { + for (const prop of this.properties) { + if (prop.value !== undefined) { + props.push(prop.name + '=?'); + values.push(prop.value); + } else { + needs_full_update = true; + } + } + values.push(this.id); + await query(`UPDATE ${this.table} SET ${props.join(',')} WHERE id=?`, values, connection); + } else { + const props_holders = []; + for (const prop of this.properties) { + if (prop.value !== undefined) { + props.push(prop.name); + props_holders.push('?'); + values.push(prop.value); + } else { + needs_full_update = true; + } + } + const result = await query(`INSERT INTO ${this.table} (${props.join(', ')}) VALUES(${props_holders.join(', ')})`, values, connection); + + this.id = result.other.insertId; + } + + return needs_full_update; + } + + public static get table(): string { + return this.name + .replace(/(?:^|\.?)([A-Z])/g, (x, y) => '_' + y.toLowerCase()) + .replace(/^_/, '') + + 's'; + } + + public get table(): string { + // @ts-ignore + return this.constructor.table; + } + + public async exists(): Promise { + if (!this.id) return false; + + const result = await query(`SELECT 1 FROM ${this.table} WHERE id=? LIMIT 1`, [ + this.id, + ]); + return result.results.length > 0; + } + + public async delete(): Promise { + if (!(await this.exists())) throw new Error('This model instance doesn\'t exist in DB.'); + + await query(`DELETE FROM ${this.table} WHERE id=?`, [ + this.id, + ]); + ModelCache.forget(this); + this.id = undefined; + } + + public async validate(onlyFormat: boolean = false, connection?: Connection): Promise { + return await Promise.all(this.properties.map(prop => prop.validate(onlyFormat, connection))); + } + + private cache() { + ModelCache.cache(this); + } + + protected relation(name: string): T | null { + if (this.relations[name] === undefined) throw new Error('Model not loaded'); + return this.relations[name]; + } +} + +export interface ModelFactory { + (data: any): T; +} + +class ModelProperty { + public readonly name: string; + private readonly validator: Validator; + private val?: T; + + constructor(name: string, validator: Validator) { + this.name = name; + this.validator = validator; + } + + public async validate(onlyFormat: boolean, connection?: Connection): Promise { + return await this.validator.execute(this.name, this.value, onlyFormat, connection); + } + + public get value(): T | undefined { + return this.val; + } + + public set value(val: T | undefined) { + this.val = val; + } +} + +export class ModelCache { + private static readonly caches: { + [key: string]: { + [key: number]: Model + } + } = {}; + + public static cache(instance: Model) { + if (instance.id === undefined) throw new Error('Cannot cache an instance with an undefined id.'); + + let tableCache = this.caches[instance.table]; + if (!tableCache) tableCache = this.caches[instance.table] = {}; + + if (!tableCache[instance.id]) tableCache[instance.id] = instance; + } + + public static forget(instance: Model) { + if (instance.id === undefined) throw new Error('Cannot forget an instance with an undefined id.'); + + let tableCache = this.caches[instance.table]; + if (!tableCache) return; + + if (tableCache[instance.id]) delete tableCache[instance.id]; + } + + public static all(table: string): { + [key: number]: Model + } | undefined { + return this.caches[table]; + } + + public static get(table: string, id: number): Model | undefined { + const tableCache = this.all(table); + if (!tableCache) return undefined; + return tableCache[id]; + } +} + +export const EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/; \ No newline at end of file diff --git a/src/db/MysqlConnectionManager.ts b/src/db/MysqlConnectionManager.ts new file mode 100644 index 0000000..3bccd7e --- /dev/null +++ b/src/db/MysqlConnectionManager.ts @@ -0,0 +1,169 @@ +import mysql, {Connection, FieldInfo, Pool} from 'mysql'; +import config from 'config'; +import Migration from "./Migration"; +import Logger from "../Logger"; + +export interface QueryResult { + readonly results: any[]; + readonly fields: FieldInfo[]; + readonly other?: any; + foundRows?: number; +} + +export async function query(queryString: string, values?: any, connection?: Connection): Promise { + return await MysqlConnectionManager.query(queryString, values, connection); +} + +export default class MysqlConnectionManager { + private static currentPool?: Pool; + private static databaseReady: boolean = false; + private static readonly migrations: Migration[] = []; + + public static registerMigration(migration: (version: number) => Migration) { + this.migrations.push(migration(this.migrations.length + 1)); + } + + public static async prepare() { + if (config.get('mysql.create_database_automatically') === true) { + const dbName = config.get('mysql.database'); + Logger.info(`Creating database ${dbName}...`); + const connection = mysql.createConnection({ + host: config.get('mysql.host'), + user: config.get('mysql.user'), + password: config.get('mysql.password'), + }); + await new Promise((resolve, reject) => { + connection.query(`CREATE DATABASE IF NOT EXISTS ${dbName}`, (error) => { + if (error !== null) { + reject(error); + } else { + resolve(); + } + }); + }); + connection.end(); + Logger.info(`Database ${dbName} created!`); + } + this.databaseReady = true; + + await this.handleMigrations(); + } + + public static get pool(): Pool { + if (this.currentPool === undefined) { + this.currentPool = this.createPool(); + } + return this.currentPool; + } + + private static createPool(): Pool { + return mysql.createPool({ + connectionLimit: config.get('mysql.connectionLimit'), + host: config.get('mysql.host'), + user: config.get('mysql.user'), + password: config.get('mysql.password'), + database: config.get('mysql.database'), + }); + } + + public static async endPool(): Promise { + return new Promise(resolve => { + if (this.currentPool !== undefined) { + this.currentPool.end(() => { + Logger.info('Mysql connection pool ended.'); + resolve(); + }); + this.currentPool = undefined; + } else { + resolve(); + } + }); + } + + public static async query(queryString: string, values?: any, connection?: Connection): Promise { + return await new Promise((resolve, reject) => { + Logger.dev('Mysql query:', queryString, '; values:', values); + (connection ? connection : this.pool).query(queryString, values, (error, results, fields) => { + if (error !== null) { + reject(error); + return; + } + + resolve({ + results: Array.isArray(results) ? results : [], + fields: fields !== undefined ? fields : [], + other: Array.isArray(results) ? null : results + }); + }); + }); + } + + public static async wrapTransaction(transaction: (connection: Connection) => Promise): Promise { + return await new Promise((resolve, reject) => { + this.pool.getConnection((err, connection) => { + if (err) { + reject(err); + return; + } + + connection.beginTransaction((err) => { + if (err) { + reject(err); + this.pool.releaseConnection(connection); + return; + } + + transaction(connection).then(val => { + connection.commit((err) => { + if (err) { + this.rejectAndRollback(connection, err, reject); + this.pool.releaseConnection(connection); + return; + } + + this.pool.releaseConnection(connection); + resolve(val); + }); + }).catch(err => { + this.rejectAndRollback(connection, err, reject); + this.pool.releaseConnection(connection); + }); + }); + }); + }); + } + + private static rejectAndRollback(connection: Connection, err: any, reject: (err: any) => void) { + connection.rollback((rollbackErr) => { + if (rollbackErr) { + reject(err + '\n' + rollbackErr); + } else { + reject(err); + } + }); + } + + private static async handleMigrations() { + let currentVersion = 0; + + try { + const result = await query('SELECT id FROM migrations ORDER BY id DESC LIMIT 1'); + currentVersion = result.results[0].id; + } catch (e) { + if (e.code === 'ECONNREFUSED' || e.code !== 'ER_NO_SUCH_TABLE') { + throw new Error('Cannot run migrations: ' + e.code); + } + } + + for (const migration of this.migrations) { + if (await migration.shouldRun(currentVersion)) { + Logger.info('Running migration ', migration.version, migration.constructor.name); + await migration.install(); + await query('INSERT INTO migrations VALUES(?, ?, NOW())', [ + migration.version, + migration.constructor.name, + ]); + } + } + } +} \ No newline at end of file diff --git a/src/db/Query.ts b/src/db/Query.ts new file mode 100644 index 0000000..882f5eb --- /dev/null +++ b/src/db/Query.ts @@ -0,0 +1,214 @@ +import {query, QueryResult} from "./MysqlConnectionManager"; +import {Connection} from "mysql"; + +export default class Query { + public static select(table: string, ...fields: string[]): Query { + return new Query(QueryType.SELECT, table, fields.length > 0 ? fields : ['*']); + } + + public static update(table: string, data: { + [key: string]: any + }) { + const fields = []; + for (let key in data) { + if (data.hasOwnProperty(key)) { + fields.push(new UpdateFieldValue(key, data[key])); + } + } + return new Query(QueryType.UPDATE, table, fields); + } + + public static delete(table: string) { + return new Query(QueryType.DELETE, table); + } + + private readonly type: QueryType; + private readonly table: string; + private readonly fields: (string | SelectFieldValue | UpdateFieldValue)[]; + private _where: WhereFieldValue[] = []; + private _limit?: number; + private _offset?: number; + private _sortBy?: string; + private _sortDirection?: 'ASC' | 'DESC'; + private _foundRows: boolean = false; + + private constructor(type: QueryType, table: string, fields?: (string | SelectFieldValue | UpdateFieldValue)[]) { + this.type = type; + this.table = table; + this.fields = fields || []; + } + + public where(field: string, value: string | Date | Query | any, operator: WhereOperator = WhereOperator.AND, test: WhereTest = WhereTest.EQUALS): Query { + this._where.push(new WhereFieldValue(field, value, operator, test)); + return this; + } + + public whereNot(field: string, value: string | Date | Query | any, operator: WhereOperator = WhereOperator.AND): Query { + return this.where(field, value, operator, WhereTest.DIFFERENT); + } + + public orWhere(field: string, value: string | Date | Query | any): Query { + return this.where(field, value, WhereOperator.OR); + } + + public whereIn(field: string, value: any[]): Query { + return this.where(field, value, WhereOperator.AND, WhereTest.IN); + } + + public limit(limit: number, offset: number = 0): Query { + this._limit = limit; + this._offset = offset; + return this; + } + + public first(): Query { + return this.limit(1); + } + + public sortBy(field: string, direction: 'ASC' | 'DESC' = 'ASC'): Query { + this._sortBy = field; + this._sortDirection = direction; + return this; + } + + public withTotalRowCount(): Query { + this._foundRows = true; + return this; + } + + public toString(final: boolean = false): string { + let query = ''; + + let fields = this.fields?.join(','); + + let where = ''; + if (this._where.length > 0) { + where = `WHERE ${this._where[0]}`; + for (let i = 1; i < this._where.length; i++) { + where += this._where[i].toString(false); + } + } + + let limit = ''; + if (typeof this._limit === 'number') { + limit = `LIMIT ${this._limit}`; + if (typeof this._offset === 'number' && this._offset !== 0) { + limit += ` OFFSET ${this._offset}`; + } + } + + let orderBy = ''; + if (typeof this._sortBy === 'string') { + orderBy = `ORDER BY ${this._sortBy} ${this._sortDirection}`; + } + + switch (this.type) { + case QueryType.SELECT: + query = `SELECT ${this._foundRows ? 'SQL_CALC_FOUND_ROWS' : ''} ${fields} FROM ${this.table} ${where} ${orderBy} ${limit}`; + break; + case QueryType.UPDATE: + query = `UPDATE ${this.table} SET ${fields} ${where} ${orderBy} ${limit}`; + break; + case QueryType.DELETE: + query = `DELETE FROM ${this.table} ${where} ${orderBy} ${limit}`; + break; + + } + + return final ? query : `(${query})`; + } + + public build(): string { + return this.toString(true); + } + + public get variables(): any[] { + const variables: any[] = []; + this.fields?.filter(v => v instanceof FieldValue) + .flatMap(v => (v).variables) + .forEach(v => variables.push(v)); + this._where.flatMap(v => v.variables) + .forEach(v => variables.push(v)); + return variables; + } + + public isCacheable(): boolean { + return this.type === QueryType.SELECT && this.fields.length === 1 && this.fields[0] === '*'; + } + + public async execute(connection?: Connection): Promise { + const queryResult = await query(this.build(), this.variables, connection); + if (this._foundRows) { + const foundRows = await query('SELECT FOUND_ROWS() as r', undefined, connection); + queryResult.foundRows = foundRows.results[0].r; + } + return queryResult; + } +} + +export enum QueryType { + SELECT, + UPDATE, + DELETE, +} + +enum WhereOperator { + AND = 'AND', + OR = 'OR', +} + +enum WhereTest { + EQUALS = '=', + DIFFERENT = '!=', + IN = ' IN ', +} + +class FieldValue { + protected readonly field: string; + protected value: any; + + constructor(field: string, value: any) { + this.field = field; + this.value = value; + } + + public toString(first: boolean = true): string { + return `${!first ? ',' : ''}${this.field}${this.test}${this.value instanceof Query ? this.value : (Array.isArray(this.value) ? '(?)' : '?')}`; + } + + protected get test(): string { + return '='; + } + + public get variables(): any[] { + return this.value instanceof Query ? this.value.variables : [this.value]; + } +} + +class SelectFieldValue extends FieldValue { + public toString(first: boolean = true): string { + return `(${this.value instanceof Query ? this.value : '?'}) AS ${this.field}`; + } +} + +class UpdateFieldValue extends FieldValue { +} + +class WhereFieldValue extends FieldValue { + private readonly operator: WhereOperator; + private readonly _test: WhereTest; + + constructor(field: string, value: any, operator: WhereOperator, test: WhereTest) { + super(field, value); + this.operator = operator; + this._test = test; + } + + public toString(first: boolean = true): string { + return (!first ? ` ${this.operator} ` : '') + super.toString(true); + } + + protected get test(): string { + return this._test; + } +} \ No newline at end of file diff --git a/src/db/Validator.ts b/src/db/Validator.ts new file mode 100644 index 0000000..e76ed9a --- /dev/null +++ b/src/db/Validator.ts @@ -0,0 +1,308 @@ +import Model from "./Model"; +import Query from "./Query"; +import {Connection} from "mysql"; + +export default class Validator { + private readonly steps: ValidationStep[] = []; + private readonly validationAttributes: string[] = []; + + private _min?: number; + private _max?: number; + + /** + * @param thingName The name of the thing to validate. + * @param value The value to verify. + * @param onlyFormat {@code true} to only validate format properties, {@code false} otherwise. + * @param connection A connection to use in case of wrapped transactions. + */ + async execute(thingName: string, value: T | undefined, onlyFormat: boolean, connection?: Connection): Promise { + const bag = new ValidationBag(); + + for (const step of this.steps) { + if (onlyFormat && !step.isFormat) continue; + + const result = step.verifyStep(value, thingName, connection); + if ((result === false || result instanceof Promise && (await result) === false) && step.throw) { + const error: ValidationError = step.throw(); + error.thingName = thingName; + error.value = value; + bag.addMessage(error); + } else if (step.interrupt !== undefined && step.interrupt(value)) { + break; + } + } + + if (bag.hasMessages()) { + throw bag; + } + } + + public defined(): Validator { + this.validationAttributes.push('required'); + + this.addStep({ + verifyStep: val => val !== undefined, + throw: () => new UndefinedValueValidationError(), + isFormat: true, + }); + return this; + } + + public acceptUndefined(): Validator { + this.addStep({ + verifyStep: () => true, + throw: null, + interrupt: val => val === undefined || val === null, + isFormat: true, + }); + return this; + } + + public equals(other?: T): Validator { + this.addStep({ + verifyStep: val => val === other, + throw: () => new BadValueValidationError(other), + isFormat: true, + }); + return this; + } + + public regexp(regexp: RegExp): Validator { + this.validationAttributes.push(`pattern="${regexp}"`); + this.addStep({ + verifyStep: val => regexp.test(val), + throw: () => new InvalidFormatValidationError(), + isFormat: true, + }); + return this; + } + + public length(length: number): Validator { + this.addStep({ + verifyStep: val => (val).length === length, + throw: () => new BadLengthValidationError(length), + isFormat: true, + }); + return this; + } + + /** + * @param minLength included + * @param maxLength included + */ + public between(minLength: number, maxLength: number): Validator { + this.addStep({ + verifyStep: val => { + const length = (val).length; + return length >= minLength && length <= maxLength; + }, + throw: () => new BadLengthValidationError(minLength, maxLength), + isFormat: true, + }); + return this; + } + + /** + * @param min included + */ + public min(min: number): Validator { + this.validationAttributes.push(`min="${min}"`); + this._min = min; + this.addStep({ + verifyStep: val => { + return (val) >= min; + }, + throw: () => new OutOfRangeValidationError(this._min, this._max), + isFormat: true, + }); + return this; + } + + /** + * @param max included + */ + public max(max: number): Validator { + this.validationAttributes.push(`max="${max}"`); + this._max = max; + this.addStep({ + verifyStep: val => { + return (val) <= max; + }, + throw: () => new OutOfRangeValidationError(this._min, this._max), + isFormat: true, + }); + return this; + } + + public unique(model: Model, querySupplier?: () => Query): Validator { + this.addStep({ + verifyStep: async (val, thingName, c) => { + let query: Query; + if (querySupplier) { + query = querySupplier().where(thingName, val); + } else { + query = (model.constructor).select('1').where(thingName, val); + } + if (typeof model.id === 'number') query = query.whereNot('id', model.id); + return (await query.execute(c)).results.length === 0; + }, + throw: () => new AlreadyExistsValidationError(model.table), + isFormat: false, + }); + return this; + } + + public exists(modelClass: Function, foreignKey?: string): Validator { + this.addStep({ + verifyStep: async (val, thingName, c) => (await (modelClass).select('1').where(foreignKey !== undefined ? foreignKey : thingName, val).execute(c)).results.length >= 1, + throw: () => new UnknownRelationValidationError((modelClass).table, foreignKey), + isFormat: false, + }); + return this; + } + + private addStep(step: ValidationStep) { + this.steps.push(step); + } + + public getValidationAttributes(): string[] { + return this.validationAttributes; + } + + public step(step: number): Validator { + this.validationAttributes.push(`step="${step}"`); + return this; + } +} + +interface ValidationStep { + interrupt?: (val?: T) => boolean; + + verifyStep(val: T | undefined, thingName: string, connection?: Connection): boolean | Promise; + + throw: ((val?: T) => ValidationError) | null; + + readonly isFormat: boolean; +} + +export class ValidationBag extends Error { + private readonly messages: { [p: string]: any } = {}; + + public addMessage(err: ValidationError) { + if (!err.thingName) { + throw new Error('Null thing name'); + } + + this.messages[err.thingName] = { + name: err.name, + message: err.message, + value: err.value, + }; + } + + public hasMessages(): boolean { + return Object.keys(this.messages).length > 0; + } + + public getMessages(): { [p: string]: ValidationError } { + return this.messages; + } +} + +export abstract class ValidationError extends Error { + public thingName?: string; + public value?: any; + + public get name(): string { + return this.constructor.name; + } +} + +export class BadLengthValidationError extends ValidationError { + private readonly expectedLength: number; + private readonly maxLength?: number; + + constructor(expectedLength: number, maxLength?: number) { + super(); + this.expectedLength = expectedLength; + this.maxLength = maxLength; + } + + public get message(): string { + return `${this.thingName} expected length: ${this.expectedLength}${this.maxLength !== undefined ? ` to ${this.maxLength}` : ''}; ` + + `actual length: ${this.value.length}.`; + } +} + +export class BadValueValidationError extends ValidationError { + private readonly expectedValue: any; + + constructor(expectedValue: any) { + super(); + this.expectedValue = expectedValue; + } + + public get message(): string { + return `Expected: ${this.expectedValue}; got: ${this.value}.` + } +} + +export class OutOfRangeValidationError extends ValidationError { + private readonly min?: number; + private readonly max?: number; + + constructor(min?: number, max?: number) { + super(); + this.min = min; + this.max = max; + } + + public get message(): string { + if (this.min === undefined) { + return `${this.thingName} must be at most ${this.max}`; + } else if (this.max === undefined) { + return `${this.thingName} must be at least ${this.min}`; + } + return `${this.thingName} must be between ${this.min} and ${this.max}.`; + } +} + +export class InvalidFormatValidationError extends ValidationError { + public get message(): string { + return `"${this.value}" is not a valid ${this.thingName}.`; + } +} + +export class UndefinedValueValidationError extends ValidationError { + public get message(): string { + return `${this.thingName} is required.`; + } +} + +export class AlreadyExistsValidationError extends ValidationError { + private readonly table: string; + + constructor(table: string) { + super(); + this.table = table; + } + + public get message(): string { + return `${this.value} already exists in ${this.table}.${this.thingName}.`; + } +} + +export class UnknownRelationValidationError extends ValidationError { + private readonly table: string; + private readonly foreignKey?: string; + + constructor(table: string, foreignKey?: string) { + super(); + this.table = table; + this.foreignKey = foreignKey; + } + + public get message(): string { + return `${this.thingName}=${this.value} relation was not found in ${this.table}${this.foreignKey !== undefined ? `.${this.foreignKey}` : ''}.`; + } +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..55df1ed --- /dev/null +++ b/src/index.ts @@ -0,0 +1 @@ +export {default as Application} from "./Application"; \ No newline at end of file diff --git a/src/migrations/CreateLogsTable.ts b/src/migrations/CreateLogsTable.ts new file mode 100644 index 0000000..37511b7 --- /dev/null +++ b/src/migrations/CreateLogsTable.ts @@ -0,0 +1,25 @@ +import Migration from "../db/Migration"; +import {query} from "../db/MysqlConnectionManager"; + +/** + * Must be the first migration + */ +export default class CreateLogsTable extends Migration { + async install(): Promise { + await query('CREATE TABLE logs(' + + 'id INT NOT NULL AUTO_INCREMENT,' + + 'level TINYINT UNSIGNED NOT NULL,' + + 'message TEXT NOT NULL,' + + 'log_id BINARY(16),' + + 'error_name VARCHAR(128),' + + 'error_message VARCHAR(512),' + + 'error_stack TEXT,' + + 'created_at DATETIME NOT NULL DEFAULT NOW(),' + + 'PRIMARY KEY (id)' + + ')'); + } + + async rollback(): Promise { + await query('DROP TABLE logs'); + } +} \ No newline at end of file diff --git a/src/migrations/CreateMigrationsTable.ts b/src/migrations/CreateMigrationsTable.ts new file mode 100644 index 0000000..5931d24 --- /dev/null +++ b/src/migrations/CreateMigrationsTable.ts @@ -0,0 +1,32 @@ +import Migration from "../db/Migration"; +import {query} from "../db/MysqlConnectionManager"; + +/** + * Must be the first migration + */ +export default class CreateMigrationsTable extends Migration { + async shouldRun(currentVersion: number): Promise { + try { + await query('SELECT 1 FROM migrations LIMIT 1'); + } catch (e) { + if (e.code !== 'ER_NO_SUCH_TABLE') { + return false; + } + } + + return await super.shouldRun(currentVersion); + } + + async install(): Promise { + await query('CREATE TABLE migrations(' + + 'id INT NOT NULL,' + + 'name VARCHAR(64) NOT NULL,' + + 'migration_date DATE,' + + 'PRIMARY KEY (id)' + + ')'); + } + + async rollback(): Promise { + await query('DROP TABLE migrations'); + } +} \ No newline at end of file diff --git a/src/models/Log.ts b/src/models/Log.ts new file mode 100644 index 0000000..e702423 --- /dev/null +++ b/src/models/Log.ts @@ -0,0 +1,69 @@ +import Model from "../db/Model"; +import {LogLevel, LogLevelKeys} from "../Logger"; +import Validator from "../db/Validator"; + +export default class Log extends Model { + private level?: number; + public message?: string; + private log_id?: Buffer; + private error_name?: string; + private error_message?: string; + private error_stack?: string; + private created_at?: Date; + + protected defineProperties(): void { + this.defineProperty('level', new Validator().defined()); + this.defineProperty('message', new Validator().defined().between(0, 65535)); + this.defineProperty('log_id', new Validator().acceptUndefined().length(16)); + this.defineProperty('error_name', new Validator().acceptUndefined().between(0, 128)); + this.defineProperty('error_message', new Validator().acceptUndefined().between(0, 512)); + this.defineProperty('error_stack', new Validator().acceptUndefined().between(0, 65535)); + this.defineProperty('created_at', new Validator()); + } + + public getLevel(): LogLevelKeys { + if (typeof this.level !== 'number') return 'ERROR'; + return LogLevel[this.level]; + } + + public setLevel(level: LogLevelKeys) { + this.level = LogLevel[level]; + } + + public getLogID(): string | null { + if (!this.log_id) return null; + const chars = this.log_id!.toString('hex'); + let out = ''; + let i = 0; + for (const l of [8, 4, 4, 4, 12]) { + if (i > 0) out += '-'; + out += chars.substr(i, l); + i += l; + } + return out; + } + + public setLogID(buffer: Buffer) { + this.log_id = buffer; + } + + public getErrorName(): string { + return this.error_name || ''; + } + + public getErrorMessage(): string { + return this.error_message || ''; + } + + public getErrorStack(): string { + return this.error_stack || ''; + } + + public setError(error?: Error) { + if (!error) return; + + this.error_name = error.name; + this.error_message = error.message; + this.error_stack = error.stack; + } +} diff --git a/src/types/Express.d.ts b/src/types/Express.d.ts new file mode 100644 index 0000000..41a32b5 --- /dev/null +++ b/src/types/Express.d.ts @@ -0,0 +1,20 @@ +import {Environment} from "nunjucks"; +import Model from "../db/Model"; + +declare module 'express-serve-static-core' { + export interface Request { + env: Environment; + models: { [p: string]: Model | null }; + modelCollections: { [p: string]: Model[] | null }; + + flash(): { [key: string]: string[] }; + + flash(message: string): any; + + flash(event: string, message: any): any; + } + + export interface Response { + redirectBack(defaultUrl?: string): any; + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..3f61cae --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + "target": "ES6", + "declaration": true, + "stripInternal": true, + + + "strict": true, +// "noUnusedLocals": true, +// "noUnusedParameters": true, + "allowSyntheticDefaultImports": true, + + "moduleResolution": "Node", + "baseUrl": ".", + "rootDir": "src", + "sourceRoot": ".", + "inlineSourceMap": true, + "inlineSources": true, + "outDir": "dist", + + "typeRoots": [ + "node_modules/@types", + "src/types" + ], + "lib": [ + "es2020" + ] + }, + "include": [ + "src" + ] +} \ No newline at end of file diff --git a/tsconfig.tsbuildinfo b/tsconfig.tsbuildinfo new file mode 100644 index 0000000..acc04c6 --- /dev/null +++ b/tsconfig.tsbuildinfo @@ -0,0 +1,3132 @@ +{ + "program": { + "fileInfos": { + "./node_modules/typescript/lib/lib.es5.d.ts": { + "version": "b42eddba1a53c9d27279cfe7fc0416c10a81489826ad47e39013b9d340fc0cc7", + "signature": "b42eddba1a53c9d27279cfe7fc0416c10a81489826ad47e39013b9d340fc0cc7" + }, + "./node_modules/typescript/lib/lib.es2015.d.ts": { + "version": "7994d44005046d1413ea31d046577cdda33b8b2470f30281fd9c8b3c99fe2d96", + "signature": "7994d44005046d1413ea31d046577cdda33b8b2470f30281fd9c8b3c99fe2d96" + }, + "./node_modules/typescript/lib/lib.es2016.d.ts": { + "version": "5f217838d25704474d9ef93774f04164889169ca31475fe423a9de6758f058d1", + "signature": "5f217838d25704474d9ef93774f04164889169ca31475fe423a9de6758f058d1" + }, + "./node_modules/typescript/lib/lib.es2017.d.ts": { + "version": "459097c7bdd88fc5731367e56591e4f465f2c9de81a35427a7bd473165c34743", + "signature": "459097c7bdd88fc5731367e56591e4f465f2c9de81a35427a7bd473165c34743" + }, + "./node_modules/typescript/lib/lib.es2018.d.ts": { + "version": "9c67dcc7ca897b61f58d57d487bc9f07950546e5ac8701cbc41a8a4fec48b091", + "signature": "9c67dcc7ca897b61f58d57d487bc9f07950546e5ac8701cbc41a8a4fec48b091" + }, + "./node_modules/typescript/lib/lib.es2019.d.ts": { + "version": "0fc0f68d3f4d94aa65fab955592e4a9f2066e6f8ee2f66fcc45adf4037fc167b", + "signature": "0fc0f68d3f4d94aa65fab955592e4a9f2066e6f8ee2f66fcc45adf4037fc167b" + }, + "./node_modules/typescript/lib/lib.es2020.d.ts": { + "version": "585694acba05fe18d6ad9c9f662f3de3766779933efb9f2d8c482c1a92bf073c", + "signature": "585694acba05fe18d6ad9c9f662f3de3766779933efb9f2d8c482c1a92bf073c" + }, + "./node_modules/typescript/lib/lib.es2015.core.d.ts": { + "version": "734ddc145e147fbcd55f07d034f50ccff1086f5a880107665ec326fb368876f6", + "signature": "734ddc145e147fbcd55f07d034f50ccff1086f5a880107665ec326fb368876f6" + }, + "./node_modules/typescript/lib/lib.es2015.collection.d.ts": { + "version": "4a0862a21f4700de873db3b916f70e41570e2f558da77d2087c9490f5a0615d8", + "signature": "4a0862a21f4700de873db3b916f70e41570e2f558da77d2087c9490f5a0615d8" + }, + "./node_modules/typescript/lib/lib.es2015.generator.d.ts": { + "version": "765e0e9c9d74cf4d031ca8b0bdb269a853e7d81eda6354c8510218d03db12122", + "signature": "765e0e9c9d74cf4d031ca8b0bdb269a853e7d81eda6354c8510218d03db12122" + }, + "./node_modules/typescript/lib/lib.es2015.iterable.d.ts": { + "version": "285958e7699f1babd76d595830207f18d719662a0c30fac7baca7df7162a9210", + "signature": "285958e7699f1babd76d595830207f18d719662a0c30fac7baca7df7162a9210" + }, + "./node_modules/typescript/lib/lib.es2015.promise.d.ts": { + "version": "d4deaafbb18680e3143e8b471acd650ed6f72a408a33137f0a0dd104fbe7f8ca", + "signature": "d4deaafbb18680e3143e8b471acd650ed6f72a408a33137f0a0dd104fbe7f8ca" + }, + "./node_modules/typescript/lib/lib.es2015.proxy.d.ts": { + "version": "5e72f949a89717db444e3bd9433468890068bb21a5638d8ab15a1359e05e54fe", + "signature": "5e72f949a89717db444e3bd9433468890068bb21a5638d8ab15a1359e05e54fe" + }, + "./node_modules/typescript/lib/lib.es2015.reflect.d.ts": { + "version": "f5b242136ae9bfb1cc99a5971cccc44e99947ae6b5ef6fd8aa54b5ade553b976", + "signature": "f5b242136ae9bfb1cc99a5971cccc44e99947ae6b5ef6fd8aa54b5ade553b976" + }, + "./node_modules/typescript/lib/lib.es2015.symbol.d.ts": { + "version": "9ae2860252d6b5f16e2026d8a2c2069db7b2a3295e98b6031d01337b96437230", + "signature": "9ae2860252d6b5f16e2026d8a2c2069db7b2a3295e98b6031d01337b96437230" + }, + "./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts": { + "version": "3e0a459888f32b42138d5a39f706ff2d55d500ab1031e0988b5568b0f67c2303", + "signature": "3e0a459888f32b42138d5a39f706ff2d55d500ab1031e0988b5568b0f67c2303" + }, + "./node_modules/typescript/lib/lib.es2016.array.include.d.ts": { + "version": "3f96f1e570aedbd97bf818c246727151e873125d0512e4ae904330286c721bc0", + "signature": "3f96f1e570aedbd97bf818c246727151e873125d0512e4ae904330286c721bc0" + }, + "./node_modules/typescript/lib/lib.es2017.object.d.ts": { + "version": "c2d60b2e558d44384e4704b00e6b3d154334721a911f094d3133c35f0917b408", + "signature": "c2d60b2e558d44384e4704b00e6b3d154334721a911f094d3133c35f0917b408" + }, + "./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts": { + "version": "b8667586a618c5cf64523d4e500ae39e781428abfb28f3de441fc66b56144b6f", + "signature": "b8667586a618c5cf64523d4e500ae39e781428abfb28f3de441fc66b56144b6f" + }, + "./node_modules/typescript/lib/lib.es2017.string.d.ts": { + "version": "21df2e0059f14dcb4c3a0e125859f6b6ff01332ee24b0065a741d121250bc71c", + "signature": "21df2e0059f14dcb4c3a0e125859f6b6ff01332ee24b0065a741d121250bc71c" + }, + "./node_modules/typescript/lib/lib.es2017.intl.d.ts": { + "version": "c1759cb171c7619af0d2234f2f8fb2a871ee88e956e2ed91bb61778e41f272c6", + "signature": "c1759cb171c7619af0d2234f2f8fb2a871ee88e956e2ed91bb61778e41f272c6" + }, + "./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts": { + "version": "28569d59e07d4378cb3d54979c4c60f9f06305c9bb6999ffe6cab758957adc46", + "signature": "28569d59e07d4378cb3d54979c4c60f9f06305c9bb6999ffe6cab758957adc46" + }, + "./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts": { + "version": "2958de3d25bfb0b5cdace0244e11c9637e5988920b99024db705a720ce6348e7", + "signature": "2958de3d25bfb0b5cdace0244e11c9637e5988920b99024db705a720ce6348e7" + }, + "./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts": { + "version": "85085a0783532dc04b66894748dc4a49983b2fbccb0679b81356947021d7a215", + "signature": "85085a0783532dc04b66894748dc4a49983b2fbccb0679b81356947021d7a215" + }, + "./node_modules/typescript/lib/lib.es2018.intl.d.ts": { + "version": "5494f46d3a8a0329d13ddc37f8759d5288760febb51c92336608d1c06bb18d29", + "signature": "5494f46d3a8a0329d13ddc37f8759d5288760febb51c92336608d1c06bb18d29" + }, + "./node_modules/typescript/lib/lib.es2018.promise.d.ts": { + "version": "efe049114bad1035b0aa9a4a0359f50ab776e3897c411521e51d3013079cbd62", + "signature": "efe049114bad1035b0aa9a4a0359f50ab776e3897c411521e51d3013079cbd62" + }, + "./node_modules/typescript/lib/lib.es2018.regexp.d.ts": { + "version": "e7780d04cd4120ee554c665829db2bbdd6b947cbaa3c150b7d9ea74df3beb2e8", + "signature": "e7780d04cd4120ee554c665829db2bbdd6b947cbaa3c150b7d9ea74df3beb2e8" + }, + "./node_modules/typescript/lib/lib.es2019.array.d.ts": { + "version": "7054111c49ea06f0f2e623eab292a9c1ae9b7d04854bd546b78f2b8b57e13d13", + "signature": "7054111c49ea06f0f2e623eab292a9c1ae9b7d04854bd546b78f2b8b57e13d13" + }, + "./node_modules/typescript/lib/lib.es2019.object.d.ts": { + "version": "989b95205f1189943fab0ce12a39c80570edf8f200aca60e0fdc500afc4d5859", + "signature": "989b95205f1189943fab0ce12a39c80570edf8f200aca60e0fdc500afc4d5859" + }, + "./node_modules/typescript/lib/lib.es2019.string.d.ts": { + "version": "e9bfd234b801c955459cde7109bebf6fd1b4814fd8b394942f5ba746828a6486", + "signature": "e9bfd234b801c955459cde7109bebf6fd1b4814fd8b394942f5ba746828a6486" + }, + "./node_modules/typescript/lib/lib.es2019.symbol.d.ts": { + "version": "5f2a476cdb4990b249077b46a6242979876e9bba5152e066d68fad77510ee328", + "signature": "5f2a476cdb4990b249077b46a6242979876e9bba5152e066d68fad77510ee328" + }, + "./node_modules/typescript/lib/lib.es2020.bigint.d.ts": { + "version": "0c9ea8c2028047f39a3f66752682604f543c08be8806258c3d95c93e75a43255", + "signature": "0c9ea8c2028047f39a3f66752682604f543c08be8806258c3d95c93e75a43255" + }, + "./node_modules/typescript/lib/lib.es2020.promise.d.ts": { + "version": "4a44be5b17ae6385fcc9a486361f50231992d556c9298373ae0d38cfae9f4056", + "signature": "4a44be5b17ae6385fcc9a486361f50231992d556c9298373ae0d38cfae9f4056" + }, + "./node_modules/typescript/lib/lib.es2020.string.d.ts": { + "version": "01f1170ac78a31964a8a05cc46df7dc63d6911f683cb49586b27c49f54187a86", + "signature": "01f1170ac78a31964a8a05cc46df7dc63d6911f683cb49586b27c49f54187a86" + }, + "./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts": { + "version": "1debec13dc47b66e7e5a5ceb3872ea7f141613148f6083ef6dc38626ee8c9a93", + "signature": "1debec13dc47b66e7e5a5ceb3872ea7f141613148f6083ef6dc38626ee8c9a93" + }, + "./node_modules/typescript/lib/lib.esnext.intl.d.ts": { + "version": "1377923021927244ea19433873b997ad8585533b0a56d5de29cda497f7842756", + "signature": "1377923021927244ea19433873b997ad8585533b0a56d5de29cda497f7842756" + }, + "./node_modules/@types/node/globals.d.ts": { + "version": "9d0b32c595a2e0d320a56b3d0e8f0a317e4149239ec913aa8f11eeb73edc92be", + "signature": "9d0b32c595a2e0d320a56b3d0e8f0a317e4149239ec913aa8f11eeb73edc92be" + }, + "./node_modules/@types/node/async_hooks.d.ts": { + "version": "96e547b51f95ee76bdb25731c92420fa6f93b59c3f38f23d505be36e2de394ee", + "signature": "96e547b51f95ee76bdb25731c92420fa6f93b59c3f38f23d505be36e2de394ee" + }, + "./node_modules/@types/node/buffer.d.ts": { + "version": "61215c1a376bbe8f51cab4cc4ddbf3746387015113c37a84d981d4738c21b878", + "signature": "61215c1a376bbe8f51cab4cc4ddbf3746387015113c37a84d981d4738c21b878" + }, + "../node_modules/@types/events/index.d.ts": { + "version": "400db42c3a46984118bff14260d60cec580057dc1ab4c2d7310beb643e4f5935", + "signature": "400db42c3a46984118bff14260d60cec580057dc1ab4c2d7310beb643e4f5935" + }, + "./node_modules/@types/node/child_process.d.ts": { + "version": "3ca89ecb953fe3b63dae41e5bb986506e812754dde0369c5fe61de26eff47dbe", + "signature": "3ca89ecb953fe3b63dae41e5bb986506e812754dde0369c5fe61de26eff47dbe" + }, + "./node_modules/@types/node/cluster.d.ts": { + "version": "123ec69e4b3a686eb49afd94ebe3292a5c84a867ecbcb6bb84bdd720a12af803", + "signature": "123ec69e4b3a686eb49afd94ebe3292a5c84a867ecbcb6bb84bdd720a12af803" + }, + "./node_modules/@types/node/console.d.ts": { + "version": "525c8fc510d9632d2a0a9de2d41c3ac1cdd79ff44d3b45c6d81cacabb683528d", + "signature": "525c8fc510d9632d2a0a9de2d41c3ac1cdd79ff44d3b45c6d81cacabb683528d" + }, + "./node_modules/@types/node/constants.d.ts": { + "version": "90c85ddbb8de82cd19198bda062065fc51b7407c0f206f2e399e65a52e979720", + "signature": "90c85ddbb8de82cd19198bda062065fc51b7407c0f206f2e399e65a52e979720" + }, + "./node_modules/@types/node/crypto.d.ts": { + "version": "d56c93b6bf66e602869e926ddc8b1b4630d1ff397909291767d18d4ffc22d33f", + "signature": "d56c93b6bf66e602869e926ddc8b1b4630d1ff397909291767d18d4ffc22d33f" + }, + "./node_modules/@types/node/dgram.d.ts": { + "version": "7ecfe97b43aa6c8b8f90caa599d5648bb559962e74e6f038f73a77320569dd78", + "signature": "7ecfe97b43aa6c8b8f90caa599d5648bb559962e74e6f038f73a77320569dd78" + }, + "./node_modules/@types/node/dns.d.ts": { + "version": "aad3237c3f99480041cad7ca04d64307c98933996f822342b7c0ee4a78553346", + "signature": "aad3237c3f99480041cad7ca04d64307c98933996f822342b7c0ee4a78553346" + }, + "./node_modules/@types/node/domain.d.ts": { + "version": "4d4c83f77ac21a72252785baa5328a5612b0b6598d512f68b8cb14f7966d059e", + "signature": "4d4c83f77ac21a72252785baa5328a5612b0b6598d512f68b8cb14f7966d059e" + }, + "./node_modules/@types/node/events.d.ts": { + "version": "5ffa4219ee64e130980a4231392cbc628544df137ccf650ae8d76e0a1744fd2b", + "signature": "5ffa4219ee64e130980a4231392cbc628544df137ccf650ae8d76e0a1744fd2b" + }, + "./node_modules/@types/node/fs.d.ts": { + "version": "e1a12c7e7951b9762cfbcc43c72eb5611120967706a7c3142ad303c6b7ee767f", + "signature": "e1a12c7e7951b9762cfbcc43c72eb5611120967706a7c3142ad303c6b7ee767f" + }, + "./node_modules/@types/node/http.d.ts": { + "version": "b5fd0a137bd6d0afe291d465e99c7469b082b66b3ee89273b3b22801b6c2948e", + "signature": "b5fd0a137bd6d0afe291d465e99c7469b082b66b3ee89273b3b22801b6c2948e" + }, + "./node_modules/@types/node/http2.d.ts": { + "version": "873da589b78a1f1fa7d623483bd2c2730a02e0852259fb8fdcfe5221ac51d18a", + "signature": "873da589b78a1f1fa7d623483bd2c2730a02e0852259fb8fdcfe5221ac51d18a" + }, + "./node_modules/@types/node/https.d.ts": { + "version": "c969bf4c7cdfe4d5dd28aa09432f99d09ad1d8d8b839959646579521d0467d1a", + "signature": "c969bf4c7cdfe4d5dd28aa09432f99d09ad1d8d8b839959646579521d0467d1a" + }, + "./node_modules/@types/node/inspector.d.ts": { + "version": "4218ced3933a31eed1278d350dd63c5900df0f0904f57d61c054d7a4b83dbe4c", + "signature": "4218ced3933a31eed1278d350dd63c5900df0f0904f57d61c054d7a4b83dbe4c" + }, + "./node_modules/@types/node/module.d.ts": { + "version": "a376e245f494b58365a4391a2568e6dd9da372c3453f4732eb6e15ebb9038451", + "signature": "a376e245f494b58365a4391a2568e6dd9da372c3453f4732eb6e15ebb9038451" + }, + "./node_modules/@types/node/net.d.ts": { + "version": "ffe8912b7c45288810c870b768190c6c097459930a587dd6ef0d900a5529a811", + "signature": "ffe8912b7c45288810c870b768190c6c097459930a587dd6ef0d900a5529a811" + }, + "./node_modules/@types/node/os.d.ts": { + "version": "f53678bdb9f25445c8cdf021f2b003b74fd638e69bb1959dde8e370e8cc1e4fa", + "signature": "f53678bdb9f25445c8cdf021f2b003b74fd638e69bb1959dde8e370e8cc1e4fa" + }, + "./node_modules/@types/node/path.d.ts": { + "version": "84044697c8b3e08ef24e4b32cfe6440143d07e469a5e34bda0635276d32d9f35", + "signature": "84044697c8b3e08ef24e4b32cfe6440143d07e469a5e34bda0635276d32d9f35" + }, + "./node_modules/@types/node/perf_hooks.d.ts": { + "version": "0b6098fedb648cab8091cca2b022a5c729b6ef18da923852033f495907cb1a45", + "signature": "0b6098fedb648cab8091cca2b022a5c729b6ef18da923852033f495907cb1a45" + }, + "./node_modules/@types/node/process.d.ts": { + "version": "0e0d58f5e90c0a270dac052b9c5ad8ccdfc8271118c2105b361063218d528d6e", + "signature": "0e0d58f5e90c0a270dac052b9c5ad8ccdfc8271118c2105b361063218d528d6e" + }, + "./node_modules/@types/node/punycode.d.ts": { + "version": "30ec6f9c683b988c3cfaa0c4690692049c4e7ed7dc6f6e94f56194c06b86f5e1", + "signature": "30ec6f9c683b988c3cfaa0c4690692049c4e7ed7dc6f6e94f56194c06b86f5e1" + }, + "./node_modules/@types/node/querystring.d.ts": { + "version": "9f633ecf3e065ff82c19eccab35c8aa1d6d5d1a49af282dc29ef5a64cca34164", + "signature": "9f633ecf3e065ff82c19eccab35c8aa1d6d5d1a49af282dc29ef5a64cca34164" + }, + "./node_modules/@types/node/readline.d.ts": { + "version": "6b2bb67b0942bcfce93e1d6fad5f70afd54940a2b13df7f311201fba54b2cbe9", + "signature": "6b2bb67b0942bcfce93e1d6fad5f70afd54940a2b13df7f311201fba54b2cbe9" + }, + "./node_modules/@types/node/repl.d.ts": { + "version": "dd3706b25d06fe23c73d16079e8c66ac775831ef419da00716bf2aee530a04a4", + "signature": "dd3706b25d06fe23c73d16079e8c66ac775831ef419da00716bf2aee530a04a4" + }, + "./node_modules/@types/node/stream.d.ts": { + "version": "d74b8e644da7415e3757a17a42b7f284597b577e3c87b80f4b3ba0cc2db1184f", + "signature": "d74b8e644da7415e3757a17a42b7f284597b577e3c87b80f4b3ba0cc2db1184f" + }, + "./node_modules/@types/node/string_decoder.d.ts": { + "version": "7e62aac2cc9c0710d772047ad89e8d7117f52592c791eb995ce1f865fedab432", + "signature": "7e62aac2cc9c0710d772047ad89e8d7117f52592c791eb995ce1f865fedab432" + }, + "./node_modules/@types/node/timers.d.ts": { + "version": "b40652bf8ce4a18133b31349086523b219724dca8df3448c1a0742528e7ad5b9", + "signature": "b40652bf8ce4a18133b31349086523b219724dca8df3448c1a0742528e7ad5b9" + }, + "./node_modules/@types/node/tls.d.ts": { + "version": "424bc64b2794d9280c1e1f4a3518ba9d285385a16d84753a6427bb469e582eca", + "signature": "424bc64b2794d9280c1e1f4a3518ba9d285385a16d84753a6427bb469e582eca" + }, + "./node_modules/@types/node/trace_events.d.ts": { + "version": "a77fdb357c78b70142b2fdbbfb72958d69e8f765fd2a3c69946c1018e89d4638", + "signature": "a77fdb357c78b70142b2fdbbfb72958d69e8f765fd2a3c69946c1018e89d4638" + }, + "./node_modules/@types/node/tty.d.ts": { + "version": "3c2ac350c3baa61fd2b1925844109e098f4376d0768a4643abc82754fd752748", + "signature": "3c2ac350c3baa61fd2b1925844109e098f4376d0768a4643abc82754fd752748" + }, + "./node_modules/@types/node/url.d.ts": { + "version": "826d48e49c905cedb906cbde6ccaf758827ff5867d4daa006b5a79e0fb489357", + "signature": "826d48e49c905cedb906cbde6ccaf758827ff5867d4daa006b5a79e0fb489357" + }, + "./node_modules/@types/node/util.d.ts": { + "version": "893d1b5dd98f1c01a0ec4122dfd7f774e0fa1560e1aa19e509c96ed543c6244e", + "signature": "893d1b5dd98f1c01a0ec4122dfd7f774e0fa1560e1aa19e509c96ed543c6244e" + }, + "./node_modules/@types/node/v8.d.ts": { + "version": "289be113bad7ee27ee7fa5b1e373c964c9789a5e9ed7db5ddcb631371120b953", + "signature": "289be113bad7ee27ee7fa5b1e373c964c9789a5e9ed7db5ddcb631371120b953" + }, + "./node_modules/@types/node/vm.d.ts": { + "version": "e4abb8eaa8a7d78236be0f8342404aab076668d20590209e32fdeb924588531e", + "signature": "e4abb8eaa8a7d78236be0f8342404aab076668d20590209e32fdeb924588531e" + }, + "./node_modules/@types/node/worker_threads.d.ts": { + "version": "1b4db6ed54916341a48bb81cfd9f910999b3bcd6b71c6a4c7416532a6908775d", + "signature": "1b4db6ed54916341a48bb81cfd9f910999b3bcd6b71c6a4c7416532a6908775d" + }, + "./node_modules/@types/node/zlib.d.ts": { + "version": "f409183966a1dd93d3a9cd1d54fbeb85c73101e87cd5b19467c5e37b252f3fd8", + "signature": "f409183966a1dd93d3a9cd1d54fbeb85c73101e87cd5b19467c5e37b252f3fd8" + }, + "./node_modules/@types/node/base.d.ts": { + "version": "5ff4ecfd544d596de3c8011a6d44c59443c85e1f99065095e556b15237eb39ac", + "signature": "5ff4ecfd544d596de3c8011a6d44c59443c85e1f99065095e556b15237eb39ac" + }, + "./node_modules/@types/node/ts3.2/fs.d.ts": { + "version": "12b2608d6074167c331c9c3c6994a57819f6ff934c7fd4527e23aabf56d4c8d1", + "signature": "12b2608d6074167c331c9c3c6994a57819f6ff934c7fd4527e23aabf56d4c8d1" + }, + "./node_modules/@types/node/ts3.2/util.d.ts": { + "version": "ffc1cd688606ad1ddb59a40e8f3defbde907af2a3402d1d9ddf69accb2903f07", + "signature": "ffc1cd688606ad1ddb59a40e8f3defbde907af2a3402d1d9ddf69accb2903f07" + }, + "./node_modules/@types/node/ts3.2/globals.d.ts": { + "version": "4926e99d2ad39c0bbd36f2d37cc8f52756bc7a5661ad7b12815df871a4b07ba1", + "signature": "4926e99d2ad39c0bbd36f2d37cc8f52756bc7a5661ad7b12815df871a4b07ba1" + }, + "./node_modules/@types/node/ts3.2/base.d.ts": { + "version": "8a70903bbbdad1d58e3936ca90b3ad993e54827ea324e20f2f63cef4e14e9d55", + "signature": "8a70903bbbdad1d58e3936ca90b3ad993e54827ea324e20f2f63cef4e14e9d55" + }, + "./node_modules/@types/node/assert.d.ts": { + "version": "f61a4062a627acbe5c4a9650319132ec8fa7fe2f276a7f40a056e59c2a877e04", + "signature": "f61a4062a627acbe5c4a9650319132ec8fa7fe2f276a7f40a056e59c2a877e04" + }, + "./node_modules/@types/node/ts3.2/index.d.ts": { + "version": "9522f3e35b412f2f17974b1431a1b18d06e0a8f614a0700c37220a4afb04afa8", + "signature": "9522f3e35b412f2f17974b1431a1b18d06e0a8f614a0700c37220a4afb04afa8" + }, + "./node_modules/@types/range-parser/index.d.ts": { + "version": "4e88b833be14c7f384e0dcd57bb30acd799e8e34d212635d693e41a75a71164b", + "signature": "4e88b833be14c7f384e0dcd57bb30acd799e8e34d212635d693e41a75a71164b" + }, + "./node_modules/@types/express-serve-static-core/index.d.ts": { + "version": "a3c58104e1f519cb211279ab6a0dc70e6232f7c7eb11b6a0ca0b43d7e3e72983", + "signature": "a3c58104e1f519cb211279ab6a0dc70e6232f7c7eb11b6a0ca0b43d7e3e72983" + }, + "./node_modules/@types/mime/index.d.ts": { + "version": "be27a64e821a3e5af838650e4aa25805c60f057d0c37a9762c378d19d364b3e6", + "signature": "be27a64e821a3e5af838650e4aa25805c60f057d0c37a9762c378d19d364b3e6" + }, + "./node_modules/@types/serve-static/index.d.ts": { + "version": "cdbae5083ef8f786069519405ca1f1e2ce72b9efebdf5e1931584fba747f3bc0", + "signature": "cdbae5083ef8f786069519405ca1f1e2ce72b9efebdf5e1931584fba747f3bc0" + }, + "./node_modules/@types/connect/index.d.ts": { + "version": "e6ffa74698f0a1d23e4223242ed7dcdb89d02bbbb063a1930e9f91d0385abe16", + "signature": "e6ffa74698f0a1d23e4223242ed7dcdb89d02bbbb063a1930e9f91d0385abe16" + }, + "./node_modules/@types/body-parser/index.d.ts": { + "version": "ebddbd167c2fabd0151f50e5df94ca6d845149c47521280d8867afe3429dd078", + "signature": "ebddbd167c2fabd0151f50e5df94ca6d845149c47521280d8867afe3429dd078" + }, + "./node_modules/@types/qs/index.d.ts": { + "version": "7bc3168fdda8512614c9b6627fbd356043e61070639879cf23d102265259730c", + "signature": "7bc3168fdda8512614c9b6627fbd356043e61070639879cf23d102265259730c" + }, + "./node_modules/@types/express/index.d.ts": { + "version": "ead1ed9dd4874f4907a506a31e4fe9c4e079b42816f6b7ea5016a6d5ddf2fde3", + "signature": "ead1ed9dd4874f4907a506a31e4fe9c4e079b42816f6b7ea5016a6d5ddf2fde3" + }, + "./src/Utils.ts": { + "version": "3fafe931d1756c86680c24af41a389419674bffacc5a2113e7bad6228aeca27a", + "signature": "2336cc1135d6c2625d134e4f9efd92bd7a8d032a46a6b07704955fc942ee2e60" + }, + "./src/HttpError.ts": { + "version": "4c20f2f3d3b94dce23f5a7e1f69f513418e54d5ad29dda562d8d5b83a8a4b26a", + "signature": "a3ad2414c8f96cc5a0133dd38723f942bea58067e7e284646f73d20e81351f21" + }, + "../node_modules/@types/nunjucks/index.d.ts": { + "version": "47081001316dd776632f5bf4954183ba40a0690d1dff832cc709685950e25471", + "signature": "47081001316dd776632f5bf4954183ba40a0690d1dff832cc709685950e25471" + }, + "../node_modules/@types/config/index.d.ts": { + "version": "a2841f04e5d6e69661720db979db826a07dd2c2c6b170fb5fb8ff2680692e922", + "signature": "a2841f04e5d6e69661720db979db826a07dd2c2c6b170fb5fb8ff2680692e922" + }, + "../node_modules/@types/uuid/interfaces.d.ts": { + "version": "5cc5d6f26a50072d51c4ea3a85ee65574b7fa2ae48261ae27b07014695638c50", + "signature": "5cc5d6f26a50072d51c4ea3a85ee65574b7fa2ae48261ae27b07014695638c50" + }, + "../node_modules/@types/uuid/index.d.ts": { + "version": "f961dd194a4ed86a12a6e651bd1fc10d1cea2084b4dbb1a2bb8f3af9ee03a964", + "signature": "f961dd194a4ed86a12a6e651bd1fc10d1cea2084b4dbb1a2bb8f3af9ee03a964" + }, + "../node_modules/@types/mysql/index.d.ts": { + "version": "c31e81b6cf25fee45088689e5043c6243284a7ac1ec9368094d901ea5602bd7b", + "signature": "c31e81b6cf25fee45088689e5043c6243284a7ac1ec9368094d901ea5602bd7b" + }, + "./src/db/Migration.ts": { + "version": "8561d53e8860d46b21bdbdac51e3d68a13a574cb37b6920989df2b6b78f8f371", + "signature": "15cb26bcb2cc6c96ef080c577563c71543e177f199ea5a247beff26ed754d9ed" + }, + "./src/db/MysqlConnectionManager.ts": { + "version": "055fbe99285d902e53ea0eb853696dcb2e35adeb942ce8da515a0be2df99b756", + "signature": "3e6e686f61efa3d2d3312b282bfb08ae6396618d8ff7ee8dee15cb25c5858bf7" + }, + "./src/db/Query.ts": { + "version": "a43192457b79127d344087091c80d4189964edf4ddc86ed476b12d176e22fc70", + "signature": "d37930d32d2842039847f68b7b40855622404378811df23f4d3eac7d15cbb896" + }, + "./src/db/Validator.ts": { + "version": "826ebd3a2060d1a07c14dcb14c41c11ff3ec7d252dc48a3f92744e21e0a76bf4", + "signature": "b279f5059a857fb54b3044e90179aa5f73429ce96be90970a4d94c1aea03aba9" + }, + "./src/Pagination.ts": { + "version": "23419feda468a0484fb8780cf80767efac9944791043c035e5a99772fe0080f1", + "signature": "6aea91ae324d18504957ff52a8c31bb61d15b9895e7bff53e5044f77e0146d1f" + }, + "./src/db/Model.ts": { + "version": "b48b098abf85a4bc11f5c2ccfe735edc3f9e9d808ba3de340961fbfb0a4e6e5f", + "signature": "44fbb4d4ec99995dd6da1283a1ced2f9e56dbb699ba0ab92792c583940f0d04f" + }, + "./src/models/Log.ts": { + "version": "306ff5f522fd37e6e19b207f9d82d147a56f4050ec66e2cb912d84cb6253fb77", + "signature": "fe0f4f3bef6db55a4dba56e4b229cb5abd2225af12fe217d38268e42f2308ae9" + }, + "./src/Logger.ts": { + "version": "37e9fda17789d37a59318f932373d0f7a91fb440c04ad127735535a42b447d03", + "signature": "543d96fd1f49c36dd6061439805a2b7bb91e50b2fa9e552d9ee7906b5d0cf01a" + }, + "../node_modules/@types/ws/index.d.ts": { + "version": "75ce9fa40c86cf9a4f0a546958cc0e5104bf53e408e0f2b71c3757a610adb6b4", + "signature": "75ce9fa40c86cf9a4f0a546958cc0e5104bf53e408e0f2b71c3757a610adb6b4" + }, + "./src/WebSocketListener.ts": { + "version": "ee4d3c2651d6c8e064dba83ba650d92e3a0bd07f9914638d68f43377635e848a", + "signature": "3d406b9aa15cc62f4365fb0ef64aa0f4118003d1166e20927bf299d6f30a07e8" + }, + "./src/ApplicationComponent.ts": { + "version": "23f6f0f5509fc12ddb5e0eec429d448be24fb254d7aef3b6e9a61cf90e797d63", + "signature": "c09ebb6934e80943c2f3699fd8bf29d012281049af1c7f5af576e57fefc0f8d7" + }, + "./src/Controller.ts": { + "version": "2a243e8b262491c3c6ed7f50a87d64d063b964d5e52cc210d36876a579f8b75d", + "signature": "9aee25f9c3c8b8f7d12d49f9e357afe668608a43a2edbecce146829ef028a60a" + }, + "./src/Application.ts": { + "version": "4ece554b602b37717c7ffa073555d58445036b3d8022557ce87c63c294d9a10d", + "signature": "29edd84f74afdcf8d07c6e76f4aa5c69dc883310b5f7612a2f10bc1dbf0dbf63" + }, + "../node_modules/@types/nodemailer/lib/dkim/index.d.ts": { + "version": "971b6006a4610efd734e051f5d1421f87bc0c73bfc3cd205819236d497cba1e4", + "signature": "971b6006a4610efd734e051f5d1421f87bc0c73bfc3cd205819236d497cba1e4" + }, + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts": { + "version": "d9be0e7047e30df44cafac456f18dd3f43af529225ad747c7330e835da6b370c", + "signature": "d9be0e7047e30df44cafac456f18dd3f43af529225ad747c7330e835da6b370c" + }, + "../node_modules/@types/nodemailer/lib/xoauth2.d.ts": { + "version": "a9d32ef46fa1075bfeff4a4ab96c1331254558865ca9c7bf383712baa297f065", + "signature": "a9d32ef46fa1075bfeff4a4ab96c1331254558865ca9c7bf383712baa297f065" + }, + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts": { + "version": "bf54271e59aa6df4670631b40b7fc0666e8ac0978fae18f96ed99f37fb8b3936", + "signature": "bf54271e59aa6df4670631b40b7fc0666e8ac0978fae18f96ed99f37fb8b3936" + }, + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts": { + "version": "689b62c8e45e8f63dacf3a6de1655e06d524cf853f9a96f9446461553c49bd84", + "signature": "689b62c8e45e8f63dacf3a6de1655e06d524cf853f9a96f9446461553c49bd84" + }, + "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts": { + "version": "559d3b5e23b28a26355233cd54b496701c6837fd9b539511158e44c028d7b8c5", + "signature": "559d3b5e23b28a26355233cd54b496701c6837fd9b539511158e44c028d7b8c5" + }, + "../node_modules/@types/nodemailer/lib/shared.d.ts": { + "version": "06fdb97fb4733b9ff5a24fc3bf9c0713c93231d361f27ea95ed05bfab679ac61", + "signature": "06fdb97fb4733b9ff5a24fc3bf9c0713c93231d361f27ea95ed05bfab679ac61" + }, + "../node_modules/@types/nodemailer/lib/json-transport.d.ts": { + "version": "f5af2c4bee48b94b4a247464406d600b5232036df7b835d16504f84303977474", + "signature": "f5af2c4bee48b94b4a247464406d600b5232036df7b835d16504f84303977474" + }, + "../node_modules/@types/nodemailer/lib/sendmail-transport/index.d.ts": { + "version": "2739f287a5d26386849a9e1fd05421ece3366ae533f7569654ab73cc74d30aae", + "signature": "2739f287a5d26386849a9e1fd05421ece3366ae533f7569654ab73cc74d30aae" + }, + "../node_modules/@types/nodemailer/lib/ses-transport.d.ts": { + "version": "dd335f22e01cf7abb3445c837e2a8a94650fc23b37572876581d36c2b8f96cb8", + "signature": "dd335f22e01cf7abb3445c837e2a8a94650fc23b37572876581d36c2b8f96cb8" + }, + "../node_modules/@types/nodemailer/lib/smtp-pool/index.d.ts": { + "version": "f44c29cd43b1b2ebcb49b51b3315c85d00fd5ed66b80a7c7a629ad27132bf213", + "signature": "f44c29cd43b1b2ebcb49b51b3315c85d00fd5ed66b80a7c7a629ad27132bf213" + }, + "../node_modules/@types/nodemailer/lib/smtp-transport.d.ts": { + "version": "b5a4a00d0d26d9ca9ce666ea46c2cf84f12139aa4e57b648d22c33362e25554a", + "signature": "b5a4a00d0d26d9ca9ce666ea46c2cf84f12139aa4e57b648d22c33362e25554a" + }, + "../node_modules/@types/nodemailer/lib/stream-transport.d.ts": { + "version": "d10c3e41c9d07022049b732e9b5e8d16a5e584393cfa589b299ac29630ab671a", + "signature": "d10c3e41c9d07022049b732e9b5e8d16a5e584393cfa589b299ac29630ab671a" + }, + "../node_modules/@types/nodemailer/index.d.ts": { + "version": "7c9ad24b7763a35bc2b94f495ee80a4f08f5d7f6fa677526c9931af90fdf6da5", + "signature": "7c9ad24b7763a35bc2b94f495ee80a4f08f5d7f6fa677526c9931af90fdf6da5" + }, + "../node_modules/@types/mjml/index.d.ts": { + "version": "29e6dd4f18688f445ad9d23a358c37e55493894768940449c28ddad2bc118aab", + "signature": "29e6dd4f18688f445ad9d23a358c37e55493894768940449c28ddad2bc118aab" + }, + "./src/Mail.ts": { + "version": "a321991e2afb9ffb308a93936b46edcdc3102e3a18cb55ef23b1d0dc0549cca1", + "signature": "ad7c8edfa4c0e9e5d8325228af68fc92d018fa2cf702dcb5cd793956cabf1036" + }, + "./src/index.ts": { + "version": "21dac02d30e8c4266c081894aa6d0938b620d7ba06c0d3632ab790ccd517be5f", + "signature": "22e5bc2b989e4d6c621ac438700ed6567b63dcc6ff67bffb54e0ede2ef45e721" + }, + "./src/components/CsrfProtectionComponent.ts": { + "version": "d2ac8a26b66bd7c9de6e85eb0fa31223f786636f129be51098e1121f12e91e32", + "signature": "7a208416ae5bfff4bd1f0fe507fdbb23b2026149b1e70c6dd5d52efbf834f049" + }, + "./src/components/ExpressAppComponent.ts": { + "version": "0bf2a47d0497ea6ba5231e5020ea560eafd6272045080f0407b39b42417eb486", + "signature": "1893d96ff6b9d0cc83f76612c4bf48e999e361ffecb6b68b79d908eec4657f80" + }, + "./src/components/FormHelperComponent.ts": { + "version": "6cf21d88314fafeb0499a1b926c9b9ca8f475d7c92c15ca3a06ce40cccb1e1b3", + "signature": "8993db64158ef1437c674fad5f62785b854f777a02273eaa1e3eafd54e670288" + }, + "../node_modules/@types/on-finished/index.d.ts": { + "version": "c69767317aec528b574762b18727db85eef7cf66f33617cc0ee905cbe5a43d97", + "signature": "c69767317aec528b574762b18727db85eef7cf66f33617cc0ee905cbe5a43d97" + }, + "./src/components/LogRequestsComponent.ts": { + "version": "770580c0d8eb417d27b035cba14d18ecc137a72f2a7b2efc4b4e8c7fb94898e6", + "signature": "bdcfd88a151dbdba6a995f66555318bfa466c0b520ebaecbfa4174a7b6107c57" + }, + "./src/components/MailComponent.ts": { + "version": "91f2f87f4c14bdbce5a4a0636f0982482bb7e09390f68fbbc7d7a9ab77cc3388", + "signature": "4051b829aa2900c112bf181f96346150ddb248cb3c0a9395cb592d1f4e46a177" + }, + "./src/components/MaintenanceComponent.ts": { + "version": "0cb6d08367b949a54920be736a0ca7e7d0bd48219082a9743afc7f669f5f4c9a", + "signature": "94f0546ca6c9f8255740ecc19c3883310bec540012c28e9652c10ffb477ac8dc" + }, + "./src/components/MysqlComponent.ts": { + "version": "842acfffb204031d1f449a32f36448f2289e7b979d7438c6922932cfdc3bce66", + "signature": "140c141b201786ff49458f1cbcce2b77052881d168f7ae79d0582185b9aeedee" + }, + "./src/components/RedirectBackComponent.ts": { + "version": "aeed6a141a3295545db9a40642601a3002a75c47ce4fc7803d8103cf03f1707f", + "signature": "ed921b450bfc547bd1ea2edbc0e77d71505c432d8ca141c62a5e4883849eb54c" + }, + "../node_modules/@types/redis/ts3.1/index.d.ts": { + "version": "c09db611897b893f45fc71ba3c8f0ad2b578911f5454b0063cd099d7d7c82ad5", + "signature": "c09db611897b893f45fc71ba3c8f0ad2b578911f5454b0063cd099d7d7c82ad5" + }, + "../node_modules/@types/express/index.d.ts": { + "version": "ead1ed9dd4874f4907a506a31e4fe9c4e079b42816f6b7ea5016a6d5ddf2fde3", + "signature": "ead1ed9dd4874f4907a506a31e4fe9c4e079b42816f6b7ea5016a6d5ddf2fde3" + }, + "../node_modules/@types/express-session/index.d.ts": { + "version": "3e03ea3c4d568a10e41f540bc891c5fb42c036a430187132e599176f7974eaf7", + "signature": "3e03ea3c4d568a10e41f540bc891c5fb42c036a430187132e599176f7974eaf7" + }, + "../node_modules/@types/ioredis/index.d.ts": { + "version": "1b5e15b9e676645123c3f17404ac4736e4dd5eba8189a572b23a09a569989d8f", + "signature": "1b5e15b9e676645123c3f17404ac4736e4dd5eba8189a572b23a09a569989d8f" + }, + "../node_modules/@types/connect-redis/index.d.ts": { + "version": "36b01abb39b1ea4a1081cc4347e4ea09878e015e2ff66bdd1ad25e17f318c93a", + "signature": "36b01abb39b1ea4a1081cc4347e4ea09878e015e2ff66bdd1ad25e17f318c93a" + }, + "./src/components/RedisComponent.ts": { + "version": "c6b95081fc7b4ece4a2b3883e478bfffddb1815fc11b2bf75297056f9c47454c", + "signature": "ed4412eae1fff66afd3f714dd1004aa6d7cb69229fe67e1ce192820c373ec191" + }, + "./src/components/ServeStaticDirectoryComponent.ts": { + "version": "3afaf06a8cadbcc74427bf9e7b987b9cc9413c503df01b8f3f58c7c975cd2dd6", + "signature": "b01e48eed7e04d1f10b2d3f9df5c87b08fd86bc77c5dd1dca7a8ced23f369841" + }, + "../node_modules/@types/connect-flash/index.d.ts": { + "version": "eb6dd47dbc0800f57073a9d5388e0e8cffdc34cc5f3910d8311cdf4a799d5eaa", + "signature": "eb6dd47dbc0800f57073a9d5388e0e8cffdc34cc5f3910d8311cdf4a799d5eaa" + }, + "./src/components/SessionComponent.ts": { + "version": "0ca82dd47213589b8cb879aa25f456157de6d1984ca7e7b157bfd63598c570bb", + "signature": "0b026cff1f2e9cd1e4f22be20024b1cf6c22478229a25adb77dc7086a3438dd4" + }, + "../node_modules/@types/cookie/index.d.ts": { + "version": "90643a7d80d87f379ec4c6448a4b5e473b7fb64062ac649a61d93b3a1a8b2180", + "signature": "90643a7d80d87f379ec4c6448a4b5e473b7fb64062ac649a61d93b3a1a8b2180" + }, + "../node_modules/@types/cookie-parser/index.d.ts": { + "version": "8d77ed4e39114c32edc2e35b683b6f54a6b3292ecdf392e4bfc5f726734955d8", + "signature": "8d77ed4e39114c32edc2e35b683b6f54a6b3292ecdf392e4bfc5f726734955d8" + }, + "./src/components/WebSocketServerComponent.ts": { + "version": "b3705ed6eee728898b2a34b5bbf731c86dceefb9ae2a38a8a40efc8f4b57b759", + "signature": "752b5d1937d8bc6a5e9146dda0bf0de9d9a2470735a86a7471a0de8e06dc3f38" + }, + "./src/migrations/CreateLogsTable.ts": { + "version": "943eae01421342827dfb1e345f225da23605264c72a71fa1b1bff23a80746672", + "signature": "f773ac0c4f5a4182882e6aba40dae5613738f0931b3affe712fdeb7d2b9953c7" + }, + "./src/migrations/CreateMigrationsTable.ts": { + "version": "53c71413d70f75862c2c2b56ecddbf01e592cf7106b5182969f762790e2bbf20", + "signature": "604690ec96d6d95d9d9a3b3662caf186f87c49d8e88a3a36bf63a29449fd0a9c" + }, + "./src/types/Express.d.ts": { + "version": "ace3d52e1a42f5ba8324fba29ca2327a1e0789b8c1a2a51e04fa537254fdc6b9", + "signature": "ace3d52e1a42f5ba8324fba29ca2327a1e0789b8c1a2a51e04fa537254fdc6b9" + } + }, + "options": { + "module": 1, + "esModuleInterop": true, + "outDir": "./dist", + "target": 2, + "strict": true, + "lib": [ + "lib.es2020.d.ts" + ], + "typeRoots": [ + "./node_modules/@types", + "./src/types" + ], + "composite": true, + "rootDir": "./src", + "declaration": true, + "declarationMap": true, + "configFilePath": "./tsconfig.json" + }, + "referencedMap": { + "./node_modules/typescript/lib/lib.es5.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2016.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2017.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2018.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2019.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2020.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.core.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.collection.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.generator.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.iterable.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.promise.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.proxy.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.reflect.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.symbol.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2016.array.include.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2017.object.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2017.string.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2017.intl.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2018.intl.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2018.promise.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2018.regexp.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2019.array.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2019.object.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2019.string.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2019.symbol.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2020.bigint.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2020.promise.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2020.string.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.esnext.intl.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/globals.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/async_hooks.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/buffer.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/events/index.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/child_process.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/cluster.d.ts": [ + "./node_modules/@types/node/child_process.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/console.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/constants.d.ts": [ + "./node_modules/@types/node/os.d.ts", + "./node_modules/@types/node/crypto.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/crypto.d.ts": [ + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/dgram.d.ts": [ + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/dns.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/dns.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/domain.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/events.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/fs.d.ts": [ + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/http.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/http2.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/tls.d.ts", + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/https.d.ts": [ + "./node_modules/@types/node/tls.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/inspector.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/module.d.ts": [ + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/net.d.ts": [ + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/dns.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/os.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/path.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/perf_hooks.d.ts": [ + "./node_modules/@types/node/async_hooks.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/process.d.ts": [ + "./node_modules/@types/node/tty.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/punycode.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/querystring.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/readline.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/repl.d.ts": [ + "./node_modules/@types/node/readline.d.ts", + "./node_modules/@types/node/vm.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/stream.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/string_decoder.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/timers.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/tls.d.ts": [ + "./node_modules/@types/node/crypto.d.ts", + "./node_modules/@types/node/dns.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/trace_events.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/tty.d.ts": [ + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/url.d.ts": [ + "./node_modules/@types/node/querystring.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/util.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/v8.d.ts": [ + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/vm.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/worker_threads.d.ts": [ + "./node_modules/@types/node/vm.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/zlib.d.ts": [ + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/base.d.ts": [ + "./node_modules/@types/node/globals.d.ts", + "./node_modules/@types/node/async_hooks.d.ts", + "./node_modules/@types/node/buffer.d.ts", + "./node_modules/@types/node/child_process.d.ts", + "./node_modules/@types/node/cluster.d.ts", + "./node_modules/@types/node/console.d.ts", + "./node_modules/@types/node/constants.d.ts", + "./node_modules/@types/node/crypto.d.ts", + "./node_modules/@types/node/dgram.d.ts", + "./node_modules/@types/node/dns.d.ts", + "./node_modules/@types/node/domain.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/http2.d.ts", + "./node_modules/@types/node/https.d.ts", + "./node_modules/@types/node/inspector.d.ts", + "./node_modules/@types/node/module.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/os.d.ts", + "./node_modules/@types/node/path.d.ts", + "./node_modules/@types/node/perf_hooks.d.ts", + "./node_modules/@types/node/process.d.ts", + "./node_modules/@types/node/punycode.d.ts", + "./node_modules/@types/node/querystring.d.ts", + "./node_modules/@types/node/readline.d.ts", + "./node_modules/@types/node/repl.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/string_decoder.d.ts", + "./node_modules/@types/node/timers.d.ts", + "./node_modules/@types/node/tls.d.ts", + "./node_modules/@types/node/trace_events.d.ts", + "./node_modules/@types/node/tty.d.ts", + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/v8.d.ts", + "./node_modules/@types/node/vm.d.ts", + "./node_modules/@types/node/worker_threads.d.ts", + "./node_modules/@types/node/zlib.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/ts3.2/fs.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/ts3.2/util.d.ts": [ + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts" + ], + "./node_modules/@types/node/ts3.2/globals.d.ts": [ + "./node_modules/@types/node/globals.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/ts3.2/base.d.ts": [ + "./node_modules/@types/node/base.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts", + "./node_modules/@types/node/ts3.2/globals.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/util.d.ts" + ], + "./node_modules/@types/node/assert.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/ts3.2/index.d.ts": [ + "./node_modules/@types/node/ts3.2/base.d.ts", + "./node_modules/@types/node/assert.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/range-parser/index.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/express-serve-static-core/index.d.ts": [ + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/range-parser/index.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/mime/index.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/serve-static/index.d.ts": [ + "./node_modules/@types/express-serve-static-core/index.d.ts", + "./node_modules/@types/mime/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/connect/index.d.ts": [ + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/body-parser/index.d.ts": [ + "./node_modules/@types/connect/index.d.ts", + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/qs/index.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/express/index.d.ts": [ + "./node_modules/@types/body-parser/index.d.ts", + "./node_modules/@types/serve-static/index.d.ts", + "./node_modules/@types/express-serve-static-core/index.d.ts", + "./node_modules/@types/qs/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/Utils.ts": [ + "./node_modules/@types/node/crypto.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/HttpError.ts": [ + "./src/Utils.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nunjucks/index.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/config/index.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/uuid/interfaces.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/uuid/index.d.ts": [ + "../node_modules/@types/uuid/interfaces.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/mysql/index.d.ts": [ + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/tls.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/db/Migration.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/db/MysqlConnectionManager.ts": [ + "../node_modules/@types/mysql/index.d.ts", + "../node_modules/@types/config/index.d.ts", + "./src/db/Migration.ts", + "./src/Logger.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/db/Query.ts": [ + "./src/db/MysqlConnectionManager.ts", + "../node_modules/@types/mysql/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/db/Validator.ts": [ + "./src/db/Model.ts", + "./src/db/Query.ts", + "../node_modules/@types/mysql/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/Pagination.ts": [ + "./src/db/Model.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/db/Model.ts": [ + "./src/db/MysqlConnectionManager.ts", + "./src/db/Validator.ts", + "../node_modules/@types/mysql/index.d.ts", + "./src/db/Query.ts", + "./node_modules/@types/express/index.d.ts", + "./src/Pagination.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/models/Log.ts": [ + "./src/db/Model.ts", + "./src/Logger.ts", + "./src/db/Validator.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/Logger.ts": [ + "../node_modules/@types/config/index.d.ts", + "../node_modules/@types/uuid/index.d.ts", + "./src/models/Log.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/ws/index.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/https.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/zlib.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/WebSocketListener.ts": [ + "../node_modules/@types/ws/index.d.ts", + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/ApplicationComponent.ts": [ + "./node_modules/@types/express/index.d.ts", + "./src/Logger.ts", + "./src/Utils.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/Controller.ts": [ + "./node_modules/@types/express/index.d.ts", + "./node_modules/@types/express-serve-static-core/index.d.ts", + "../node_modules/@types/config/index.d.ts", + "./src/Logger.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/Application.ts": [ + "./node_modules/@types/express/index.d.ts", + "./src/HttpError.ts", + "../node_modules/@types/nunjucks/index.d.ts", + "./src/Logger.ts", + "./src/WebSocketListener.ts", + "./src/ApplicationComponent.ts", + "./src/Controller.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/dkim/index.d.ts": [ + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts": [ + "./node_modules/@types/node/stream.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/xoauth2.d.ts": [ + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/stream.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/url.d.ts", + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/dkim/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", + "../node_modules/@types/nodemailer/lib/xoauth2.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts": [ + "./node_modules/@types/node/stream.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/tls.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "../node_modules/@types/nodemailer/lib/xoauth2.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/shared.d.ts": [ + "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/json-transport.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/sendmail-transport/index.d.ts": [ + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/ses-transport.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/smtp-pool/index.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/smtp-transport.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/stream.d.ts", + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", + "../node_modules/@types/nodemailer/lib/xoauth2.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/stream-transport.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/stream.d.ts", + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/index.d.ts": [ + "../node_modules/@types/nodemailer/lib/json-transport.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/sendmail-transport/index.d.ts", + "../node_modules/@types/nodemailer/lib/ses-transport.d.ts", + "../node_modules/@types/nodemailer/lib/smtp-pool/index.d.ts", + "../node_modules/@types/nodemailer/lib/smtp-transport.d.ts", + "../node_modules/@types/nodemailer/lib/stream-transport.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/mjml/index.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/Mail.ts": [ + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/config/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nunjucks/index.d.ts", + "./node_modules/@types/node/util.d.ts", + "./src/Utils.ts", + "../node_modules/@types/mjml/index.d.ts", + "./node_modules/@types/node/querystring.d.ts", + "./src/Logger.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/index.ts": [ + "./src/ApplicationComponent.ts", + "./src/Mail.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/CsrfProtectionComponent.ts": [ + "./src/ApplicationComponent.ts", + "./node_modules/@types/express/index.d.ts", + "./node_modules/@types/node/crypto.d.ts", + "./src/HttpError.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/ExpressAppComponent.ts": [ + "./src/ApplicationComponent.ts", + "./node_modules/@types/express/index.d.ts", + "./src/Logger.ts", + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/FormHelperComponent.ts": [ + "./src/ApplicationComponent.ts", + "./node_modules/@types/express/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/on-finished/index.d.ts": [ + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/LogRequestsComponent.ts": [ + "./src/ApplicationComponent.ts", + "../node_modules/@types/on-finished/index.d.ts", + "./src/Logger.ts", + "./node_modules/@types/express/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/MailComponent.ts": [ + "./src/ApplicationComponent.ts", + "./node_modules/@types/express/index.d.ts", + "./src/Mail.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/MaintenanceComponent.ts": [ + "./src/ApplicationComponent.ts", + "./node_modules/@types/express/index.d.ts", + "./src/HttpError.ts", + "./src/Application.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/MysqlComponent.ts": [ + "./src/ApplicationComponent.ts", + "./node_modules/@types/express/index.d.ts", + "./src/db/MysqlConnectionManager.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/RedirectBackComponent.ts": [ + "./src/ApplicationComponent.ts", + "./node_modules/@types/express/index.d.ts", + "../node_modules/@types/on-finished/index.d.ts", + "./src/Logger.ts", + "./src/HttpError.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/redis/ts3.1/index.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/express/index.d.ts": [ + "./node_modules/@types/body-parser/index.d.ts", + "./node_modules/@types/serve-static/index.d.ts", + "./node_modules/@types/express-serve-static-core/index.d.ts", + "./node_modules/@types/qs/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/express-session/index.d.ts": [ + "./node_modules/@types/express/index.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/ioredis/index.d.ts": [ + "./node_modules/@types/node/tls.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/connect-redis/index.d.ts": [ + "./node_modules/@types/express/index.d.ts", + "../node_modules/@types/express-session/index.d.ts", + "../node_modules/@types/ioredis/index.d.ts", + "../node_modules/@types/redis/ts3.1/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/RedisComponent.ts": [ + "./src/ApplicationComponent.ts", + "./node_modules/@types/express/index.d.ts", + "../node_modules/@types/redis/ts3.1/index.d.ts", + "../node_modules/@types/config/index.d.ts", + "./src/Logger.ts", + "../node_modules/@types/express-session/index.d.ts", + "../node_modules/@types/connect-redis/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/ServeStaticDirectoryComponent.ts": [ + "./src/ApplicationComponent.ts", + "./node_modules/@types/express/index.d.ts", + "./node_modules/@types/express-serve-static-core/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/connect-flash/index.d.ts": [ + "./node_modules/@types/express/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/SessionComponent.ts": [ + "./src/ApplicationComponent.ts", + "../node_modules/@types/express-session/index.d.ts", + "../node_modules/@types/config/index.d.ts", + "./src/components/RedisComponent.ts", + "../node_modules/@types/connect-flash/index.d.ts", + "./node_modules/@types/express/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/cookie/index.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/cookie-parser/index.d.ts": [ + "./node_modules/@types/express/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/WebSocketServerComponent.ts": [ + "./src/ApplicationComponent.ts", + "./node_modules/@types/express/index.d.ts", + "../node_modules/@types/ws/index.d.ts", + "./src/Logger.ts", + "../node_modules/@types/cookie/index.d.ts", + "../node_modules/@types/cookie-parser/index.d.ts", + "../node_modules/@types/config/index.d.ts", + "./src/components/ExpressAppComponent.ts", + "./src/Application.ts", + "./src/components/RedisComponent.ts", + "./src/WebSocketListener.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/migrations/CreateLogsTable.ts": [ + "./src/db/Migration.ts", + "./src/db/MysqlConnectionManager.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/migrations/CreateMigrationsTable.ts": [ + "./src/db/Migration.ts", + "./src/db/MysqlConnectionManager.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/types/Express.d.ts": [ + "../node_modules/@types/nunjucks/index.d.ts", + "./src/db/Model.ts", + "./node_modules/@types/express-serve-static-core/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ] + }, + "exportedModulesMap": { + "./node_modules/typescript/lib/lib.es5.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2016.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2017.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2018.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2019.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2020.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.core.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.collection.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.generator.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.iterable.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.promise.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.proxy.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.reflect.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.symbol.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2016.array.include.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2017.object.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2017.string.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2017.intl.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2018.intl.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2018.promise.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2018.regexp.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2019.array.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2019.object.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2019.string.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2019.symbol.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2020.bigint.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2020.promise.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2020.string.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/typescript/lib/lib.esnext.intl.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/globals.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/async_hooks.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/buffer.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/events/index.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/child_process.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/cluster.d.ts": [ + "./node_modules/@types/node/child_process.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/console.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/constants.d.ts": [ + "./node_modules/@types/node/os.d.ts", + "./node_modules/@types/node/crypto.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/crypto.d.ts": [ + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/dgram.d.ts": [ + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/dns.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/dns.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/domain.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/events.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/fs.d.ts": [ + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/http.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/http2.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/tls.d.ts", + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/https.d.ts": [ + "./node_modules/@types/node/tls.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/inspector.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/module.d.ts": [ + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/net.d.ts": [ + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/dns.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/os.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/path.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/perf_hooks.d.ts": [ + "./node_modules/@types/node/async_hooks.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/process.d.ts": [ + "./node_modules/@types/node/tty.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/punycode.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/querystring.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/readline.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/repl.d.ts": [ + "./node_modules/@types/node/readline.d.ts", + "./node_modules/@types/node/vm.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/stream.d.ts": [ + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/string_decoder.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/timers.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/tls.d.ts": [ + "./node_modules/@types/node/crypto.d.ts", + "./node_modules/@types/node/dns.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/trace_events.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/tty.d.ts": [ + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/url.d.ts": [ + "./node_modules/@types/node/querystring.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/util.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/v8.d.ts": [ + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/vm.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/worker_threads.d.ts": [ + "./node_modules/@types/node/vm.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/zlib.d.ts": [ + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/base.d.ts": [ + "./node_modules/@types/node/globals.d.ts", + "./node_modules/@types/node/async_hooks.d.ts", + "./node_modules/@types/node/buffer.d.ts", + "./node_modules/@types/node/child_process.d.ts", + "./node_modules/@types/node/cluster.d.ts", + "./node_modules/@types/node/console.d.ts", + "./node_modules/@types/node/constants.d.ts", + "./node_modules/@types/node/crypto.d.ts", + "./node_modules/@types/node/dgram.d.ts", + "./node_modules/@types/node/dns.d.ts", + "./node_modules/@types/node/domain.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/http2.d.ts", + "./node_modules/@types/node/https.d.ts", + "./node_modules/@types/node/inspector.d.ts", + "./node_modules/@types/node/module.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/os.d.ts", + "./node_modules/@types/node/path.d.ts", + "./node_modules/@types/node/perf_hooks.d.ts", + "./node_modules/@types/node/process.d.ts", + "./node_modules/@types/node/punycode.d.ts", + "./node_modules/@types/node/querystring.d.ts", + "./node_modules/@types/node/readline.d.ts", + "./node_modules/@types/node/repl.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/string_decoder.d.ts", + "./node_modules/@types/node/timers.d.ts", + "./node_modules/@types/node/tls.d.ts", + "./node_modules/@types/node/trace_events.d.ts", + "./node_modules/@types/node/tty.d.ts", + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/v8.d.ts", + "./node_modules/@types/node/vm.d.ts", + "./node_modules/@types/node/worker_threads.d.ts", + "./node_modules/@types/node/zlib.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/ts3.2/fs.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/ts3.2/util.d.ts": [ + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts" + ], + "./node_modules/@types/node/ts3.2/globals.d.ts": [ + "./node_modules/@types/node/globals.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/ts3.2/base.d.ts": [ + "./node_modules/@types/node/base.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts", + "./node_modules/@types/node/ts3.2/globals.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/util.d.ts" + ], + "./node_modules/@types/node/assert.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/node/ts3.2/index.d.ts": [ + "./node_modules/@types/node/ts3.2/base.d.ts", + "./node_modules/@types/node/assert.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/range-parser/index.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/express-serve-static-core/index.d.ts": [ + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/range-parser/index.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/mime/index.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/serve-static/index.d.ts": [ + "./node_modules/@types/express-serve-static-core/index.d.ts", + "./node_modules/@types/mime/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/connect/index.d.ts": [ + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/body-parser/index.d.ts": [ + "./node_modules/@types/connect/index.d.ts", + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/qs/index.d.ts": [ + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./node_modules/@types/express/index.d.ts": [ + "./node_modules/@types/body-parser/index.d.ts", + "./node_modules/@types/serve-static/index.d.ts", + "./node_modules/@types/express-serve-static-core/index.d.ts", + "./node_modules/@types/qs/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/HttpError.ts": [ + "./src/Utils.ts" + ], + "../node_modules/@types/nunjucks/index.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/config/index.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/uuid/interfaces.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/uuid/index.d.ts": [ + "../node_modules/@types/uuid/interfaces.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/mysql/index.d.ts": [ + "../node_modules/@types/node/stream.d.ts", + "../node_modules/@types/node/tls.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/db/MysqlConnectionManager.ts": [ + "../node_modules/@types/mysql/index.d.ts", + "./src/db/Migration.ts" + ], + "./src/db/Query.ts": [ + "../node_modules/@types/mysql/index.d.ts", + "./src/db/MysqlConnectionManager.ts" + ], + "./src/db/Validator.ts": [ + "../node_modules/@types/mysql/index.d.ts", + "./src/db/Model.ts", + "./src/db/Query.ts" + ], + "./src/Pagination.ts": [ + "./src/db/Model.ts" + ], + "./src/db/Model.ts": [ + "./node_modules/@types/express/index.d.ts", + "./src/db/Query.ts", + "./src/db/Validator.ts", + "../node_modules/@types/mysql/index.d.ts" + ], + "./src/models/Log.ts": [ + "./src/Logger.ts", + "./src/db/Model.ts" + ], + "../node_modules/@types/ws/index.d.ts": [ + "../node_modules/@types/node/events.d.ts", + "../node_modules/@types/node/http.d.ts", + "../node_modules/@types/node/https.d.ts", + "../node_modules/@types/node/net.d.ts", + "../node_modules/@types/node/url.d.ts", + "../node_modules/@types/node/zlib.d.ts", + "../node_modules/@types/node/stream.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/WebSocketListener.ts": [ + "../node_modules/@types/ws/index.d.ts", + "./node_modules/@types/node/http.d.ts" + ], + "./src/ApplicationComponent.ts": [ + "./node_modules/@types/express/index.d.ts" + ], + "./src/Controller.ts": [ + "./node_modules/@types/express/index.d.ts", + "./node_modules/@types/express-serve-static-core/index.d.ts" + ], + "./src/Application.ts": [ + "./src/Controller.ts", + "./src/WebSocketListener.ts", + "./src/ApplicationComponent.ts" + ], + "../node_modules/@types/nodemailer/lib/dkim/index.d.ts": [ + "../node_modules/@types/node/stream.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts": [ + "../node_modules/@types/node/stream.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/xoauth2.d.ts": [ + "../node_modules/@types/node/http.d.ts", + "../node_modules/@types/node/stream.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts": [ + "../node_modules/@types/node/events.d.ts", + "../node_modules/@types/node/net.d.ts", + "../node_modules/@types/node/stream.d.ts", + "../node_modules/@types/node/url.d.ts", + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/dkim/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", + "../node_modules/@types/nodemailer/lib/xoauth2.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts": [ + "../node_modules/@types/node/stream.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts": [ + "../node_modules/@types/node/events.d.ts", + "../node_modules/@types/node/net.d.ts", + "../node_modules/@types/node/stream.d.ts", + "../node_modules/@types/node/tls.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "../node_modules/@types/nodemailer/lib/xoauth2.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/shared.d.ts": [ + "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", + "../node_modules/@types/node/stream.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/json-transport.d.ts": [ + "../node_modules/@types/node/events.d.ts", + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/sendmail-transport/index.d.ts": [ + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/ses-transport.d.ts": [ + "../node_modules/@types/node/events.d.ts", + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/smtp-pool/index.d.ts": [ + "../node_modules/@types/node/events.d.ts", + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/smtp-transport.d.ts": [ + "../node_modules/@types/node/events.d.ts", + "../node_modules/@types/node/stream.d.ts", + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", + "../node_modules/@types/nodemailer/lib/xoauth2.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/lib/stream-transport.d.ts": [ + "../node_modules/@types/node/events.d.ts", + "../node_modules/@types/node/stream.d.ts", + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/nodemailer/index.d.ts": [ + "../node_modules/@types/nodemailer/lib/json-transport.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/sendmail-transport/index.d.ts", + "../node_modules/@types/nodemailer/lib/ses-transport.d.ts", + "../node_modules/@types/nodemailer/lib/smtp-pool/index.d.ts", + "../node_modules/@types/nodemailer/lib/smtp-transport.d.ts", + "../node_modules/@types/nodemailer/lib/stream-transport.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/mjml/index.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/Mail.ts": [ + "../node_modules/@types/nodemailer/index.d.ts" + ], + "./src/components/CsrfProtectionComponent.ts": [ + "./node_modules/@types/express/index.d.ts", + "./src/ApplicationComponent.ts" + ], + "./src/components/ExpressAppComponent.ts": [ + "./node_modules/@types/express/index.d.ts", + "./node_modules/@types/node/http.d.ts", + "./src/ApplicationComponent.ts" + ], + "./src/components/FormHelperComponent.ts": [ + "./node_modules/@types/express/index.d.ts", + "./src/ApplicationComponent.ts" + ], + "../node_modules/@types/on-finished/index.d.ts": [ + "../node_modules/@types/node/http.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/LogRequestsComponent.ts": [ + "./node_modules/@types/express/index.d.ts", + "./src/ApplicationComponent.ts" + ], + "./src/components/MailComponent.ts": [ + "./node_modules/@types/express/index.d.ts", + "./src/ApplicationComponent.ts" + ], + "./src/components/MaintenanceComponent.ts": [ + "./src/Application.ts", + "./node_modules/@types/express/index.d.ts", + "./src/ApplicationComponent.ts" + ], + "./src/components/MysqlComponent.ts": [ + "./node_modules/@types/express/index.d.ts", + "./src/ApplicationComponent.ts" + ], + "./src/components/RedirectBackComponent.ts": [ + "./node_modules/@types/express/index.d.ts", + "./src/ApplicationComponent.ts" + ], + "../node_modules/@types/redis/ts3.1/index.d.ts": [ + "../node_modules/@types/node/events.d.ts", + "../node_modules/@types/node/stream.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/express/index.d.ts": [ + "../node_modules/@types/body-parser/index.d.ts", + "../node_modules/@types/serve-static/index.d.ts", + "../node_modules/@types/express-serve-static-core/index.d.ts", + "../node_modules/@types/qs/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/express-session/index.d.ts": [ + "../node_modules/@types/express/index.d.ts", + "../node_modules/@types/node/events.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/ioredis/index.d.ts": [ + "../node_modules/@types/node/tls.d.ts", + "../node_modules/@types/node/stream.d.ts", + "../node_modules/@types/node/events.d.ts", + "../node_modules/@types/node/ts3.2/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/connect-redis/index.d.ts": [ + "../node_modules/@types/express/index.d.ts", + "../node_modules/@types/express-session/index.d.ts", + "../node_modules/@types/ioredis/index.d.ts", + "../node_modules/@types/redis/ts3.1/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/RedisComponent.ts": [ + "./node_modules/@types/express/index.d.ts", + "../node_modules/@types/express-session/index.d.ts", + "./src/ApplicationComponent.ts" + ], + "./src/components/ServeStaticDirectoryComponent.ts": [ + "./node_modules/@types/express-serve-static-core/index.d.ts", + "./node_modules/@types/express/index.d.ts", + "./src/ApplicationComponent.ts" + ], + "../node_modules/@types/connect-flash/index.d.ts": [ + "../node_modules/@types/express/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/SessionComponent.ts": [ + "./src/components/RedisComponent.ts", + "./node_modules/@types/express/index.d.ts", + "./src/ApplicationComponent.ts" + ], + "../node_modules/@types/cookie/index.d.ts": [ + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "../node_modules/@types/cookie-parser/index.d.ts": [ + "../node_modules/@types/express/index.d.ts", + "../node_modules/@types/node/fs.d.ts", + "../node_modules/@types/node/ts3.2/fs.d.ts", + "../node_modules/@types/node/util.d.ts", + "../node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/components/WebSocketServerComponent.ts": [ + "./src/Application.ts", + "./src/components/ExpressAppComponent.ts", + "./src/components/RedisComponent.ts", + "./node_modules/@types/express/index.d.ts", + "./src/ApplicationComponent.ts" + ], + "./src/migrations/CreateLogsTable.ts": [ + "./src/db/Migration.ts" + ], + "./src/migrations/CreateMigrationsTable.ts": [ + "./src/db/Migration.ts" + ], + "./src/types/Express.d.ts": [ + "../node_modules/@types/nunjucks/index.d.ts", + "./src/db/Model.ts", + "./node_modules/@types/express-serve-static-core/index.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts" + ], + "./src/index.ts": [ + "./src/ApplicationComponent.ts", + "./src/Mail.ts" + ] + }, + "semanticDiagnosticsPerFile": [ + "./node_modules/typescript/lib/lib.es5.d.ts", + "./node_modules/typescript/lib/lib.es2015.d.ts", + "./node_modules/typescript/lib/lib.es2016.d.ts", + "./node_modules/typescript/lib/lib.es2017.d.ts", + "./node_modules/typescript/lib/lib.es2018.d.ts", + "./node_modules/typescript/lib/lib.es2019.d.ts", + "./node_modules/typescript/lib/lib.es2020.d.ts", + "./node_modules/typescript/lib/lib.es2015.core.d.ts", + "./node_modules/typescript/lib/lib.es2015.collection.d.ts", + "./node_modules/typescript/lib/lib.es2015.generator.d.ts", + "./node_modules/typescript/lib/lib.es2015.iterable.d.ts", + "./node_modules/typescript/lib/lib.es2015.promise.d.ts", + "./node_modules/typescript/lib/lib.es2015.proxy.d.ts", + "./node_modules/typescript/lib/lib.es2015.reflect.d.ts", + "./node_modules/typescript/lib/lib.es2015.symbol.d.ts", + "./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts", + "./node_modules/typescript/lib/lib.es2016.array.include.d.ts", + "./node_modules/typescript/lib/lib.es2017.object.d.ts", + "./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts", + "./node_modules/typescript/lib/lib.es2017.string.d.ts", + "./node_modules/typescript/lib/lib.es2017.intl.d.ts", + "./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts", + "./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts", + "./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts", + "./node_modules/typescript/lib/lib.es2018.intl.d.ts", + "./node_modules/typescript/lib/lib.es2018.promise.d.ts", + "./node_modules/typescript/lib/lib.es2018.regexp.d.ts", + "./node_modules/typescript/lib/lib.es2019.array.d.ts", + "./node_modules/typescript/lib/lib.es2019.object.d.ts", + "./node_modules/typescript/lib/lib.es2019.string.d.ts", + "./node_modules/typescript/lib/lib.es2019.symbol.d.ts", + "./node_modules/typescript/lib/lib.es2020.bigint.d.ts", + "./node_modules/typescript/lib/lib.es2020.promise.d.ts", + "./node_modules/typescript/lib/lib.es2020.string.d.ts", + "./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts", + "./node_modules/typescript/lib/lib.esnext.intl.d.ts", + "./node_modules/@types/node/globals.d.ts", + "./node_modules/@types/node/async_hooks.d.ts", + "./node_modules/@types/node/buffer.d.ts", + "../node_modules/@types/events/index.d.ts", + "./node_modules/@types/node/child_process.d.ts", + "./node_modules/@types/node/cluster.d.ts", + "./node_modules/@types/node/console.d.ts", + "./node_modules/@types/node/constants.d.ts", + "./node_modules/@types/node/crypto.d.ts", + "./node_modules/@types/node/dgram.d.ts", + "./node_modules/@types/node/dns.d.ts", + "./node_modules/@types/node/domain.d.ts", + "./node_modules/@types/node/events.d.ts", + "./node_modules/@types/node/fs.d.ts", + "./node_modules/@types/node/http.d.ts", + "./node_modules/@types/node/http2.d.ts", + "./node_modules/@types/node/https.d.ts", + "./node_modules/@types/node/inspector.d.ts", + "./node_modules/@types/node/module.d.ts", + "./node_modules/@types/node/net.d.ts", + "./node_modules/@types/node/os.d.ts", + "./node_modules/@types/node/path.d.ts", + "./node_modules/@types/node/perf_hooks.d.ts", + "./node_modules/@types/node/process.d.ts", + "./node_modules/@types/node/punycode.d.ts", + "./node_modules/@types/node/querystring.d.ts", + "./node_modules/@types/node/readline.d.ts", + "./node_modules/@types/node/repl.d.ts", + "./node_modules/@types/node/stream.d.ts", + "./node_modules/@types/node/string_decoder.d.ts", + "./node_modules/@types/node/timers.d.ts", + "./node_modules/@types/node/tls.d.ts", + "./node_modules/@types/node/trace_events.d.ts", + "./node_modules/@types/node/tty.d.ts", + "./node_modules/@types/node/url.d.ts", + "./node_modules/@types/node/util.d.ts", + "./node_modules/@types/node/v8.d.ts", + "./node_modules/@types/node/vm.d.ts", + "./node_modules/@types/node/worker_threads.d.ts", + "./node_modules/@types/node/zlib.d.ts", + "./node_modules/@types/node/base.d.ts", + "./node_modules/@types/node/ts3.2/fs.d.ts", + "./node_modules/@types/node/ts3.2/util.d.ts", + "./node_modules/@types/node/ts3.2/globals.d.ts", + "./node_modules/@types/node/ts3.2/base.d.ts", + "./node_modules/@types/node/assert.d.ts", + "./node_modules/@types/node/ts3.2/index.d.ts", + "./node_modules/@types/range-parser/index.d.ts", + "./node_modules/@types/express-serve-static-core/index.d.ts", + "./node_modules/@types/mime/index.d.ts", + "./node_modules/@types/serve-static/index.d.ts", + "./node_modules/@types/connect/index.d.ts", + "./node_modules/@types/body-parser/index.d.ts", + "./node_modules/@types/qs/index.d.ts", + "./node_modules/@types/express/index.d.ts", + "./src/Utils.ts", + "./src/HttpError.ts", + "../node_modules/@types/nunjucks/index.d.ts", + "../node_modules/@types/config/index.d.ts", + "../node_modules/@types/uuid/interfaces.d.ts", + "../node_modules/@types/uuid/index.d.ts", + "../node_modules/@types/mysql/index.d.ts", + "./src/db/Migration.ts", + "./src/db/MysqlConnectionManager.ts", + "./src/db/Query.ts", + "./src/db/Validator.ts", + "./src/Pagination.ts", + "./src/db/Model.ts", + "./src/models/Log.ts", + "./src/Logger.ts", + "../node_modules/@types/ws/index.d.ts", + "./src/WebSocketListener.ts", + "./src/ApplicationComponent.ts", + "./src/Controller.ts", + "./src/Application.ts", + "../node_modules/@types/nodemailer/lib/dkim/index.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", + "../node_modules/@types/nodemailer/lib/xoauth2.d.ts", + "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", + "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", + "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", + "../node_modules/@types/nodemailer/lib/shared.d.ts", + "../node_modules/@types/nodemailer/lib/json-transport.d.ts", + "../node_modules/@types/nodemailer/lib/sendmail-transport/index.d.ts", + "../node_modules/@types/nodemailer/lib/ses-transport.d.ts", + "../node_modules/@types/nodemailer/lib/smtp-pool/index.d.ts", + "../node_modules/@types/nodemailer/lib/smtp-transport.d.ts", + "../node_modules/@types/nodemailer/lib/stream-transport.d.ts", + "../node_modules/@types/nodemailer/index.d.ts", + "../node_modules/@types/mjml/index.d.ts", + "./src/Mail.ts", + "./src/components/CsrfProtectionComponent.ts", + "./src/components/ExpressAppComponent.ts", + "./src/components/FormHelperComponent.ts", + "../node_modules/@types/on-finished/index.d.ts", + "./src/components/LogRequestsComponent.ts", + "./src/components/MailComponent.ts", + "./src/components/MaintenanceComponent.ts", + "./src/components/MysqlComponent.ts", + "./src/components/RedirectBackComponent.ts", + "../node_modules/@types/redis/ts3.1/index.d.ts", + "../node_modules/@types/express/index.d.ts", + "../node_modules/@types/express-session/index.d.ts", + "../node_modules/@types/ioredis/index.d.ts", + "../node_modules/@types/connect-redis/index.d.ts", + "./src/components/RedisComponent.ts", + "./src/components/ServeStaticDirectoryComponent.ts", + "../node_modules/@types/connect-flash/index.d.ts", + "./src/components/SessionComponent.ts", + "../node_modules/@types/cookie/index.d.ts", + "../node_modules/@types/cookie-parser/index.d.ts", + "./src/components/WebSocketServerComponent.ts", + "./src/migrations/CreateLogsTable.ts", + "./src/migrations/CreateMigrationsTable.ts", + "./src/types/Express.d.ts", + "./src/index.ts" + ] + }, + "version": "3.8.3" +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..472c524 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,439 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/body-parser@*": + version "1.19.0" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" + integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.33" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546" + integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A== + dependencies: + "@types/node" "*" + +"@types/express-serve-static-core@*": + version "4.17.5" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.5.tgz#a00ac7dadd746ae82477443e4d480a6a93ea083c" + integrity sha512-578YH5Lt88AKoADy0b2jQGwJtrBxezXtVe/MBqWXKZpqx91SnC0pVkVCcxcytz3lWW+cHBYDi3Ysh0WXc+rAYw== + dependencies: + "@types/node" "*" + "@types/range-parser" "*" + +"@types/express@^4.17.6": + version "4.17.6" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.6.tgz#6bce49e49570507b86ea1b07b806f04697fac45e" + integrity sha512-n/mr9tZI83kd4azlPG5y997C/M4DNABK9yErhFM6hKdym4kkmd9j0vtsJyjFIwfRBxtrxZtAfGZCNRIBMFLK5w== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "*" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/mime@*": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" + integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw== + +"@types/node@*": + version "13.13.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.2.tgz#160d82623610db590a64e8ca81784e11117e5a54" + integrity sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A== + +"@types/qs@*": + version "6.9.1" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.1.tgz#937fab3194766256ee09fcd40b781740758617e7" + integrity sha512-lhbQXx9HKZAPgBkISrBcmAcMpZsmpe/Cd/hY7LGZS5OfkySUBItnPZHgQPssWYUET8elF+yCFBbP1Q0RZPTdaw== + +"@types/range-parser@*": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" + integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== + +"@types/serve-static@*": + version "1.13.3" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.3.tgz#eb7e1c41c4468272557e897e9171ded5e2ded9d1" + integrity sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g== + dependencies: + "@types/express-serve-static-core" "*" + "@types/mime" "*" + +accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +express@^4.17.1: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +inherits@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +mime-db@1.43.0: + version "1.43.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" + integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== + +mime-types@~2.1.24: + version "2.1.26" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" + integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== + dependencies: + mime-db "1.43.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +proxy-addr@~2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" + integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.1" + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +safe-buffer@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@^3.8.3: + version "3.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" + integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +ws@^7.2.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46" + integrity sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==