aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.env.defaults1
-rw-r--r--app/directory.ts140
-rw-r--r--app/index.ts7
-rw-r--r--app/logger.ts23
-rw-r--r--app/routes/page/router.ts19
-rw-r--r--app/routes/special/router.ts3
-rw-r--r--app/wikiparser.ts47
-rw-r--r--package-lock.json412
-rw-r--r--package.json3
-rw-r--r--static/css/globalstyles.css6
10 files changed, 625 insertions, 36 deletions
diff --git a/.env.defaults b/.env.defaults
index 3f2229f..1c11ae4 100644
--- a/.env.defaults
+++ b/.env.defaults
@@ -3,3 +3,4 @@ PAGES_DIR=pages
REBUILD_COOLDOWN_MIN=10
PURGE_COOLDOWN_MIN=10
PARSER_MAX_RECURSION=20
+LOGGING_LEVEL=info
diff --git a/app/directory.ts b/app/directory.ts
index fd9c008..ee6a5a9 100644
--- a/app/directory.ts
+++ b/app/directory.ts
@@ -1,9 +1,9 @@
-import { parse } from './wikiparser.js';
+import * as parser from './wikiparser.js';
import { readFileSync } from 'fs';
import glob from 'glob';
+import { logger } from './logger.js'
export class PageDirectory {
-
pages: Record<string, Page>;
primaryPages: Page[];
pagePath: string;
@@ -33,28 +33,74 @@ export class PageDirectory {
const pages = glob.sync(`**/*.wiki`, { cwd: this.pagePath })
pages.forEach(page => {
- page = page.replace('.wiki', '').replace('/', ':').replace(/[^a-z0-9:]/gi, '_').toLowerCase();
+ page = this.convertNameToStandard(page.replace('.wiki', '').replace('/', ':'));
this.pages[page] = {
standardName: page,
+ raw: this.loadRaw(page),
buildTime: 0,
- metadata: {}
+ metadata: {
+ dependencies: [],
+ dependents: [],
+ errors: []
+ }
}
});
- // Build templates first
- Object.keys(this.pages).forEach(name => {
- if (name.includes('Template:')) {
- this.pages[name] = this.buildPage(name);
+ const dependencyGraph: Record<string, string[]> = {};
+
+ Object.keys(this.pages).forEach(name => dependencyGraph[name] = Array.from(parser.findDependencies(this.pages[name].raw)).map(e => this.convertNameToStandard(e)));
+
+ function traverse(dependents: string[], dependencies: string[], recursionCount: number) {
+ if (recursionCount > parseInt(process.env.PARSER_MAX_RECURSION, 10)) {
+ throw new RecursionError('max recursion reached');
}
+ dependencies?.forEach((dependency: string) => {
+ if (dependencyGraph[dependency]?.length != 0) {
+ dependents.forEach((dependent: string) => {
+ if (dependencyGraph[dependency]?.includes(dependent)) {
+ throw new DependencyError(`circular dependency between ${dependent} and ${dependency}`, [dependent, dependency]);
+ }
+ });
+ traverse([...dependents, dependency], dependencyGraph[dependency], recursionCount + 1);
+ }
+ });
+ }
+
+ Object.keys(dependencyGraph).forEach(name => {
+ dependencyGraph[name].forEach(dependency => {
+ try {
+ traverse([name, dependency], dependencyGraph[dependency], 1);
+ } catch (e) {
+ if (e instanceof RecursionError) {
+ this.pages[name].metadata.errors.push({
+ identifier: 'max-recursion-reached',
+ message: `maximum dependency depth of ${process.env.PARSER_MAX_RECURSION} reached`
+ })
+ logger.warn(`max recursion for ${name} reached`)
+ } else if (e instanceof DependencyError) {
+ if (e.pages.includes(name)) {
+ this.pages[name].metadata.errors.push({
+ identifier: 'circular-dependency',
+ message: e.message
+ })
+ logger.warn(`${e.pages[0]} has a circular dependency with ${e.pages[1]}`)
+ } else {
+ logger.warn(`transclusions on page ${name} may not resolve due to dependency errors in its dependency tree`)
+ }
+ } else {
+ throw e;
+ }
+ }
+ });
});
const primaryPages = [];
Object.keys(this.pages).forEach(name => {
- if (!name.includes('Template:')) {
+ if (this.pages[name].metadata.errors.length == 0) {
this.pages[name] = this.buildPage(name);
- }
- if (this.pages[name].metadata.includeInNavbar) {
- primaryPages.push(this.pages[name]);
+ if (this.pages[name].metadata.includeInNavbar) {
+ primaryPages.push(this.pages[name]);
+ }
}
});
@@ -88,11 +134,7 @@ export class PageDirectory {
if (!page) {
return undefined;
}
-
- if (!page.html) {
- return this.buildPage(name)
- }
-
+
return page;
}
@@ -147,6 +189,17 @@ export class PageDirectory {
getPrimaryPages(): Page[] {
return this.primaryPages;
}
+
+ private loadRaw(name: string): string {
+ name = this.convertNameToStandard(name);
+ let data: string;
+ try {
+ data = readFileSync(`${this.pagePath}/${this.convertStandardToFilePath(name)}`, 'utf-8');
+ } catch {
+ return undefined;
+ }
+ return data;
+ }
/**
* Build a page.
@@ -157,12 +210,13 @@ export class PageDirectory {
private buildPage(name: string): Page {
name = this.convertNameToStandard(name);
let data: string;
- try {
- data = readFileSync(`${this.pagePath}/${this.convertStandardToFilePath(name)}`, 'utf-8');
- } catch {
- return undefined;
+ if (this.pages[name]?.raw) {
+ data = this.pages[name]?.raw
+ } else {
+ data = this.loadRaw(name)
}
- const result = parse(this, data);
+
+ const result = parser.parse(this, data);
const title = result.metadata.displayTitle ?? name
const content = `${result.metadata.notitle ? '' : `<h1>${title}</h1>`}${result.html}`;
@@ -175,7 +229,10 @@ export class PageDirectory {
includeInNavbar: result.metadata.primary ?? false,
sortOrder: result.metadata.sortOrder ?? -1,
showTitle: !result.metadata.notitle ?? true,
- displayTitle: title
+ displayTitle: title,
+ dependencies: [],
+ dependents: [],
+ errors: []
}
};
this.pages[name] = page;
@@ -189,7 +246,11 @@ export class PageDirectory {
* @param name non-standard name for a page
*/
private convertNameToStandard(name: string): string {
- return name.replace(/[^a-z0-9:]/gi, '_').toLowerCase();
+ name = name.replace(/[^a-z0-9:]/gi, '_').toLowerCase();
+ if (!name.includes(':')) {
+ name = `main:${name}`;
+ }
+ return name;
}
/**
@@ -198,7 +259,7 @@ export class PageDirectory {
* @param name standard name for a page
*/
private convertStandardToFilePath(name: string): string {
- const [first, second] = name.split(':');
+ const [first, second] = name.replace('main:', '').split(':');
const [title, subpage] = ((second) ? second : first).split('.')
const namespace = (second) ? first : undefined
@@ -209,7 +270,7 @@ export class PageDirectory {
export type Page = {
html?: string;
raw?: string;
- standardName: string,
+ standardName: string;
buildTime: number;
metadata: PageMetadata;
};
@@ -219,4 +280,31 @@ export type PageMetadata = {
sortOrder?: number;
showTitle?: boolean;
includeInNavbar?: boolean;
+ dependencies: string[];
+ dependents: string[];
+ errors: PageError[];
};
+
+export type PageError = {
+ identifier: string;
+ message: string;
+}
+
+export class DependencyError extends Error {
+ pages: string[]
+
+ constructor(message: string, pages: string[]) {
+ super(message);
+ this.pages = pages;
+
+ Object.setPrototypeOf(this, DependencyError.prototype);
+ }
+}
+
+export class RecursionError extends Error {
+ constructor(message: string) {
+ super(message);
+
+ Object.setPrototypeOf(this, RecursionError.prototype);
+ }
+}
diff --git a/app/index.ts b/app/index.ts
index 9865190..8514380 100644
--- a/app/index.ts
+++ b/app/index.ts
@@ -4,14 +4,13 @@ import dotenv from 'dotenv-defaults';
import * as page from './routes/page/router.js';
import * as special from './routes/special/router.js';
import { navbar } from './middlewares/index.js'
+import { logger } from './logger.js'
dotenv.config()
const app = express();
const directory = new PageDirectory(process.env.PAGES_DIR);
-directory.rebuild();
-
app.set('view engine', 'ejs');
app.set('views', 'views');
@@ -33,11 +32,11 @@ app.use(navbar, (req, res) => {
});
const server = app.listen(process.env.PORT, () => {
- console.log(`App listening on port ${process.env.PORT}`);
+ logger.info(`App listening on port ${process.env.PORT}`);
});
const exit = () => {
- console.info('Stopping server...');
+ logger.info('Stopping server...');
server.close(() => {
process.exit(0);
})
diff --git a/app/logger.ts b/app/logger.ts
new file mode 100644
index 0000000..4ce0150
--- /dev/null
+++ b/app/logger.ts
@@ -0,0 +1,23 @@
+import winston from 'winston';
+
+const enumerateErrorFormat = winston.format((info) => {
+ if (info instanceof Error) {
+ Object.assign(info, { message: info.stack });
+ }
+ return info;
+ });
+
+export const logger = winston.createLogger({
+ level: process.env.LOGGING_LEVEL === 'development' ? 'debug' : 'info',
+ format: winston.format.combine(
+ enumerateErrorFormat(),
+ winston.format.colorize(),
+ winston.format.splat(),
+ winston.format.printf(({ level, message }) => `${level}: ${message}`)
+ ),
+ transports: [
+ new winston.transports.Console({
+ stderrLevels: ['error'],
+ }),
+ ],
+});
diff --git a/app/routes/page/router.ts b/app/routes/page/router.ts
index af5e844..dc819f8 100644
--- a/app/routes/page/router.ts
+++ b/app/routes/page/router.ts
@@ -26,11 +26,26 @@ router.get('/:page?', navbar, (req, res, next) => {
return;
}
+ let html: string;
+ let title: string;
+
+ if (page.metadata.errors.length != 0) {
+ html = '<div class="box-red">This page could not be built due to the following errors:<br><ul>'
+ page.metadata.errors.forEach(e => {
+ html += `<li>${e.identifier}: ${e.message}</li>`
+ });
+ html += '</ul>Go <a href="/">home</a>?</div>'
+ title = 'Page error'
+ } else {
+ html = page.html;
+ title = page.metadata.displayTitle;
+ }
+
res.render('page.ejs', {
navbar: res.locals.navbarHtml,
path: res.locals.path,
- content: page.html,
- title: page.metadata.displayTitle,
+ content: html,
+ title: title,
buildTime: new Date(page.buildTime)
});
});
diff --git a/app/routes/special/router.ts b/app/routes/special/router.ts
index e88919c..26130c5 100644
--- a/app/routes/special/router.ts
+++ b/app/routes/special/router.ts
@@ -1,5 +1,6 @@
import express from 'express';
import { navbar, page } from '../../middlewares/index.js';
+import { logger } from './../../logger.js'
export const router = express.Router({ mergeParams: true });
@@ -30,6 +31,7 @@ router.get('/special/purge/:page/confirm', (req, res, next) => {
return;
}
+ logger.info(`Purge for page ${page.standardName} requested by ${req.headers['x-forwarded-for'] || req.socket.remoteAddress }`)
if (res.locals.directory.purge(res.locals.path)) {
res.status(200).send();
} else {
@@ -44,6 +46,7 @@ router.get('/special/rebuild', navbar, (req, res) => {
});
router.get('/special/rebuild/confirm', (req, res) => {
+ logger.info(`Directory rebuild requested by ${req.headers['x-forwarded-for'] || req.socket.remoteAddress }`)
if (res.locals.directory.rebuild()) {
res.status(200).send();
} else {
diff --git a/app/wikiparser.ts b/app/wikiparser.ts
index 544b6e5..f52d646 100644
--- a/app/wikiparser.ts
+++ b/app/wikiparser.ts
@@ -38,6 +38,49 @@ const re = (regex, flag = 'mgi') => {
const r = String.raw;
const arg = r`\s*([^|}]+?)\s*`;
+export function findDependencies(data: string): Set<string> {
+ const pages = new Set<string>();
+
+ let outText = data;
+ for (let l = 0, last = ''; l < parseInt(process.env.PARSER_MAX_RECURSION, 10); l++) {
+ if (last === outText) break; last = outText;
+
+ outText = outText
+ // Remove non-template magic words
+ .replace(re(r`<(/?) \s* (?= script|link|meta|iframe|frameset|object|embed|applet|form|input|button|textarea )`), '&lt;$1')
+ .replace(re(r`(?<= <[^>]+ ) (\bon(\w+))`), 'data-$2')
+ .replace(/<!--[^]+?-->/g, '')
+ .replace(re(r`{{ \s* displayTitle: ([^}]+) }}`), '')
+ .replace(re(r`{{ \s* navbarSortOrder: ([^}]+) }}`), '')
+ .replace(re(r`{{ \s* ! \s* }}`), '&vert;')
+ .replace(re(r`{{ \s* = \s* }}`), '&equals;')
+ .replace(re(r`{{ \s* [Rr]eflist \s* }}`), '<references/>')
+ .replace(re(r`{{ \s* #? urlencode: ${arg} }}`), '')
+ .replace(re(r`{{ \s* #? urldecode: ${arg} }}`), '')
+ .replace(re(r`{{ \s* #? lc: ${arg} }}`), '')
+ .replace(re(r`{{ \s* #? uc: ${arg} }}`), '')
+ .replace(re(r`{{ \s* #? lcfirst: ${arg} }}`), '')
+ .replace(re(r`{{ \s* #? ucfirst: ${arg} }}`), '')
+ .replace(re(r`{{ \s* #? len: ${arg} }}`), '')
+ .replace(re(r`{{ \s* #? pos: ${arg} \|${arg} (?: \s*\|${arg} )? }}`), '')
+ .replace(re(r`{{ \s* #? sub: ${arg} \|${arg} (?:\|${arg})? }}`), '')
+ .replace(re(r`{{ \s* #? padleft: ${arg} \|${arg} \|${arg} }}`), '')
+ .replace(re(r`{{ \s* #? padright: ${arg} \|${arg} \|${arg} }}`), '')
+ .replace(re(r`{{ \s* #? replace: ${arg} \|${arg} \|${arg} }}`), '')
+ .replace(re(r`{{ \s* #? explode: ${arg} \|${arg} \|${arg} }}`), '')
+ .replace(re(r`{{ \s* (#\w+) \s* : \s* ( [^{}]+ ) \s* }} ( ?!} )`), '')
+
+ // Templates: {{template}}
+ .replace(re(r`{{ \s* ([^#}|]+?) (\|[^}]+)? }} (?!})`), (_, title, params = '') => {
+ if (/{{/.test(params)) return _;
+ const page = title.includes(':') ? title : `Template:${title}`
+ pages.add(page);
+ return '';
+ })
+ }
+ return pages;
+}
+
export function parse(directory, data): Result {
const vars = {};
const metadata: any = {};
@@ -131,8 +174,8 @@ export function parse(directory, data): Result {
// Retrieve template content
let content = directory.get(page);
- if (!content) {
- return `<a class="internal-link redlink" title="${title}" href="${page}">Template:${title}</a>`;
+ if (!content?.html) {
+ return `<a class="internal-link redlink" title="${title}" href="/${page}">Template:${title}</a>`;
}
// Remove non-template sections
diff --git a/package-lock.json b/package-lock.json
index bd6578f..4e52a2a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,7 +18,8 @@
"ejs": "^3.1.6",
"escape-html": "^1.0.3",
"express": "^4.17.1",
- "glob": "^7.2.0"
+ "glob": "^7.2.0",
+ "winston": "^3.3.3"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.7.0",
@@ -26,6 +27,16 @@
"eslint": "^8.5.0"
}
},
+ "node_modules/@dabh/diagnostics": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz",
+ "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==",
+ "dependencies": {
+ "colorspace": "1.1.x",
+ "enabled": "2.0.x",
+ "kuler": "^2.0.0"
+ }
+ },
"node_modules/@eslint/eslintrc": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz",
@@ -658,6 +669,15 @@
"node": ">=4"
}
},
+ "node_modules/color": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
+ "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+ "dependencies": {
+ "color-convert": "^1.9.3",
+ "color-string": "^1.6.0"
+ }
+ },
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -671,6 +691,32 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
+ "node_modules/color-string": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz",
+ "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==",
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
+ "node_modules/colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/colorspace": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz",
+ "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==",
+ "dependencies": {
+ "color": "^3.1.3",
+ "text-hex": "1.0.x"
+ }
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -816,6 +862,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/enabled": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
+ "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="
+ },
"node_modules/encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
@@ -1248,6 +1299,11 @@
"reusify": "^1.0.4"
}
},
+ "node_modules/fecha": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz",
+ "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q=="
+ },
"node_modules/file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -1316,6 +1372,11 @@
"integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==",
"dev": true
},
+ "node_modules/fn.name": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
+ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
+ },
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -1499,6 +1560,11 @@
"node": ">= 0.10"
}
},
+ "node_modules/is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
+ },
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -1529,6 +1595,17 @@
"node": ">=0.12.0"
}
},
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -1576,6 +1653,11 @@
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
"dev": true
},
+ "node_modules/kuler": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
+ "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="
+ },
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -1595,6 +1677,23 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
+ "node_modules/logform": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.0.tgz",
+ "integrity": "sha512-graeoWUH2knKbGthMtuG1EfaSPMZFZBIrhuJHhkS5ZseFBrc7DupCzihOQAzsK/qIKPQaPJ/lFQFctILUY5ARQ==",
+ "dependencies": {
+ "colors": "^1.2.1",
+ "fecha": "^4.2.0",
+ "ms": "^2.1.1",
+ "safe-stable-stringify": "^1.1.0",
+ "triple-beam": "^1.3.0"
+ }
+ },
+ "node_modules/logform/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -1729,6 +1828,14 @@
"wrappy": "1"
}
},
+ "node_modules/one-time": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
+ "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
+ "dependencies": {
+ "fn.name": "1.x.x"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@@ -1898,6 +2005,19 @@
"node": ">= 0.8"
}
},
+ "node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/regexpp": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
@@ -1972,6 +2092,11 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
+ "node_modules/safe-stable-stringify": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz",
+ "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw=="
+ },
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -2060,6 +2185,14 @@
"node": ">=8"
}
},
+ "node_modules/simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
"node_modules/slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -2069,6 +2202,14 @@
"node": ">=8"
}
},
+ "node_modules/stack-trace": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+ "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
@@ -2077,6 +2218,33 @@
"node": ">= 0.6"
}
},
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/string_decoder/node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
@@ -2112,6 +2280,11 @@
"node": ">=4"
}
},
+ "node_modules/text-hex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
+ "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="
+ },
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -2138,6 +2311,11 @@
"node": ">=0.6"
}
},
+ "node_modules/triple-beam": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
+ "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
+ },
"node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
@@ -2226,6 +2404,11 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
"node_modules/utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
@@ -2263,6 +2446,43 @@
"node": ">= 8"
}
},
+ "node_modules/winston": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz",
+ "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==",
+ "dependencies": {
+ "@dabh/diagnostics": "^2.0.2",
+ "async": "^3.1.0",
+ "is-stream": "^2.0.0",
+ "logform": "^2.2.0",
+ "one-time": "^1.0.0",
+ "readable-stream": "^3.4.0",
+ "stack-trace": "0.0.x",
+ "triple-beam": "^1.3.0",
+ "winston-transport": "^4.4.0"
+ },
+ "engines": {
+ "node": ">= 6.4.0"
+ }
+ },
+ "node_modules/winston-transport": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.1.tgz",
+ "integrity": "sha512-ciZRlU4CSjHqHe8RQG1iPxKMRVwv6ZJ0RC7DxStKWd0KjpAhPDy5gVYSCpIUq+5CUsP+IyNOTZy1X0tO2QZqjg==",
+ "dependencies": {
+ "logform": "^2.2.0",
+ "readable-stream": "^3.4.0",
+ "triple-beam": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 6.4.0"
+ }
+ },
+ "node_modules/winston/node_modules/async": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz",
+ "integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g=="
+ },
"node_modules/word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
@@ -2285,6 +2505,16 @@
}
},
"dependencies": {
+ "@dabh/diagnostics": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz",
+ "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==",
+ "requires": {
+ "colorspace": "1.1.x",
+ "enabled": "2.0.x",
+ "kuler": "^2.0.0"
+ }
+ },
"@eslint/eslintrc": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz",
@@ -2753,6 +2983,15 @@
"supports-color": "^5.3.0"
}
},
+ "color": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
+ "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+ "requires": {
+ "color-convert": "^1.9.3",
+ "color-string": "^1.6.0"
+ }
+ },
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -2766,6 +3005,29 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
+ "color-string": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz",
+ "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==",
+ "requires": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
+ "colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="
+ },
+ "colorspace": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz",
+ "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==",
+ "requires": {
+ "color": "^3.1.3",
+ "text-hex": "1.0.x"
+ }
+ },
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -2878,6 +3140,11 @@
"jake": "^10.6.1"
}
},
+ "enabled": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
+ "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="
+ },
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
@@ -3211,6 +3478,11 @@
"reusify": "^1.0.4"
}
},
+ "fecha": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz",
+ "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q=="
+ },
"file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -3267,6 +3539,11 @@
"integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==",
"dev": true
},
+ "fn.name": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
+ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
+ },
"forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -3399,6 +3676,11 @@
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
},
+ "is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
+ },
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -3420,6 +3702,11 @@
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
+ "is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="
+ },
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -3458,6 +3745,11 @@
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
"dev": true
},
+ "kuler": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
+ "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="
+ },
"levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -3474,6 +3766,25 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
+ "logform": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.0.tgz",
+ "integrity": "sha512-graeoWUH2knKbGthMtuG1EfaSPMZFZBIrhuJHhkS5ZseFBrc7DupCzihOQAzsK/qIKPQaPJ/lFQFctILUY5ARQ==",
+ "requires": {
+ "colors": "^1.2.1",
+ "fecha": "^4.2.0",
+ "ms": "^2.1.1",
+ "safe-stable-stringify": "^1.1.0",
+ "triple-beam": "^1.3.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ }
+ }
+ },
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -3572,6 +3883,14 @@
"wrappy": "1"
}
},
+ "one-time": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
+ "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
+ "requires": {
+ "fn.name": "1.x.x"
+ }
+ },
"optionator": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@@ -3682,6 +4001,16 @@
"unpipe": "1.0.0"
}
},
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
"regexpp": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
@@ -3723,6 +4052,11 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
+ "safe-stable-stringify": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz",
+ "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw=="
+ },
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -3795,17 +4129,45 @@
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true
},
+ "simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
+ "requires": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
"slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true
},
+ "stack-trace": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+ "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
+ },
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
},
+ "string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "requires": {
+ "safe-buffer": "~5.2.0"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+ }
+ }
+ },
"strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
@@ -3829,6 +4191,11 @@
"has-flag": "^3.0.0"
}
},
+ "text-hex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
+ "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="
+ },
"text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -3849,6 +4216,11 @@
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
},
+ "triple-beam": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
+ "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
+ },
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
@@ -3909,6 +4281,11 @@
"punycode": "^2.1.0"
}
},
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
@@ -3934,6 +4311,39 @@
"isexe": "^2.0.0"
}
},
+ "winston": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz",
+ "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==",
+ "requires": {
+ "@dabh/diagnostics": "^2.0.2",
+ "async": "^3.1.0",
+ "is-stream": "^2.0.0",
+ "logform": "^2.2.0",
+ "one-time": "^1.0.0",
+ "readable-stream": "^3.4.0",
+ "stack-trace": "0.0.x",
+ "triple-beam": "^1.3.0",
+ "winston-transport": "^4.4.0"
+ },
+ "dependencies": {
+ "async": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz",
+ "integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g=="
+ }
+ }
+ },
+ "winston-transport": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.1.tgz",
+ "integrity": "sha512-ciZRlU4CSjHqHe8RQG1iPxKMRVwv6ZJ0RC7DxStKWd0KjpAhPDy5gVYSCpIUq+5CUsP+IyNOTZy1X0tO2QZqjg==",
+ "requires": {
+ "logform": "^2.2.0",
+ "readable-stream": "^3.4.0",
+ "triple-beam": "^1.2.0"
+ }
+ },
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
diff --git a/package.json b/package.json
index cbae2c7..293868e 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,8 @@
"ejs": "^3.1.6",
"escape-html": "^1.0.3",
"express": "^4.17.1",
- "glob": "^7.2.0"
+ "glob": "^7.2.0",
+ "winston": "^3.3.3"
},
"type": "module",
"devDependencies": {
diff --git a/static/css/globalstyles.css b/static/css/globalstyles.css
index 3c39e38..6826ab9 100644
--- a/static/css/globalstyles.css
+++ b/static/css/globalstyles.css
@@ -99,3 +99,9 @@ a {
padding: 10px;
background-color: rgba(0, 0, 0, 0.1);
}
+
+.box-red {
+ border: solid 1px rgba(255, 0, 0, 0.5);
+ padding: 10px;
+ background-color: rgba(255, 0, 0, 0.2);
+}