mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-03-21 17:25:10 -05:00
Vendor node-static (#11295)
Also includes a decent amount of refactoring to bring it in line with Showdown code standards. --------- Co-authored-by: Slayer95 <ivojulca@hotmail.com>
This commit is contained in:
parent
1487d52db0
commit
7a9e535e35
439
lib/static-server.ts
Normal file
439
lib/static-server.ts
Normal file
|
|
@ -0,0 +1,439 @@
|
|||
/**
|
||||
* Static server
|
||||
*
|
||||
* API resembles node-static, but with some differences:
|
||||
*
|
||||
* - `serve`'s callback needs to return `true` to suppress the default error page
|
||||
* - everything is Promises
|
||||
* - no customizing cache time by filename
|
||||
* - no index.json directory streaming (it was undocumented; you weren't using it)
|
||||
*
|
||||
* Forked from node-static @
|
||||
* https://github.com/cloudhead/node-static/blob/e49fbd728e93294c225f52103962e56aab86cb1a/lib/node-static.js
|
||||
*
|
||||
* @author Guangcong Luo <guangcongluo@gmail.com>, Alexis Sellier, Brett Zamir
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import fs from 'node:fs';
|
||||
import fsP from 'node:fs/promises';
|
||||
import http from 'node:http';
|
||||
import path from 'node:path';
|
||||
|
||||
const DEBUG = false;
|
||||
export const SERVER_INFO = 'node-static-vendored/1.0';
|
||||
|
||||
export type Headers = Record<string, string>;
|
||||
export type Options = {
|
||||
/** Root directory to serve files from. */
|
||||
root?: string,
|
||||
/** Index file when serving a directory. */
|
||||
indexFile?: string,
|
||||
/** Default extension to append to files if not found. */
|
||||
defaultExtension?: string,
|
||||
/** Cache time in seconds. null = no cache header. undefined = default (3600). 0 = no cache. */
|
||||
cacheTime?: number | null,
|
||||
/** Serve `.gz` files if available. */
|
||||
gzip?: boolean | RegExp,
|
||||
/** Custom headers for success responses (not sent on errors). */
|
||||
headers?: Headers,
|
||||
/** Server header. `null` to disable. */
|
||||
serverInfo?: string | null,
|
||||
};
|
||||
export type Result = {
|
||||
status: number,
|
||||
headers: Record<string, string>,
|
||||
message: string | undefined,
|
||||
/** Have we already responded? */
|
||||
alreadySent: boolean,
|
||||
};
|
||||
/** Return true to suppress default error page */
|
||||
export type ErrorCallback = (result: Result) => boolean | void;
|
||||
|
||||
export const mimeTypes: { [key: string]: string } = {
|
||||
'.html': 'text/html;charset=utf-8',
|
||||
'.htm': 'text/html;charset=utf-8',
|
||||
'.css': 'text/css;charset=utf-8',
|
||||
'.js': 'application/javascript;charset=utf-8',
|
||||
'.jsx': 'application/javascript;charset=utf-8',
|
||||
'.cjs': 'application/javascript;charset=utf-8',
|
||||
'.mjs': 'application/javascript;charset=utf-8',
|
||||
'.json': 'application/json;charset=utf-8',
|
||||
'.ts': 'application/typescript;charset=utf-8',
|
||||
'.xml': 'application/xml;charset=utf-8',
|
||||
'.txt': 'text/plain;charset=utf-8',
|
||||
'.md': 'text/markdown;charset=utf-8',
|
||||
|
||||
'.png': 'image/png',
|
||||
'.jpg': 'image/jpeg',
|
||||
'.jpeg': 'image/jpeg',
|
||||
'.gif': 'image/gif',
|
||||
'.svg': 'image/svg+xml;charset=utf-8',
|
||||
'.ico': 'image/x-icon',
|
||||
'.bmp': 'image/bmp',
|
||||
'.webp': 'image/webp',
|
||||
|
||||
'.woff': 'font/woff',
|
||||
'.woff2': 'font/woff2',
|
||||
'.ttf': 'font/ttf',
|
||||
'.eot': 'application/vnd.ms-fontobject',
|
||||
|
||||
'.zip': 'application/zip',
|
||||
'.tar': 'application/x-tar',
|
||||
'.gz': 'application/gzip',
|
||||
|
||||
'.mp3': 'audio/mpeg',
|
||||
'.wav': 'audio/wav',
|
||||
'.ogg': 'audio/ogg',
|
||||
'.mp4': 'video/mp4',
|
||||
'.webm': 'video/webm',
|
||||
};
|
||||
|
||||
export class StaticServer {
|
||||
root: string;
|
||||
options: Options;
|
||||
cacheTime: number | null = 3600;
|
||||
defaultHeaders: Headers = {};
|
||||
/** Contains the `.`, unlike options.defaultExtension */
|
||||
defaultExtension = '';
|
||||
constructor(root: string, options?: Options);
|
||||
constructor(options?: Options);
|
||||
constructor(root?: Options | string | null, options?: Options) {
|
||||
if (root && typeof root === 'object') {
|
||||
options = root;
|
||||
root = null;
|
||||
}
|
||||
|
||||
// resolve() doesn't normalize (to lowercase) drive letters on Windows
|
||||
this.root = path.normalize(path.resolve(root || '.'));
|
||||
this.options = options || {};
|
||||
|
||||
this.options.indexFile ||= 'index.html';
|
||||
|
||||
if (this.options.cacheTime !== undefined) {
|
||||
this.cacheTime = this.options.cacheTime;
|
||||
}
|
||||
|
||||
if (this.options.defaultExtension) {
|
||||
this.defaultExtension = `.${this.options.defaultExtension}`;
|
||||
}
|
||||
|
||||
if (this.options.serverInfo !== null) {
|
||||
this.defaultHeaders['server'] = this.options.serverInfo || SERVER_INFO;
|
||||
}
|
||||
|
||||
for (const k in this.options.headers) {
|
||||
this.defaultHeaders[k] = this.options.headers[k];
|
||||
}
|
||||
}
|
||||
|
||||
async serveDir(
|
||||
pathname: string, req: http.IncomingMessage, res: http.ServerResponse
|
||||
): Promise<Result> {
|
||||
const htmlIndex = path.join(pathname, this.options.indexFile!);
|
||||
|
||||
try {
|
||||
const stat = await fsP.stat(htmlIndex);
|
||||
const status = 200;
|
||||
const headers = {};
|
||||
const originalPathname = decodeURIComponent(new URL(req.url!, 'http://localhost').pathname);
|
||||
if (originalPathname.length && !originalPathname.endsWith('/')) {
|
||||
return this.getResult(301, { 'Location': originalPathname + '/' });
|
||||
} else {
|
||||
return this.respond(status, headers, htmlIndex, stat, req, res);
|
||||
}
|
||||
} catch {
|
||||
return this.getResult(404);
|
||||
}
|
||||
}
|
||||
|
||||
async serveFile(
|
||||
pathname: string, status: number, headers: Headers, req: http.IncomingMessage, res: http.ServerResponse,
|
||||
errorCallback?: ErrorCallback
|
||||
): Promise<Result> {
|
||||
pathname = this.resolve(pathname);
|
||||
|
||||
const stat = await fsP.stat(pathname);
|
||||
const result = await this.respond(status, headers, pathname, stat, req, res);
|
||||
return this.finish(result, req, res, errorCallback);
|
||||
}
|
||||
|
||||
getResult(status: number, headers: Headers = {}, alreadySent = false): Result {
|
||||
if (this.defaultHeaders['server']) {
|
||||
headers['server'] ||= this.defaultHeaders['server'];
|
||||
}
|
||||
|
||||
return {
|
||||
status,
|
||||
headers,
|
||||
message: http.STATUS_CODES[status],
|
||||
alreadySent,
|
||||
};
|
||||
}
|
||||
|
||||
finish(
|
||||
result: Result, req: http.IncomingMessage, res: http.ServerResponse, errorCallback?: ErrorCallback
|
||||
): Result {
|
||||
// If `alreadySent`, it's been taken care of in `this.stream`.
|
||||
if (!result.alreadySent && !errorCallback?.(result)) {
|
||||
res.writeHead(result.status, result.headers);
|
||||
if (result.status >= 400 && req.method !== 'HEAD') {
|
||||
res.write(`${result.status} ${result.message}`);
|
||||
}
|
||||
res.end();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async servePath(
|
||||
pathname: string, status: number, headers: Headers, req: http.IncomingMessage, res: http.ServerResponse
|
||||
): Promise<Result> {
|
||||
pathname = this.resolve(pathname);
|
||||
|
||||
// Make sure we're not trying to access a
|
||||
// file outside of the root.
|
||||
if (!pathname.startsWith(this.root)) {
|
||||
// Forbidden
|
||||
return this.getResult(403);
|
||||
}
|
||||
|
||||
try {
|
||||
const stat = await fsP.stat(pathname);
|
||||
if (stat.isFile()) { // Stream a single file.
|
||||
return this.respond(status, headers, pathname, stat, req, res);
|
||||
} else if (stat.isDirectory()) { // Stream a directory of files.
|
||||
return this.serveDir(pathname, req, res);
|
||||
} else {
|
||||
return this.getResult(400);
|
||||
}
|
||||
} catch {
|
||||
// possibly not found, check default extension
|
||||
if (this.defaultExtension) {
|
||||
try {
|
||||
const stat = await fsP.stat(pathname + this.defaultExtension);
|
||||
if (stat.isFile()) {
|
||||
return this.respond(status, headers, pathname + this.defaultExtension, stat, req, res);
|
||||
} else {
|
||||
return this.getResult(400);
|
||||
}
|
||||
} catch {
|
||||
// really not found
|
||||
return this.getResult(404);
|
||||
}
|
||||
} else {
|
||||
return this.getResult(404);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolve(pathname: string) {
|
||||
return path.resolve(path.join(this.root, pathname));
|
||||
}
|
||||
|
||||
async serve(req: http.IncomingMessage, res: http.ServerResponse, errorCallback?: ErrorCallback): Promise<Result> {
|
||||
let pathname;
|
||||
try {
|
||||
pathname = decodeURIComponent(new URL(req.url!, 'http://localhost').pathname);
|
||||
} catch {
|
||||
return this.finish(this.getResult(400), req, res, errorCallback);
|
||||
}
|
||||
|
||||
const result = await this.servePath(pathname, 200, {}, req, res);
|
||||
return this.finish(result, req, res, errorCallback);
|
||||
}
|
||||
|
||||
/** Check if we should consider sending a gzip version of the file based on the
|
||||
* file content type and client's Accept-Encoding header value. */
|
||||
gzipOk(req: http.IncomingMessage, contentType: string) {
|
||||
const enable = this.options.gzip;
|
||||
if (enable === true || ((enable instanceof RegExp) && enable.test(contentType))) {
|
||||
return req.headers['accept-encoding']?.includes('gzip');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Send a gzipped version of the file if the options and the client indicate gzip is enabled and
|
||||
* we find a .gz file matching the static resource requested. */
|
||||
respondGzip(
|
||||
status: number, contentType: string, _headers: Headers, file: string, stat: fs.Stats,
|
||||
req: http.IncomingMessage, res: http.ServerResponse
|
||||
): Promise<Result> {
|
||||
if (!this.gzipOk(req, contentType)) {
|
||||
// Client doesn't want gzip
|
||||
return this.respondNoGzip(status, contentType, _headers, file, stat, req, res);
|
||||
}
|
||||
const gzFile = `${file}.gz`;
|
||||
return fsP.stat(gzFile).catch(() => null).then(gzStat => {
|
||||
if (gzStat?.isFile()) {
|
||||
const vary = _headers['Vary'];
|
||||
_headers['Vary'] = (vary && vary !== 'Accept-Encoding' ? `${vary}, ` : '') + 'Accept-Encoding';
|
||||
_headers['Content-Encoding'] = 'gzip';
|
||||
stat.size = gzStat.size;
|
||||
file = gzFile;
|
||||
}
|
||||
return this.respondNoGzip(status, contentType, _headers, file, stat, req, res);
|
||||
});
|
||||
}
|
||||
|
||||
parseByteRange(req: http.IncomingMessage, stat: fs.Stats) {
|
||||
const byteRange = {
|
||||
from: 0,
|
||||
to: 0,
|
||||
valid: false,
|
||||
};
|
||||
|
||||
const rangeHeader = req.headers['range'];
|
||||
const flavor = 'bytes=';
|
||||
|
||||
if (rangeHeader) {
|
||||
if (rangeHeader.startsWith(flavor) && !rangeHeader.includes(',')) {
|
||||
/* Parse */
|
||||
const splitRangeHeader = rangeHeader.substr(flavor.length).split('-');
|
||||
byteRange.from = parseInt(splitRangeHeader[0]);
|
||||
byteRange.to = parseInt(splitRangeHeader[1]);
|
||||
|
||||
/* Replace empty fields of differential requests by absolute values */
|
||||
if (isNaN(byteRange.from) && !isNaN(byteRange.to)) {
|
||||
byteRange.from = stat.size - byteRange.to;
|
||||
byteRange.to = stat.size ? stat.size - 1 : 0;
|
||||
} else if (!isNaN(byteRange.from) && isNaN(byteRange.to)) {
|
||||
byteRange.to = stat.size ? stat.size - 1 : 0;
|
||||
}
|
||||
|
||||
/* General byte range validation */
|
||||
if (!isNaN(byteRange.from) && !isNaN(byteRange.to) && 0 <= byteRange.from && byteRange.from <= byteRange.to) {
|
||||
byteRange.valid = true;
|
||||
} else {
|
||||
if (DEBUG) console.warn('Request contains invalid range header: ', splitRangeHeader);
|
||||
}
|
||||
} else {
|
||||
if (DEBUG) console.warn('Request contains unsupported range header: ', rangeHeader);
|
||||
}
|
||||
}
|
||||
return byteRange;
|
||||
}
|
||||
|
||||
async respondNoGzip(
|
||||
status: number, contentType: string, _headers: Headers, file: string, stat: fs.Stats,
|
||||
req: http.IncomingMessage, res: http.ServerResponse
|
||||
): Promise<Result> {
|
||||
const mtime = Date.parse(stat.mtime as any);
|
||||
const headers: Headers = {};
|
||||
const clientETag = req.headers['if-none-match'];
|
||||
const clientMTime = Date.parse(req.headers['if-modified-since']!);
|
||||
const byteRange = this.parseByteRange(req, stat);
|
||||
let startByte = 0;
|
||||
let length = stat.size;
|
||||
|
||||
/* Handle byte ranges */
|
||||
if (byteRange.valid) {
|
||||
if (byteRange.to < length) {
|
||||
// Note: HTTP Range param is inclusive
|
||||
startByte = byteRange.from;
|
||||
length = byteRange.to - byteRange.from + 1;
|
||||
status = 206;
|
||||
|
||||
// Set Content-Range response header (we advertise initial resource size on server here (stat.size))
|
||||
headers['Content-Range'] = `bytes ${byteRange.from}-${byteRange.to}/${stat.size}`;
|
||||
} else {
|
||||
byteRange.valid = false;
|
||||
if (DEBUG) {
|
||||
console.warn('Range request exceeds file boundaries, goes until byte no', byteRange.to, 'against file size of', length, 'bytes');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* In any case, check for unhandled byte range headers */
|
||||
if (!byteRange.valid && req.headers['range']) {
|
||||
if (DEBUG) console.error(new Error('Range request present but invalid, might serve whole file instead'));
|
||||
}
|
||||
|
||||
// Copy default headers
|
||||
for (const k in this.defaultHeaders) headers[k] = this.defaultHeaders[k];
|
||||
|
||||
headers['Etag'] = JSON.stringify([stat.ino, stat.size, mtime].join('-'));
|
||||
headers['Date'] = new Date().toUTCString();
|
||||
headers['Last-Modified'] = new Date(stat.mtime).toUTCString();
|
||||
headers['Content-Type'] = contentType;
|
||||
headers['Content-Length'] = length as any;
|
||||
|
||||
// Copy custom headers
|
||||
for (const k in _headers) { headers[k] = _headers[k]; }
|
||||
|
||||
// Conditional GET
|
||||
// If the "If-Modified-Since" or "If-None-Match" headers
|
||||
// match the conditions, send a 304 Not Modified.
|
||||
if ((clientMTime || clientETag) &&
|
||||
(!clientETag || clientETag === headers['Etag']) &&
|
||||
(!clientMTime || clientMTime >= mtime)) {
|
||||
// 304 response should not contain entity headers
|
||||
for (const entityHeader of [
|
||||
'Content-Encoding', 'Content-Language', 'Content-Length', 'Content-Location', 'Content-MD5', 'Content-Range', 'Content-Type', 'Expires', 'Last-Modified',
|
||||
]) {
|
||||
delete headers[entityHeader];
|
||||
}
|
||||
return this.getResult(304, headers);
|
||||
} else if (req.method === 'HEAD') {
|
||||
return this.getResult(status, headers);
|
||||
} else {
|
||||
res.writeHead(status, headers);
|
||||
|
||||
try {
|
||||
await this.stream(file, length, startByte, res);
|
||||
return this.getResult(status, headers, true);
|
||||
} catch {
|
||||
// too late to actually send the 500 header
|
||||
return this.getResult(500, {}, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
respond(
|
||||
status: number, _headers: Headers, file: string, stat: fs.Stats,
|
||||
req: http.IncomingMessage, res: http.ServerResponse
|
||||
): Promise<Result> {
|
||||
const contentType = _headers['Content-Type'] ||
|
||||
mimeTypes[path.extname(file)] ||
|
||||
'application/octet-stream';
|
||||
_headers = this.setCacheHeaders(_headers);
|
||||
|
||||
if (this.options.gzip) {
|
||||
return this.respondGzip(status, contentType, _headers, file, stat, req, res);
|
||||
} else {
|
||||
return this.respondNoGzip(status, contentType, _headers, file, stat, req, res);
|
||||
}
|
||||
}
|
||||
|
||||
stream(file: string, length: number, startByte: number, res: http.ServerResponse): Promise<number> {
|
||||
return new Promise<number>((resolve, reject) => {
|
||||
let offset = 0;
|
||||
|
||||
// Stream the file to the client
|
||||
fs.createReadStream(file, {
|
||||
flags: 'r',
|
||||
mode: 0o666,
|
||||
start: startByte,
|
||||
end: startByte + (length ? length - 1 : 0),
|
||||
}).on('data', chunk => {
|
||||
// Bounds check the incoming chunk and offset, as copying
|
||||
// a buffer from an invalid offset will throw an error and crash
|
||||
if (chunk.length && offset < length && offset >= 0) {
|
||||
offset += chunk.length;
|
||||
}
|
||||
}).on('close', () => {
|
||||
res.end();
|
||||
resolve(offset);
|
||||
}).on('error', err => {
|
||||
reject(err);
|
||||
console.error(err);
|
||||
}).pipe(res, { end: false });
|
||||
});
|
||||
}
|
||||
|
||||
setCacheHeaders(_headers: Headers): Headers {
|
||||
if (typeof this.cacheTime === 'number') {
|
||||
_headers['cache-control'] = `max-age=${this.cacheTime}`;
|
||||
}
|
||||
return _headers;
|
||||
}
|
||||
}
|
||||
195
package-lock.json
generated
195
package-lock.json
generated
|
|
@ -7,7 +7,6 @@
|
|||
"": {
|
||||
"name": "pokemon-showdown",
|
||||
"version": "0.11.10",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
|
|
@ -25,7 +24,6 @@
|
|||
"@types/better-sqlite3": "7.6.3",
|
||||
"@types/cloud-env": "^0.2.2",
|
||||
"@types/node": "^14.18.63",
|
||||
"@types/node-static": "^0.7.7",
|
||||
"@types/nodemailer": "^6.4.4",
|
||||
"@types/pg": "^8.6.5",
|
||||
"@types/sockjs": "^0.3.33",
|
||||
|
|
@ -44,7 +42,6 @@
|
|||
"better-sqlite3": "^11.8.1",
|
||||
"cloud-env": "^0.2.3",
|
||||
"githubhook": "^1.9.3",
|
||||
"node-static": "^0.7.11",
|
||||
"nodemailer": "^6.4.6",
|
||||
"permessage-deflate": "^0.1.7",
|
||||
"pg": "^8.11.3",
|
||||
|
|
@ -921,12 +918,6 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/mime": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
|
||||
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "14.18.63",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz",
|
||||
|
|
@ -934,16 +925,6 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node-static": {
|
||||
"version": "0.7.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-static/-/node-static-0.7.7.tgz",
|
||||
"integrity": "sha512-Cq3c9lfC9zRrGxe7ox073219Mpy/kmWNsISG0yEG7aUEk33xv/g+uqz/+4b7hM4WN9LsGageBzGuvy09inaGhg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/mime": "^1",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/nodemailer": {
|
||||
"version": "6.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.7.tgz",
|
||||
|
|
@ -1485,7 +1466,8 @@
|
|||
"node_modules/buffer-from": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/buffer-writer": {
|
||||
"version": "2.0.0",
|
||||
|
|
@ -1677,15 +1659,6 @@
|
|||
"color-support": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/colors": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
|
||||
"integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.1.90"
|
||||
}
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
||||
|
|
@ -2551,6 +2524,7 @@
|
|||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
},
|
||||
|
|
@ -2867,7 +2841,8 @@
|
|||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/log-symbols": {
|
||||
"version": "4.1.0",
|
||||
|
|
@ -2956,18 +2931,6 @@
|
|||
"node": ">=8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"mime": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-response": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||
|
|
@ -2992,12 +2955,6 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||
"integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/minipass": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||
|
|
@ -3239,6 +3196,7 @@
|
|||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/multiline": {
|
||||
|
|
@ -3337,6 +3295,7 @@
|
|||
"version": "2.9.1",
|
||||
"resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz",
|
||||
"integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"debug": "^3.2.6",
|
||||
"iconv-lite": "^0.4.4",
|
||||
|
|
@ -3353,6 +3312,7 @@
|
|||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
|
|
@ -3411,23 +3371,6 @@
|
|||
"node": ">= 10.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-static": {
|
||||
"version": "0.7.11",
|
||||
"resolved": "https://registry.npmjs.org/node-static/-/node-static-0.7.11.tgz",
|
||||
"integrity": "sha512-zfWC/gICcqb74D9ndyvxZWaI1jzcoHmf4UTHWQchBNuNMxdBLJMDiUgZ1tjGLEIe/BMhj2DxKD8HOuc2062pDQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"colors": ">=0.6.0",
|
||||
"mime": "^1.2.9",
|
||||
"optimist": ">=0.3.4"
|
||||
},
|
||||
"bin": {
|
||||
"static": "bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
"version": "6.8.0",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.8.0.tgz",
|
||||
|
|
@ -3498,16 +3441,6 @@
|
|||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/optimist": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
|
||||
"integrity": "sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"minimist": "~0.0.1",
|
||||
"wordwrap": "~0.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||
|
|
@ -3889,12 +3822,12 @@
|
|||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-7.2.3.tgz",
|
||||
"integrity": "sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"lodash.merge": "^4.6.2",
|
||||
"needle": "^2.5.2",
|
||||
"stream-parser": "~0.3.1"
|
||||
},
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"node_modules/promise-inflight": {
|
||||
"version": "1.0.1",
|
||||
|
|
@ -4138,7 +4071,8 @@
|
|||
"node_modules/sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.1",
|
||||
|
|
@ -4319,6 +4253,7 @@
|
|||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -4327,6 +4262,7 @@
|
|||
"version": "0.5.21",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"source-map": "^0.6.0"
|
||||
|
|
@ -4414,6 +4350,7 @@
|
|||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz",
|
||||
"integrity": "sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"debug": "2"
|
||||
}
|
||||
|
|
@ -4422,6 +4359,7 @@
|
|||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
|
|
@ -4429,7 +4367,8 @@
|
|||
"node_modules/stream-parser/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
|
|
@ -4832,15 +4771,6 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wordwrap": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
|
||||
"integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/workerpool": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz",
|
||||
|
|
@ -5429,28 +5359,12 @@
|
|||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/mime": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
|
||||
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "14.18.63",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz",
|
||||
"integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node-static": {
|
||||
"version": "0.7.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-static/-/node-static-0.7.7.tgz",
|
||||
"integrity": "sha512-Cq3c9lfC9zRrGxe7ox073219Mpy/kmWNsISG0yEG7aUEk33xv/g+uqz/+4b7hM4WN9LsGageBzGuvy09inaGhg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/mime": "^1",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/nodemailer": {
|
||||
"version": "6.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.7.tgz",
|
||||
|
|
@ -5809,7 +5723,8 @@
|
|||
"buffer-from": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"optional": true
|
||||
},
|
||||
"buffer-writer": {
|
||||
"version": "2.0.0",
|
||||
|
|
@ -5950,12 +5865,6 @@
|
|||
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
|
||||
"optional": true
|
||||
},
|
||||
"colors": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
|
||||
"integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
|
||||
"optional": true
|
||||
},
|
||||
"commander": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
||||
|
|
@ -6580,6 +6489,7 @@
|
|||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
}
|
||||
|
|
@ -6801,7 +6711,8 @@
|
|||
"lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||
"devOptional": true
|
||||
},
|
||||
"log-symbols": {
|
||||
"version": "4.1.0",
|
||||
|
|
@ -6867,12 +6778,6 @@
|
|||
"picomatch": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||
"optional": true
|
||||
},
|
||||
"mimic-response": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||
|
|
@ -6888,12 +6793,6 @@
|
|||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||
"integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==",
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||
|
|
@ -7064,7 +6963,8 @@
|
|||
"ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"devOptional": true
|
||||
},
|
||||
"multiline": {
|
||||
"version": "1.0.2",
|
||||
|
|
@ -7147,6 +7047,7 @@
|
|||
"version": "2.9.1",
|
||||
"resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz",
|
||||
"integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"debug": "^3.2.6",
|
||||
"iconv-lite": "^0.4.4",
|
||||
|
|
@ -7157,6 +7058,7 @@
|
|||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
|
|
@ -7202,17 +7104,6 @@
|
|||
"which": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"node-static": {
|
||||
"version": "0.7.11",
|
||||
"resolved": "https://registry.npmjs.org/node-static/-/node-static-0.7.11.tgz",
|
||||
"integrity": "sha512-zfWC/gICcqb74D9ndyvxZWaI1jzcoHmf4UTHWQchBNuNMxdBLJMDiUgZ1tjGLEIe/BMhj2DxKD8HOuc2062pDQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"colors": ">=0.6.0",
|
||||
"mime": "^1.2.9",
|
||||
"optimist": ">=0.3.4"
|
||||
}
|
||||
},
|
||||
"nodemailer": {
|
||||
"version": "6.8.0",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.8.0.tgz",
|
||||
|
|
@ -7261,16 +7152,6 @@
|
|||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"optimist": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
|
||||
"integrity": "sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "~0.0.1",
|
||||
"wordwrap": "~0.0.2"
|
||||
}
|
||||
},
|
||||
"optionator": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||
|
|
@ -7541,6 +7422,7 @@
|
|||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-7.2.3.tgz",
|
||||
"integrity": "sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"lodash.merge": "^4.6.2",
|
||||
"needle": "^2.5.2",
|
||||
|
|
@ -7695,7 +7577,8 @@
|
|||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
|
||||
"optional": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.7.1",
|
||||
|
|
@ -7814,17 +7697,18 @@
|
|||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"optional": true
|
||||
},
|
||||
"source-map-support": {
|
||||
"version": "0.5.21",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"source-map": "^0.6.0"
|
||||
},
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"split2": {
|
||||
"version": "4.1.0",
|
||||
|
|
@ -7881,6 +7765,7 @@
|
|||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz",
|
||||
"integrity": "sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"debug": "2"
|
||||
},
|
||||
|
|
@ -7889,6 +7774,7 @@
|
|||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
|
|
@ -7896,7 +7782,8 @@
|
|||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -8191,12 +8078,6 @@
|
|||
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
|
||||
"dev": true
|
||||
},
|
||||
"wordwrap": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
|
||||
"integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==",
|
||||
"optional": true
|
||||
},
|
||||
"workerpool": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz",
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
"better-sqlite3": "^11.8.1",
|
||||
"cloud-env": "^0.2.3",
|
||||
"githubhook": "^1.9.3",
|
||||
"node-static": "^0.7.11",
|
||||
"nodemailer": "^6.4.6",
|
||||
"permessage-deflate": "^0.1.7",
|
||||
"pg": "^8.11.3",
|
||||
|
|
@ -72,7 +71,6 @@
|
|||
"@types/better-sqlite3": "7.6.3",
|
||||
"@types/cloud-env": "^0.2.2",
|
||||
"@types/node": "^14.18.63",
|
||||
"@types/node-static": "^0.7.7",
|
||||
"@types/nodemailer": "^6.4.4",
|
||||
"@types/pg": "^8.6.5",
|
||||
"@types/sockjs": "^0.3.33",
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import * as path from 'path';
|
|||
import { crashlogger, ProcessManager, Streams, Repl } from '../lib';
|
||||
import { IPTools } from './ip-tools';
|
||||
import { type ChannelID, extractChannelMessages } from '../sim/battle';
|
||||
import { StaticServer } from '../lib/static-server';
|
||||
|
||||
type StreamWorker = ProcessManager.StreamWorker;
|
||||
|
||||
|
|
@ -271,7 +272,6 @@ export class ServerStream extends Streams.ObjectReadWriteStream<string> {
|
|||
wsdeflate?: typeof Config.wsdeflate,
|
||||
proxyip?: typeof Config.proxyip,
|
||||
customhttpresponse?: typeof Config.customhttpresponse,
|
||||
disablenodestatic?: boolean,
|
||||
}) {
|
||||
super();
|
||||
if (!config.bindaddress) config.bindaddress = '0.0.0.0';
|
||||
|
|
@ -334,8 +334,6 @@ export class ServerStream extends Streams.ObjectReadWriteStream<string> {
|
|||
|
||||
// Static server
|
||||
try {
|
||||
if (config.disablenodestatic) throw new Error("disablenodestatic");
|
||||
const StaticServer: typeof import('node-static').Server = require('node-static').Server;
|
||||
const roomidRegex = /^\/(?:[A-Za-z0-9][A-Za-z0-9-]*)\/?$/;
|
||||
const cssServer = new StaticServer('./config');
|
||||
const avatarServer = new StaticServer('./config/avatars');
|
||||
|
|
@ -350,19 +348,20 @@ export class ServerStream extends Streams.ObjectReadWriteStream<string> {
|
|||
|
||||
let server = staticServer;
|
||||
if (req.url) {
|
||||
if (req.url === '/custom.css') {
|
||||
if (req.url === '/custom.css' || req.url.startsWith('/custom.css?')) {
|
||||
server = cssServer;
|
||||
} else if (req.url.startsWith('/avatars/')) {
|
||||
req.url = req.url.substr(8);
|
||||
req.url = req.url.slice(8);
|
||||
server = avatarServer;
|
||||
} else if (roomidRegex.test(req.url)) {
|
||||
req.url = '/';
|
||||
}
|
||||
}
|
||||
|
||||
server.serve(req, res, e => {
|
||||
if (e && (e as any).status === 404) {
|
||||
staticServer.serveFile('404.html', 404, {}, req, res);
|
||||
void server.serve(req, res, e => {
|
||||
if (e.status === 404) {
|
||||
void staticServer.serveFile('404.html', 404, {}, req, res);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -370,12 +369,8 @@ export class ServerStream extends Streams.ObjectReadWriteStream<string> {
|
|||
|
||||
this.server.on('request', staticRequestHandler);
|
||||
if (this.serverSsl) this.serverSsl.on('request', staticRequestHandler);
|
||||
} catch (e: any) {
|
||||
if (e.message === 'disablenodestatic') {
|
||||
console.log('node-static is disabled');
|
||||
} else {
|
||||
console.log('Could not start node-static - try `npm install` if you want to use it');
|
||||
}
|
||||
} catch {
|
||||
console.log('Could not start static server');
|
||||
}
|
||||
|
||||
// SockJS server
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user