diff --git a/ReadMe.md b/ReadMe.md index 19b6c7e..475797e 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -48,13 +48,14 @@ git clone https://github.com/netcreateorg/netcreate-itest.git ``` cd netcreate-itest +git checkout dev // if you need to switch to a different branch npm ci ``` -If this is your first run with a newly cloned repo, run Net.Create once to set the initial configuration file and build dependent libraries: +If this is your first run with a newly cloned repo, you need to create a new project. Run Net.Create once to set the initial configuration file: ``` -cd netcreate-itest -npm run package +cd ~/your-dev-folder/nc-multiplex/netcreate-itest/ // if necessary +./nc.js --dataset=demo ``` Check your browser to make sure it's running: @@ -67,6 +68,7 @@ Then stop the Net.Create application. ctrl-c ``` + #### 3. Compile Net.Create for Classroom Use `npm run package` to package the app. @@ -110,12 +112,10 @@ cd ~/your-dev-folder/nc-multiplex ``` ***IP Address or Google Analytics Code** -Use the optional `--ip` or `--googlea` parameters if you need -to start the server with a specific IP address or google -analytics code. e.g.: +Use the optional `--ip` parameters if you need +to start the server with a specific IP address. e.g.: `node nc-multiplex.js --ip=192.168.1.40` - `node nc-multiplex.js --googlea=xxxxx` See "Caveats" below for more information. @@ -161,25 +161,11 @@ If you're not logged in, you will get an error. Shortcut: If you have an active valid cookie, you can just go directly to the URL. -#### 10. Generate Tokens - -Any user who wants to edit a graph will need to generate a token. Tokens now only work for specific graphs, so for instance a token for "hawaii" will not allow you to open "tacitus". To generate tokens, in the "Generate Tokens" box: - -1. Select the graph you want to generate tokens for. -2. Enter a Class ID. It can be any string. e.g. you can use this to designate an organization. -3. Enter a Project ID. It can be any string. e.g. you can use this to designate a group. -4. Select the number of tokens to generate. -5. Click "Generate Tokens". -6. Copy the resulting codes. - -You can regenerate the same codes any time. - - ## Managing Databases All databases are stored in the Net.Create runtime folder, e.g. `~/your-dev-folder/nc-multiplex/netcreate-itest/runtime/`. All node processes share the same database files. So any database you spin up will be in the main runtime folder. -* Prepopulate the databases and templates by simply copying the `*.loki` and `*.template` files there prior to running `node nc-multiplex.js`. +* Prepopulate the databases and templates by simply copying the `*.loki` and `*.template` files there prior to running `./start-nc-multiplex.sh`. * You can copy and back up databases directly in the `runtime` folder. @@ -193,7 +179,9 @@ All databases are stored in the Net.Create runtime folder, e.g. `~/your-dev-fold * The database named "base" is always started on port 3000 to handle static file requests. You shouldn't need to touch this graph. -* The default database template used when creating a new project is in `~/your-dev-folder/nc-multiplex/netcreate-itest/app-templates/_default.template`. You can modify this. +* The default database template used when creating a new project is in `~/your-dev-folder/nc-multiplex/netcreate-itest/app-templates/_default.template.toml`. You can modify this. + +* The currently running databases are stored in `~/your-dev-folder/nc-multiplex/.nc-process-state.json`. If this file is present, the currently running databases will be reloaded when the server restarts. ## How it works @@ -226,7 +214,7 @@ To start up: b. `git pull` c. `npm run package` 4. `cd your-dev-folder/nc-mutiplex` -5. `node nc-multiplex.js` +5. `./start-nc-multiplex.sh` --- @@ -246,10 +234,9 @@ Or you can: ## Startup Parameters -Use startup parameters to set the ip address or google analytics code: +Use startup parameters to set the ip address code: * `--ip` -- e.g. `node nc-multiplex.js --ip=192.168.1.40`. See "IP option is for private IP networks" below for more details. -* `--googlea` -- e.g. `node nc-multiplex.js --googlea=xxxxx` ## Variables diff --git a/nc-launch-config.js b/nc-launch-config.js index 84f9eef..6d6d51a 100755 --- a/nc-launch-config.js +++ b/nc-launch-config.js @@ -22,13 +22,19 @@ const REPO_PATHS = [ repo: './netcreate-2018', build: 'build', config: 'app/assets', - pubConfig: 'netcreate-config.js' + pubConfig: 'netcreate-config.js', + runtime: 'runtime', + logs: 'runtime/logs', + backups: 'runtime/backups' }, { repo: './netcreate-itest', build: '', config: 'app-config', - pubConfig: 'config/netcreate-config.js' + pubConfig: 'config/netcreate-config.js', + runtime: 'runtime', + logs: 'runtime/logs', + backups: 'runtime/backups' } ]; @@ -58,10 +64,13 @@ function ScanForRepos() { /// EXPORTS /////////////////////////////////////////////////////////////////// /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const { primary, count, repoExists } = ScanForRepos(); -const { repo, build, config, pubConfig } = primary; +const { repo, build, config, pubConfig, runtime, logs, backups } = primary; const NC_PATH = `./${path.join(repo, build)}`; const NC_SERVER_PATH = `./${path.join(repo, build)}`; const NC_CONFIG_PATH = `./${path.join(repo, build, config)}`; +const NC_RUNTIME_PATH = `./${path.join(repo, build, runtime)}`; +const NC_LOGS_PATH = `./${path.join(repo, build, logs)}`; +const NC_BACKUPS_PATH = `./${path.join(repo, build, backups)}`; const NC_URL_CONFIG = pubConfig; /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - module.exports = { @@ -69,5 +78,8 @@ module.exports = { NC_PATH, NC_SERVER_PATH, NC_CONFIG_PATH, + NC_RUNTIME_PATH, + NC_LOGS_PATH, + NC_BACKUPS_PATH, NC_URL_CONFIG }; diff --git a/nc-multiplex.js b/nc-multiplex.js index 6df225e..85e466b 100644 --- a/nc-multiplex.js +++ b/nc-multiplex.js @@ -11,7 +11,7 @@ If the graph already exists, it will be loaded. Otherwise it will create a new graph. You need to be logged into the manager for this to work. - Manager runs on `http://localhost:80` + Manager runs on `http://localhost:80` by default. Can be overriden with --port=8080 proxied routes / => localhost:80 Root: NetCreate Manager page @@ -20,8 +20,7 @@ flags - node nc-multiplex.js --IP=192.168.1.40 - node nc-multiplex.js --GOOGLEA=xxxxx + node nc-multiplex.js --IP=192.168.1.40 --port=8080 \*\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ * /////////////////////////////////////*/ @@ -33,8 +32,10 @@ const path = require('path'); const express = require('express'); const cookieParser = require('cookie-parser'); const crypto = require('crypto'); +const archiver = require('archiver'); + // session-related imports from netcreate subrepo -const { NC_SERVER_PATH, NC_URL_CONFIG, ScanForRepos } = require('./nc-launch-config'); +const { NC_SERVER_PATH, NC_RUNTIME_PATH, NC_LOGS_PATH, NC_BACKUPS_PATH, NC_URL_CONFIG, ScanForRepos } = require('./nc-launch-config'); const SESSION = require(`${NC_SERVER_PATH}/app/unisys/common-session.js`); // const NCUTILS = require('./modules/nc-utils.js'); @@ -45,7 +46,7 @@ const NCLOG = require('./modules/nc-logging-utils'); const PRE = 'NC_MUX -'; // console.log prefix, match length of netcreate output const SPC = ' '.repeat(PRE.length); /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const PORT_ROUTER = 80; +const DEFAULT_PORT = 80; // default port for the proxy server const PORT_APP = 3000; // base port for nc apps const PORT_WS = 4000; // base port for websockets const DEFAULT_PASSWORD = 'kpop'; // override with SESAME file @@ -60,7 +61,13 @@ const HEARTBEAT = 15; // Minutes. Number of minutes between memory log heartbeat let NVMRC; /// command line flags const argv = require('minimist')(process.argv.slice(2)); -const GOOGLEA = argv['googlea']; +const argv_port = Number(argv['port'] || argv['p']); +let port_override; +if (argv_port && Number.isInteger(argv_port) + && argv_port > 0 && argv_port < 65536 + && (argv_port < PORT_APP || argv_port > PORT_WS + 999)) // don't allow 3000-4999 + port_override = argv_port; +const PORT_ROUTER = port_override || DEFAULT_PORT; const IP = argv['ip']; /// local data structures let m_proxy_pool = []; // array of available port indices, usu [1...100] @@ -69,6 +76,7 @@ let m_child_processes = []; // array of forked process + meta info = { db, port, let HOMEPAGE_EXISTS; // Flag for existence of home.html override let PASSWORD; // Either default password or password in `SESAME` file let PASSWORD_HASH; // Hash generated from password +let SERVER_IP; // IP address of server. Used to tag download filenames. /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const CYN = '\x1b[96m'; // cyan const CYNR = '\x1b[46m'; // reversed cyan @@ -85,6 +93,20 @@ const $T = () => `${strDateStamp()} ${strTimeStamp()}`; // return timestamp stri /// HELPER METHODS //////////////////////////////////////////////////////////// /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +/** return server IP address */ +function m_GetServerIp() { + const interfaces = os.networkInterfaces(); + for (const name of Object.keys(interfaces)) { + for (const iface of interfaces[name]) { + // Skip over internal (i.e., 127.0.0.1) and non-IPv4 addresses + if (iface.family === 'IPv4' && !iface.internal) { + return iface.address; + } + } + } + return 'localhost'; // fallback +} +/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /** return memory parameters */ function m_MemoryReport(unit = 'kb') { const _fmt = x => x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); @@ -176,38 +198,39 @@ function m_SendErrorResponse(res, msg) { } /// SESSION OPERATIONS //////////////////////////////////////////////////////// -/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -/** Generates a list of tokens using the NetCreate common-session module - * REVIEW: Requiring a module from the secondary netcreate-2018 repo - * is a little iffy. - * @param {string} clsId - classId - * @param {string} projId - projectId - * @param {string} dataset - database name - * @param {integer} numGroups - number of tokens to generate - * @return {string} - */ -function MakeToken(clsId, projId, dataset, numGroups) { - // from nc-logic.js - if (typeof clsId !== 'string') - return 'args: str classId, str projId, str dataset, int numGroups'; - if (typeof projId !== 'string') - return 'args: str classId, str projId, str dataset, int numGroups'; - if (typeof dataset !== 'string') - return 'args: str classId, str projId, str dataset, int numGroups'; - if (clsId.length > 12) return 'classId arg1 should be 12 chars or less'; - if (projId.length > 12) return 'classId arg1 should be 12 chars or less'; - if (!Number.isInteger(numGroups)) return 'numGroups arg3 must be integer'; - if (numGroups < 1) return 'numGroups arg3 must be positive integer'; - - let out = `TOKEN LIST for class '${clsId}' project '${projId}' dataset '${dataset}'\n\n`; - let pad = String(numGroups).length; - for (let i = 1; i <= numGroups; i++) { - let id = String(i); - id = id.padStart(pad, '0'); - out += `group ${id}\t${SESSION.MakeToken(clsId, projId, i, dataset)}\n`; - } - return out; -} +// /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// DEPRECATED MakeToken function -- keep in case we need it again +// /** Generates a list of tokens using the NetCreate common-session module +// * REVIEW: Requiring a module from the secondary netcreate-2018 repo +// * is a little iffy. +// * @param {string} clsId - classId +// * @param {string} projId - projectId +// * @param {string} dataset - database name +// * @param {integer} numGroups - number of tokens to generate +// * @return {string} +// */ +// function MakeToken(clsId, projId, dataset, numGroups) { +// // from nc-logic.js +// if (typeof clsId !== 'string') +// return 'args: str classId, str projId, str dataset, int numGroups'; +// if (typeof projId !== 'string') +// return 'args: str classId, str projId, str dataset, int numGroups'; +// if (typeof dataset !== 'string') +// return 'args: str classId, str projId, str dataset, int numGroups'; +// if (clsId.length > 12) return 'classId arg1 should be 12 chars or less'; +// if (projId.length > 12) return 'classId arg1 should be 12 chars or less'; +// if (!Number.isInteger(numGroups)) return 'numGroups arg3 must be integer'; +// if (numGroups < 1) return 'numGroups arg3 must be positive integer'; + +// let out = `TOKEN LIST for class '${clsId}' project '${projId}' dataset '${dataset}'\n\n`; +// let pad = String(numGroups).length; +// for (let i = 1; i <= numGroups; i++) { +// let id = String(i); +// id = id.padStart(pad, '0'); +// out += `group ${id}\t${SESSION.MakeToken(clsId, projId, i, dataset)}\n`; +// } +// return out; +// } /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /** Used to generate a hashed password for use in the cookie * so that password text is not visible in the cookie. @@ -231,8 +254,8 @@ function CookieIsValid(req) { /// PORT POOLING ////////////////////////////////////////////////////////////// /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -/** The proxy server runs on port 80, hosting various management routes as well - * as the /graph// proxying +/** The proxy server runs on port 80 by default, hosting various management + * routes as well as the /graph// proxying * * - Base application port is 3000 * - Base websocket port is 4000 @@ -338,7 +361,8 @@ function RenderManager() { response += ``; response += `
`; response += RenderNewGraphForm(); - response += RenderGenerateTokensForm(); + response += RenderDownloadLogs(); + // response += RenderGenerateTokensForm(); response += `
`; response += RenderMemoryReport(); response += `

page last loaded on: ${m_stat.refreshed.toLocaleTimeString()}

`; @@ -432,43 +456,58 @@ function RenderNewGraphForm() { `; } /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -function RenderGenerateTokensForm() { - let response = `
`; - let dbnames = NCUTILS.GetDatabaseNamesArray().reduce( - (acc, curr) => acc + "', - '' - ); - response += ` - -

Generate Tokens

-
-

Select a database, enter a class id, a project id, and number of tokens to generate. Then click "Generate Tokens".

- - - - -

- -
- `; - response += `
`; - return response; +function RenderDownloadLogs() { + return ` +
+

Download Data

+

Download data for all graphs for ${SERVER_IP} as a zip file. + This includes all data you need to completely restore a droplet + (active graphs, loki, templates, logs) +

+ +
`; } /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// DEPRECATED RenderGenerateTokensForm function -- keep in case we need it again +// function RenderGenerateTokensForm() { +// let response = `
`; +// let dbnames = NCUTILS.GetDatabaseNamesArray().reduce( +// (acc, curr) => acc + "', +// '' +// ); +// response += ` +// +//

Generate Tokens

+//
+//

Select a database, enter a class id, a project id, and number of tokens to generate. Then click "Generate Tokens".

+// +// +// +// +//

+// +//
+// `; +// response += `
`; +// return response; +// } +/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function RenderMemoryReport() { const { sysUsedMB, sysFreeMB, sysTotalMB, sysPercent } = m_MemoryReport(); let response = ''; @@ -542,7 +581,6 @@ function m_PromiseApp(db) { port: ports.appport, netport: ports.netport, portindex: ports.index, - GOOGLEA: GOOGLEA, process: forked }; resolve(newProcessDef); // pass to SpawnApp @@ -561,8 +599,7 @@ function m_PromiseApp(db) { port: ports.appport, netport: ports.netport, process: forked, - IP, - GOOGLEA + IP }; console.log( PRE, @@ -629,7 +666,6 @@ async function LoadProcessState(child_processes, proxy_pool) { port, netport, portindex, - GOOGLEA: GOOGLEA, process: forked }; forked.send(ncStartParams); @@ -688,6 +724,11 @@ console.log('-'.repeat(80)); console.log(PRE, 'nc-multiplex started:', m_stat.start); console.log(PRE); +if (port_override) + console.log(PRE, `${RED}Using port override: ${PORT_ROUTER}${RST}`); +else + console.log(PRE, `${GRN}Using default port: ${PORT_ROUTER}${RST}`); + /// RUNTIME: CHECK FOR BASE REPO ////////////////////////////////////////////// /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const { primary, count } = ScanForRepos(); @@ -832,7 +873,7 @@ async function m_RouterLogic(req) { console.log( PRE, $T(), - `>>> proxying request /graph/${route.db}:80 to :${route.port} (client ${req.ip})` + `>>> proxying request /graph/${route.db}:${PORT_ROUTER} to :${route.port} (client ${req.ip})` ); port = route.port; } else if (PortPoolIsEmpty()) { @@ -1034,23 +1075,235 @@ app.get('/kill/:graph/', (req, res) => { res.send(response); }); /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -/// HANDLE "/maketoken" -- GENERATE TOKENS -app.get('/maketoken/:clsid/:projid/:dataset/:numgroups', (req, res) => { - const { clsid, projid, dataset, numgroups } = req.params; - console.log( - PRE, - $T(), - 'maketoken GET on /maketoken', - clsid, - projid, - dataset, - numgroups +// DEPRECATED RenderGenerateTokensForm function -- keep in case we need it again +// /// HANDLE "/maketoken" -- GENERATE TOKENS +// app.get('/maketoken/:clsid/:projid/:dataset/:numgroups', (req, res) => { +// const { clsid, projid, dataset, numgroups } = req.params; +// console.log( +// PRE, +// $T(), +// 'maketoken GET on /maketoken', +// clsid, +// projid, +// dataset, +// numgroups +// ); +// let response = MakeToken(clsid, projid, dataset, parseInt(numgroups)); +// res.set('Content-Type', 'text/html'); +// res.send(response); +// }); +/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +function m_Archive(folderPath, fileExtensions, zipFilename, req, res) { + if (!CookieIsValid(req)) { + res.redirect(`/error_not_authorized`); + return; + } + + // Create a zip archive of the folder + const archive = archiver('zip', { + zlib: { level: 9 } // Compression level + }); + + archive.on('error', err => { + const errmsg = `Error creating zip: ${err.message}`; + console.log(PRE, errmsg); + m_SendErrorResponse(res, errmsg); + return; + }); + + archive.pipe(res); + + // Add all files from the folder + fs.readdir(folderPath, (err, files) => { + if (err) { + const errmsg = `Error reading folder: ${err.message}`; + console.log(PRE, errmsg); + m_SendErrorResponse(res, errmsg); + return; + } + + // Ensure fileExtensions is an array + if (!Array.isArray(fileExtensions)) { + fileExtensions = [fileExtensions]; + } + // Filter files by the specified extensions and add them to the archive + fileExtensions.map(ext => { + files.filter(file => file.endsWith(ext)).forEach(file => { + const filePath = path.join(folderPath, file); + archive.file(filePath, { name: file }); + }); + }); + + res.setHeader('Content-Disposition', `attachment; filename=${zipFilename}`); + res.setHeader('Content-Type', 'application/zip'); + archive.finalize(); // Finish zipping + }); +} + +/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +/// ARCHIVE MULTIPLE DISCRETE FILES AND FOLDERS +function m_ArchiveMultiple(items, zipFilename, req, res) { + if (!CookieIsValid(req)) { + console.log(PRE, 'DEBUG: Cookie validation failed'); + res.redirect(`/error_not_authorized`); + return; + } + + // Create a zip archive + const archive = archiver('zip', { + zlib: { level: 9 } // Compression level + }); + + archive.on('error', err => { + const errmsg = `Error creating zip: ${err.message}`; + console.log(PRE, errmsg); + m_SendErrorResponse(res, errmsg); + return; + }); + + archive.pipe(res); + + // Set response headers + res.setHeader('Content-Disposition', `attachment; filename=${zipFilename}`); + res.setHeader('Content-Type', 'application/zip'); + + // Process each item and add to archive + const validItems = items.filter(item => { + if (!fs.existsSync(item.path)) { + console.log(PRE, `Warning: ${item.path} does not exist, skipping`); + return false; + } + return true; + }); + + if (validItems.length === 0) { + console.log(PRE, 'No valid items to archive'); + archive.finalize(); + return; + } + + // Add all valid items to the archive + validItems.forEach((item) => { + const itemPath = item.path; + const archiveName = item.name || path.basename(itemPath); + const stats = fs.statSync(itemPath); + + if (stats.isFile()) { + archive.file(itemPath, { name: archiveName }); + } else if (stats.isDirectory()) { + archive.directory(itemPath, archiveName); + } else { + console.log(PRE, `Warning: ${itemPath} is neither file nor directory, skipping`); + } + }); + + // Use setImmediate to ensure all archive operations are queued before finalizing + setImmediate(() => { + console.log(PRE, `Downloading archived data..."${zipFilename}`); + archive.finalize(); + }); +} + +// DEPRECATED: Use single file archive instead +// +// /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// /// HANDLE "/download_all_networks" -- DOWNLOAD LOKI and TEMPLATES +// app.get('/download_all_networks', (req, res) => { +// console.log(PRE, $T(), `GET /download_all_networks (client ${req})`); +// const folderPath = path.join(NC_RUNTIME_PATH); +// const zipFilename = `netcreate_networks_${SERVER_IP}_${$T()}.zip`; +// return m_Archive( +// folderPath, +// ['.loki', '.template.toml'], +// zipFilename, +// req, +// res +// ); +// }); +// /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// /// HANDLE "/download_logs" -- DOWNLOAD RESEARCH LOGS +// app.get('/download_logs', (req, res) => { +// console.log(PRE, $T(), `GET /download_logs (client ${req})`); +// const folderPath = path.join(NC_LOGS_PATH); +// const zipFilename = `netcreate_logs_${SERVER_IP}_${$T()}.zip`; +// return m_Archive( +// folderPath, +// '.txt', +// zipFilename, +// req, +// res +// ); +// }); +// /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// /// HANDLE "/download_lokis" -- DOWNLOAD RESEARCH LOGS +// app.get('/download_lokis', (req, res) => { +// console.log(PRE, $T(), `GET /download_lokis (client ${req.ip})`); +// const folderPath = path.join(NC_RUNTIME_PATH); +// const zipFilename = `netcreate_lokis_${SERVER_IP}_${$T()}.zip`; +// return m_Archive( +// folderPath, +// '.loki', +// zipFilename, +// req, +// res +// ); +// }); +// /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// /// HANDLE "/download_backups" -- DOWNLOAD RESEARCH LOGS +// app.get('/download_backups', (req, res) => { +// console.log(PRE, $T(), `GET /download_backups (client ${req.ip})`); +// const folderPath = path.join(NC_BACKUPS_PATH); +// const zipFilename = `netcreate_backups_${SERVER_IP}_${$T()}.zip`; +// return m_Archive( +// folderPath, +// '.loki', +// zipFilename, +// req, +// res +// ); +// }); +// /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// /// HANDLE "/download_templates" -- DOWNLOAD RESEARCH LOGS +// app.get('/download_templates', (req, res) => { +// console.log(PRE, $T(), `GET /download_templates (client ${req.ip})`); +// const folderPath = path.join(NC_RUNTIME_PATH); +// const zipFilename = `netcreate_templates_${SERVER_IP}_${$T()}.zip`; +// return m_Archive( +// folderPath, +// '.template.toml', +// zipFilename, +// req, +// res +// ); +// }); + +/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +/// HANDLE "/download_data" -- DOWNLOAD CUSTOM DATA ARCHIVE +app.get('/download_data', (req, res) => { + console.log(PRE, $T(), `GET /download_data (client ${req.ip})`); + + // Define the items to archive - customize this array as needed + const itemsToArchive = [ + // nc-process-state.json -- active graphs + { path: '.nc-process-state.json', name: '.nc-process-state.json' }, + // nc-server-start.txt -- log start time + { path: '.nc-server-start.txt', name: '.nc-server-start.txt' }, + // nc-multiplex log file + { path: 'log.txt', name: 'log.txt' }, + // netcreate-itest/runtime folder - will archive entire folder + // including loki, templates, template backups, loki, backup lokis, logs, etc. + { path: NC_RUNTIME_PATH, name: 'runtime' } + ]; + const zipFilename = `netcreate_data_${SERVER_IP}_${$T()}.zip`; + return m_ArchiveMultiple( + itemsToArchive, + zipFilename, + req, + res ); - let response = MakeToken(clsid, projid, dataset, parseInt(numgroups)); - res.set('Content-Type', 'text/html'); - res.send(response); }); + /// EXPRESS MANAGEMENT ROUTES ////////////////////////////////////////////////// /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *\ Authentication uses a cookie with a hashed password. @@ -1163,8 +1416,9 @@ app.use( /// EXPRESS START LISTENING /////////////////////////////////////////////////// /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - app.listen(PORT_ROUTER, () => { + SERVER_IP = m_GetServerIp(); console.log(PRE, $T()); - console.log(PRE, `NC-MULTIPLEX Express Server running on port ${PORT_ROUTER}.`); + console.log(PRE, `NC-MULTIPLEX Express Server running on ${SERVER_IP} port ${PORT_ROUTER}.`); // if .nc-process-state.json exists, read and parse it if (!fs.existsSync('.nc-process-state.json')) { diff --git a/package-lock.json b/package-lock.json index b4c5c32..2b22763 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "archiver": "^7.0.1", "cookie-parser": "^1.4.5", "crypto": "^1.0.1", "express": "^4.17.1", @@ -179,6 +180,50 @@ "dev": true, "peer": true }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -217,6 +262,16 @@ "node": ">= 8" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@types/http-proxy": { "version": "1.17.15", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", @@ -233,6 +288,18 @@ "undici-types": "~6.19.2" } }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -289,8 +356,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "peer": true, "engines": { "node": ">=8" } @@ -299,8 +364,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -311,6 +374,86 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/archiver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", + "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.2", + "async": "^3.2.4", + "buffer-crc32": "^1.0.0", + "readable-stream": "^4.0.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^3.0.0", + "zip-stream": "^6.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", + "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", + "license": "MIT", + "dependencies": { + "glob": "^10.0.0", + "graceful-fs": "^4.2.0", + "is-stream": "^2.0.1", + "lazystream": "^1.0.0", + "lodash": "^4.17.15", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/archiver-utils/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver-utils/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -323,11 +466,50 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/b4a": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "license": "Apache-2.0" + }, "node_modules/balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "node_modules/bare-events": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", + "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", + "license": "Apache-2.0", + "optional": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", @@ -368,6 +550,39 @@ "node": ">=8" } }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -407,8 +622,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -419,9 +632,23 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "peer": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/compress-commons": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", + "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } }, "node_modules/concat-map": { "version": "0.0.1", @@ -472,12 +699,42 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", + "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "peer": true, + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -534,11 +791,23 @@ "node": ">=6.0.0" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -759,11 +1028,29 @@ "node": ">= 0.6" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/express": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", @@ -811,6 +1098,12 @@ "dev": true, "peer": true }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -928,6 +1221,22 @@ "node": ">=4.0" } }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -1009,6 +1318,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -1102,6 +1417,26 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -1177,6 +1512,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -1217,12 +1561,43 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "peer": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } }, "node_modules/js-yaml": { "version": "4.1.0", @@ -1251,6 +1626,42 @@ "dev": true, "peer": true }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1281,6 +1692,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -1288,6 +1705,12 @@ "dev": true, "peer": true }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -1379,6 +1802,15 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -1399,6 +1831,15 @@ "node": ">= 0.6" } }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -1468,6 +1909,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -1520,8 +1967,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "peer": true, "engines": { "node": ">=8" } @@ -1531,6 +1976,22 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -1565,6 +2026,12 @@ "node": ">= 0.6.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, "node_modules/proxy-addr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", @@ -1638,6 +2105,52 @@ "node": ">= 0.8" } }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", @@ -1787,8 +2300,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "peer": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -1800,8 +2311,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "peer": true, "engines": { "node": ">=8" } @@ -1822,6 +2331,18 @@ "node": ">=4" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -1830,12 +2351,130 @@ "node": ">= 0.6" } }, + "node_modules/streamx": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.1.tgz", + "integrity": "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==", + "license": "MIT", + "dependencies": { + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "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==", + "license": "MIT", + "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" + } + ], + "license": "MIT" + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -1916,6 +2555,26 @@ "node": ">=8" } }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -2011,6 +2670,12 @@ "inherits": "2.0.3" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -2031,8 +2696,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "peer": true, "dependencies": { "isexe": "^2.0.0" }, @@ -2043,6 +2706,100 @@ "node": ">= 8" } }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -2081,6 +2838,20 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zip-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", + "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } } } } diff --git a/package.json b/package.json index 5437938..72cced8 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "author": "", "license": "MIT", "dependencies": { + "archiver": "^7.0.1", "cookie-parser": "^1.4.5", "crypto": "^1.0.1", "express": "^4.17.1", diff --git a/start-nc-multiplex-ssl.sh b/start-nc-multiplex-ssl.sh new file mode 100644 index 0000000..71f6a36 --- /dev/null +++ b/start-nc-multiplex-ssl.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# This script starts nc-multiplex.js on port 8080. +# This is useful when using an NGINX reverse proxy server +# to handle SSL, e.g. when deploying on DigitalOcean with HTTPS. + +# this script is intended to be launched by pm2 to ensure that +# the node process is restarted if it crashes, though you can +# also run it directly from the command line. + +# the script is often run using the pm2 process manager. +# [app] is start-nc-multiplex.sh +# pm2 list +# pm2 stop [app] # stop the process in the pm2 list +# pm2 delete [app] # to remove from pm2 list +# pm2 save # to save the current list of processes +# pm2 start [app] # to start the process + +printf "starting nc-multiplex.js on port 8080 for SSL\n" +printf "for pm2 usage: see script comments for command list\n" +printf ".. browse to http://host:8080/manage for control\n" +printf ".. output is appended to log.txt\n" +printf ".. press ctrl+c to stop.\n" + +# start the node process (sri's version) +node nc-multiplex --port=8080 >> log.txt 2>&1 \ No newline at end of file