-
Show playlist
Shuffle playlist
Next
@@ -62,7 +70,7 @@
Station controls should be private
return fetch(route)
.then(res => res.json())
.then(x => {
- console.log(x);
+ console.log(route, x);
return x;
})
}
@@ -75,17 +83,16 @@
Station controls should be private
return urlCreator.createObjectURL(blob);
}
- function info() {
- request('/info')
+ function getCurrentTrack() {
+ request('/getCurrentTrackInfo')
.then(cur => {
- document.getElementById('artist').innerHTML = `Artist: ${cur.artist}`;
- document.getElementById('title').innerHTML = `Title: ${cur.title}`;
+ document.getElementById('artist-value').innerHTML = cur.artist;
+ document.getElementById('title-value').innerHTML = cur.title;
document.getElementById('cover').src = getCoverUrl(cur.image)
})
}
- function controlsGetPlaylist() {
- document.getElementById('getPlaylist').innerHTML = ''
- request('/controls/getPlaylist')
+ function getPlaylist() {
+ request('/getPlaylist')
.then((plist) => {
const parent = document.getElementById('getPlaylist');
parent.innerHTML = '';
@@ -101,14 +108,24 @@
Station controls should be private
})
}
function controlsShufflePlaylist() {
- request('/controls/shufflePlaylist').then(controlsGetPlaylist)
+ request('/controls/shufflePlaylist').then(update)
}
function controlsNext() {
- request('/controls/next').then(controlsGetPlaylist).then(info)
+ request('/controls/next').then(update)
}
function controlsRearrange({ oldIndex, newIndex }) {
- request(`/controls/rearrangePlaylist?oldIndex=${oldIndex}&newIndex=${newIndex}`).then(controlsGetPlaylist)
+ request(`/controls/rearrangePlaylist?oldIndex=${oldIndex}&newIndex=${newIndex}`).then(getPlaylist)
+ }
+
+ // short polling results and applying them after prebuffer length is applied
+ function update() {
+ return Promise.all([getCurrentTrack(), getPlaylist()])
}
+ setInterval(() => {
+ update()
+ }, 2000)
+ update()
+
Sortable.create(document.getElementById('getPlaylist'), { onEnd: controlsRearrange });
diff --git a/examples/server.ts b/examples/server.ts
index 5519a87..e2a5a2a 100644
--- a/examples/server.ts
+++ b/examples/server.ts
@@ -1,16 +1,18 @@
/* eslint-disable no-console */
import path from 'path';
import express from 'express';
-import { SHUFFLE_METHODS, PUBLIC_EVENTS, Station } from '../src/index';
+import { SHUFFLE_METHODS, PUBLIC_EVENTS, Station, DEFAULTS } from '../src/index';
import type { ShallowTrackMeta } from '../src/index';
const port = 3001;
const server = express();
const musicPath = path.resolve(process.cwd(), process.argv[2] || './examples/music');
+const prebufferLength = DEFAULTS.PREBUFFER_LENGTH;
const station = new Station({
verbose: true, // for verbose logging to console
responseHeaders: { 'icy-genre': 'jazz' },
+ prebufferLength,
});
// add folder to station
station.addFolder(musicPath);
@@ -19,16 +21,14 @@ station.addFolder(musicPath);
let currentTrack: ShallowTrackMeta;
station.on(PUBLIC_EVENTS.NEXT_TRACK, async (track) => {
const result = await track.getMetaAsync();
- currentTrack = result;
-});
-
-station.on(PUBLIC_EVENTS.START, () => {
- // double the playlist on start
- station.reorderPlaylist((a) => a.concat(a));
-});
-
-station.on(PUBLIC_EVENTS.RESTART, () => {
- station.reorderPlaylist((a) => a.concat(a));
+ if (!currentTrack) {
+ currentTrack = result;
+ } else {
+ // in order to compensate a lag between the server and client
+ setTimeout(() => {
+ currentTrack = result;
+ }, prebufferLength * 1000);
+ }
});
// add this handler - otherwise any error will exit the process as unhandled
@@ -41,10 +41,16 @@ server.get('/stream', (req, res) => {
});
// get id3 tags of the track
-server.get('/info', (_, res) => {
+server.get('/getCurrentTrackInfo', (_, res) => {
res.json(currentTrack);
});
+// just get the entire playlist
+server.get('/getPlaylist', (_, res) => {
+ const plist = station.getPlaylist();
+ res.json(plist);
+});
+
// switch to the next track immediately
server.get('/controls/next', (_, res) => {
station.next();
@@ -64,12 +70,6 @@ server.get('/controls/rearrangePlaylist', (req, res) => {
res.json(`Succesfully moved element from "${oldIndex}" to "${newIndex}"`);
});
-// just get the entire playlist
-server.get('/controls/getPlaylist', (_, res) => {
- const plist = station.getPlaylist();
- res.json(plist);
-});
-
// route for serving static
server.get('*', (_, res) => {
res.sendFile(path.resolve(__dirname, './example.html'));
diff --git a/package-lock.json b/package-lock.json
index c847a60..8d1312b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,14 +1,15 @@
{
"name": "@fridgefm/radio-core",
- "version": "3.1.5",
+ "version": "3.2.5",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@fridgefm/radio-core",
- "version": "3.1.5",
+ "version": "3.2.5",
"license": "MIT",
"dependencies": {
+ "@fridgefm/inverter": "^0.1.9",
"chalk": "^4.1.2",
"dev-null": "^0.1.1",
"fs-extra": "^11.0.1",
@@ -17,7 +18,7 @@
"klaw-sync": "^6.0.0",
"node-id3": "^0.2.6",
"typed-emitter": "^2.1.0",
- "winston": "^3.3.3"
+ "winston": "^3.10.0"
},
"devDependencies": {
"@types/express": "^4.17.13",
@@ -659,6 +660,14 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
+ "node_modules/@colors/colors": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
+ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"dev": true,
@@ -1082,6 +1091,14 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/@fridgefm/inverter": {
+ "version": "0.1.16",
+ "resolved": "https://registry.npmjs.org/@fridgefm/inverter/-/inverter-0.1.16.tgz",
+ "integrity": "sha512-GR6s/nkXbDA7U4b9RWUIxm5eLcGF5MDUWV4OSfq6RjfVabQ+XI4T/FyDdgt0ST7cdPc5+7ndeQ1wcOwdYg49/w==",
+ "engines": {
+ "node": ">=14.0"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.6.0",
"dev": true,
@@ -1842,6 +1859,11 @@
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
"dev": true
},
+ "node_modules/@types/triple-beam": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.3.tgz",
+ "integrity": "sha512-6tOUG+nVHn0cJbVp25JFayS5UE6+xlbcNF9Lo9mU7U0zk3zeUShZied4YEQZjy1JBF043FSkdXw8YkUJuVtB5g=="
+ },
"node_modules/@types/yargs": {
"version": "17.0.24",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
@@ -2088,12 +2110,13 @@
}
},
"node_modules/accepts": {
- "version": "1.3.7",
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "mime-types": "~2.1.24",
- "negotiator": "0.6.2"
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
},
"engines": {
"node": ">= 0.6"
@@ -2380,8 +2403,9 @@
}
},
"node_modules/async": {
- "version": "3.2.1",
- "license": "MIT"
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
+ "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ=="
},
"node_modules/available-typed-arrays": {
"version": "1.0.5",
@@ -2512,37 +2536,43 @@
"license": "MIT"
},
"node_modules/body-parser": {
- "version": "1.19.0",
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
+ "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "bytes": "3.1.0",
+ "bytes": "3.1.2",
"content-type": "~1.0.4",
"debug": "2.6.9",
- "depd": "~1.1.2",
- "http-errors": "1.7.2",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
"iconv-lite": "0.4.24",
- "on-finished": "~2.3.0",
- "qs": "6.7.0",
- "raw-body": "2.4.0",
- "type-is": "~1.6.17"
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.1",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
},
"engines": {
- "node": ">= 0.8"
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/body-parser/node_modules/debug": {
"version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/body-parser/node_modules/ms": {
"version": "2.0.0",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true
},
"node_modules/brace-expansion": {
"version": "1.1.11",
@@ -2622,9 +2652,10 @@
"license": "MIT"
},
"node_modules/bytes": {
- "version": "3.1.0",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 0.8"
}
@@ -2783,13 +2814,6 @@
"simple-swizzle": "^0.2.2"
}
},
- "node_modules/colors": {
- "version": "1.4.0",
- "license": "MIT",
- "engines": {
- "node": ">=0.1.90"
- }
- },
"node_modules/colorspace": {
"version": "1.1.4",
"license": "MIT",
@@ -2809,20 +2833,22 @@
"license": "MIT"
},
"node_modules/content-disposition": {
- "version": "0.5.3",
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "safe-buffer": "5.1.2"
+ "safe-buffer": "5.2.1"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/content-type": {
- "version": "1.0.4",
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -2834,9 +2860,10 @@
"dev": true
},
"node_modules/cookie": {
- "version": "0.4.0",
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -2846,10 +2873,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/core-util-is": {
- "version": "1.0.3",
- "license": "MIT"
- },
"node_modules/create-require": {
"version": "1.1.1",
"dev": true,
@@ -2935,11 +2958,12 @@
}
},
"node_modules/depd": {
- "version": "1.1.2",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"dev": true,
- "license": "MIT",
"engines": {
- "node": ">= 0.6"
+ "node": ">= 0.8"
}
},
"node_modules/dequal": {
@@ -2953,9 +2977,14 @@
}
},
"node_modules/destroy": {
- "version": "1.0.4",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
"dev": true,
- "license": "MIT"
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
},
"node_modules/detect-newline": {
"version": "3.1.0",
@@ -3013,8 +3042,9 @@
},
"node_modules/ee-first": {
"version": "1.1.1",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "dev": true
},
"node_modules/electron-to-chromium": {
"version": "1.4.468",
@@ -3045,8 +3075,9 @@
},
"node_modules/encodeurl": {
"version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 0.8"
}
@@ -3217,8 +3248,9 @@
},
"node_modules/escape-html": {
"version": "1.0.3",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "dev": true
},
"node_modules/escape-string-regexp": {
"version": "4.0.0",
@@ -4023,8 +4055,9 @@
},
"node_modules/etag": {
"version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -4079,37 +4112,39 @@
}
},
"node_modules/express": {
- "version": "4.17.1",
+ "version": "4.18.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
+ "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "accepts": "~1.3.7",
+ "accepts": "~1.3.8",
"array-flatten": "1.1.1",
- "body-parser": "1.19.0",
- "content-disposition": "0.5.3",
+ "body-parser": "1.20.1",
+ "content-disposition": "0.5.4",
"content-type": "~1.0.4",
- "cookie": "0.4.0",
+ "cookie": "0.5.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
- "depd": "~1.1.2",
+ "depd": "2.0.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
- "finalhandler": "~1.1.2",
+ "finalhandler": "1.2.0",
"fresh": "0.5.2",
+ "http-errors": "2.0.0",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
- "on-finished": "~2.3.0",
+ "on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
- "proxy-addr": "~2.0.5",
- "qs": "6.7.0",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.11.0",
"range-parser": "~1.2.1",
- "safe-buffer": "5.1.2",
- "send": "0.17.1",
- "serve-static": "1.14.1",
- "setprototypeof": "1.1.1",
- "statuses": "~1.5.0",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
@@ -4184,8 +4219,9 @@
}
},
"node_modules/fecha": {
- "version": "4.2.1",
- "license": "MIT"
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
+ "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="
},
"node_modules/file-entry-cache": {
"version": "6.0.1",
@@ -4210,16 +4246,17 @@
}
},
"node_modules/finalhandler": {
- "version": "1.1.2",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
"dev": true,
- "license": "MIT",
"dependencies": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
- "on-finished": "~2.3.0",
+ "on-finished": "2.4.1",
"parseurl": "~1.3.3",
- "statuses": "~1.5.0",
+ "statuses": "2.0.1",
"unpipe": "~1.0.0"
},
"engines": {
@@ -4228,16 +4265,18 @@
},
"node_modules/finalhandler/node_modules/debug": {
"version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/finalhandler/node_modules/ms": {
"version": "2.0.0",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true
},
"node_modules/find-up": {
"version": "2.1.0",
@@ -4290,8 +4329,9 @@
},
"node_modules/fresh": {
"version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -4642,25 +4682,21 @@
"dev": true
},
"node_modules/http-errors": {
- "version": "1.7.2",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "depd": "~1.1.2",
- "inherits": "2.0.3",
- "setprototypeof": "1.1.1",
- "statuses": ">= 1.5.0 < 2",
- "toidentifier": "1.0.0"
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
},
"engines": {
- "node": ">= 0.6"
+ "node": ">= 0.8"
}
},
- "node_modules/http-errors/node_modules/inherits": {
- "version": "2.0.3",
- "dev": true,
- "license": "ISC"
- },
"node_modules/human-signals": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
@@ -4672,8 +4708,9 @@
},
"node_modules/iconv-lite": {
"version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
@@ -5103,10 +5140,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/isarray": {
- "version": "1.0.0",
- "license": "MIT"
- },
"node_modules/isexe": {
"version": "2.0.0",
"dev": true,
@@ -6003,13 +6036,15 @@
"peer": true
},
"node_modules/logform": {
- "version": "2.3.0",
- "license": "MIT",
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz",
+ "integrity": "sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==",
"dependencies": {
- "colors": "^1.2.1",
+ "@colors/colors": "1.5.0",
+ "@types/triple-beam": "^1.3.2",
"fecha": "^4.2.0",
"ms": "^2.1.1",
- "safe-stable-stringify": "^1.1.0",
+ "safe-stable-stringify": "^2.3.1",
"triple-beam": "^1.3.0"
}
},
@@ -6077,8 +6112,9 @@
},
"node_modules/media-typer": {
"version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -6124,8 +6160,9 @@
},
"node_modules/mime": {
"version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"dev": true,
- "license": "MIT",
"bin": {
"mime": "cli.js"
},
@@ -6134,19 +6171,21 @@
}
},
"node_modules/mime-db": {
- "version": "1.50.0",
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
- "version": "2.1.33",
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "mime-db": "1.50.0"
+ "mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
@@ -6174,9 +6213,13 @@
}
},
"node_modules/minimist": {
- "version": "1.2.5",
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true,
- "license": "MIT"
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
},
"node_modules/ms": {
"version": "2.1.3",
@@ -6188,9 +6231,10 @@
"license": "MIT"
},
"node_modules/negotiator": {
- "version": "0.6.2",
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -6354,9 +6398,10 @@
}
},
"node_modules/on-finished": {
- "version": "2.3.0",
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"dev": true,
- "license": "MIT",
"dependencies": {
"ee-first": "1.1.1"
},
@@ -6490,8 +6535,9 @@
},
"node_modules/parseurl": {
"version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 0.8"
}
@@ -6623,10 +6669,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/process-nextick-args": {
- "version": "2.0.1",
- "license": "MIT"
- },
"node_modules/progress": {
"version": "2.0.3",
"dev": true,
@@ -6704,11 +6746,18 @@
]
},
"node_modules/qs": {
- "version": "6.7.0",
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"dev": true,
- "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
"engines": {
"node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/queue-microtask": {
@@ -6732,19 +6781,21 @@
},
"node_modules/range-parser": {
"version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/raw-body": {
- "version": "2.4.0",
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+ "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "bytes": "3.1.0",
- "http-errors": "1.7.2",
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
},
@@ -6960,8 +7011,23 @@
"dev": true
},
"node_modules/safe-buffer": {
- "version": "5.1.2",
- "license": "MIT"
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
},
"node_modules/safe-regex-test": {
"version": "1.0.0",
@@ -6978,8 +7044,12 @@
}
},
"node_modules/safe-stable-stringify": {
- "version": "1.1.1",
- "license": "MIT"
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz",
+ "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==",
+ "engines": {
+ "node": ">=10"
+ }
},
"node_modules/safer-buffer": {
"version": "2.1.2",
@@ -7001,23 +7071,24 @@
}
},
"node_modules/send": {
- "version": "0.17.1",
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
"dev": true,
- "license": "MIT",
"dependencies": {
"debug": "2.6.9",
- "depd": "~1.1.2",
- "destroy": "~1.0.4",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
- "http-errors": "~1.7.2",
+ "http-errors": "2.0.0",
"mime": "1.6.0",
- "ms": "2.1.1",
- "on-finished": "~2.3.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
"range-parser": "~1.2.1",
- "statuses": "~1.5.0"
+ "statuses": "2.0.1"
},
"engines": {
"node": ">= 0.8.0"
@@ -7025,55 +7096,39 @@
},
"node_modules/send/node_modules/debug": {
"version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/send/node_modules/debug/node_modules/ms": {
"version": "2.0.0",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/send/node_modules/http-errors": {
- "version": "1.7.3",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "depd": "~1.1.2",
- "inherits": "2.0.4",
- "setprototypeof": "1.1.1",
- "statuses": ">= 1.5.0 < 2",
- "toidentifier": "1.0.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/send/node_modules/ms": {
- "version": "2.1.1",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true
},
"node_modules/serve-static": {
- "version": "1.14.1",
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
"dev": true,
- "license": "MIT",
"dependencies": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
- "send": "0.17.1"
+ "send": "0.18.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/setprototypeof": {
- "version": "1.1.1",
- "dev": true,
- "license": "ISC"
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "dev": true
},
"node_modules/shebang-command": {
"version": "2.0.0",
@@ -7204,11 +7259,12 @@
}
},
"node_modules/statuses": {
- "version": "1.5.0",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"dev": true,
- "license": "MIT",
"engines": {
- "node": ">= 0.6"
+ "node": ">= 0.8"
}
},
"node_modules/string_decoder": {
@@ -7218,24 +7274,6 @@
"safe-buffer": "~5.2.0"
}
},
- "node_modules/string_decoder/node_modules/safe-buffer": {
- "version": "5.2.1",
- "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-length": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
@@ -7479,16 +7517,21 @@
}
},
"node_modules/toidentifier": {
- "version": "1.0.0",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=0.6"
}
},
"node_modules/triple-beam": {
- "version": "1.3.0",
- "license": "MIT"
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
+ "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==",
+ "engines": {
+ "node": ">= 14.0.0"
+ }
},
"node_modules/ts-jest": {
"version": "29.1.1",
@@ -7602,9 +7645,10 @@
}
},
"node_modules/tsconfig-paths/node_modules/json5": {
- "version": "1.0.1",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+ "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"minimist": "^1.2.0"
},
@@ -7670,8 +7714,9 @@
},
"node_modules/type-is": {
"version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"dev": true,
- "license": "MIT",
"dependencies": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
@@ -7790,8 +7835,9 @@
},
"node_modules/unpipe": {
"version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 0.8"
}
@@ -7955,58 +8001,44 @@
}
},
"node_modules/winston": {
- "version": "3.3.3",
- "license": "MIT",
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/winston/-/winston-3.10.0.tgz",
+ "integrity": "sha512-nT6SIDaE9B7ZRO0u3UvdrimG0HkB7dSTAgInQnNR2SOPJ4bvq5q79+pXLftKmP52lJGW15+H5MCK0nM9D3KB/g==",
"dependencies": {
+ "@colors/colors": "1.5.0",
"@dabh/diagnostics": "^2.0.2",
- "async": "^3.1.0",
+ "async": "^3.2.3",
"is-stream": "^2.0.0",
- "logform": "^2.2.0",
+ "logform": "^2.4.0",
"one-time": "^1.0.0",
"readable-stream": "^3.4.0",
+ "safe-stable-stringify": "^2.3.1",
"stack-trace": "0.0.x",
"triple-beam": "^1.3.0",
- "winston-transport": "^4.4.0"
+ "winston-transport": "^4.5.0"
},
"engines": {
- "node": ">= 6.4.0"
+ "node": ">= 12.0.0"
}
},
"node_modules/winston-transport": {
- "version": "4.4.0",
- "license": "MIT",
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz",
+ "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==",
"dependencies": {
- "readable-stream": "^2.3.7",
- "triple-beam": "^1.2.0"
+ "logform": "^2.3.2",
+ "readable-stream": "^3.6.0",
+ "triple-beam": "^1.3.0"
},
"engines": {
"node": ">= 6.4.0"
}
},
- "node_modules/winston-transport/node_modules/readable-stream": {
- "version": "2.3.7",
- "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/winston-transport/node_modules/string_decoder": {
- "version": "1.1.1",
- "license": "MIT",
- "dependencies": {
- "safe-buffer": "~5.1.0"
- }
- },
"node_modules/word-wrap": {
- "version": "1.2.3",
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@@ -8573,6 +8605,11 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
+ "@colors/colors": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
+ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="
+ },
"@cspotcode/source-map-support": {
"version": "0.8.1",
"dev": true,
@@ -8789,6 +8826,11 @@
"strip-json-comments": "^3.1.1"
}
},
+ "@fridgefm/inverter": {
+ "version": "0.1.16",
+ "resolved": "https://registry.npmjs.org/@fridgefm/inverter/-/inverter-0.1.16.tgz",
+ "integrity": "sha512-GR6s/nkXbDA7U4b9RWUIxm5eLcGF5MDUWV4OSfq6RjfVabQ+XI4T/FyDdgt0ST7cdPc5+7ndeQ1wcOwdYg49/w=="
+ },
"@humanwhocodes/config-array": {
"version": "0.6.0",
"dev": true,
@@ -9428,6 +9470,11 @@
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
"dev": true
},
+ "@types/triple-beam": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.3.tgz",
+ "integrity": "sha512-6tOUG+nVHn0cJbVp25JFayS5UE6+xlbcNF9Lo9mU7U0zk3zeUShZied4YEQZjy1JBF043FSkdXw8YkUJuVtB5g=="
+ },
"@types/yargs": {
"version": "17.0.24",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
@@ -9563,11 +9610,13 @@
}
},
"accepts": {
- "version": "1.3.7",
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"dev": true,
"requires": {
- "mime-types": "~2.1.24",
- "negotiator": "0.6.2"
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
}
},
"acorn": {
@@ -9764,7 +9813,9 @@
"peer": true
},
"async": {
- "version": "3.2.1"
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
+ "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ=="
},
"available-typed-arrays": {
"version": "1.0.5",
@@ -9864,23 +9915,29 @@
"dev": true
},
"body-parser": {
- "version": "1.19.0",
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
+ "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
"dev": true,
"requires": {
- "bytes": "3.1.0",
+ "bytes": "3.1.2",
"content-type": "~1.0.4",
"debug": "2.6.9",
- "depd": "~1.1.2",
- "http-errors": "1.7.2",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
"iconv-lite": "0.4.24",
- "on-finished": "~2.3.0",
- "qs": "6.7.0",
- "raw-body": "2.4.0",
- "type-is": "~1.6.17"
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.1",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"requires": {
"ms": "2.0.0"
@@ -9888,6 +9945,8 @@
},
"ms": {
"version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"dev": true
}
}
@@ -9940,7 +9999,9 @@
"dev": true
},
"bytes": {
- "version": "3.1.0",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"dev": true
},
"call-bind": {
@@ -10043,9 +10104,6 @@
"simple-swizzle": "^0.2.2"
}
},
- "colors": {
- "version": "1.4.0"
- },
"colorspace": {
"version": "1.1.4",
"requires": {
@@ -10062,14 +10120,18 @@
"dev": true
},
"content-disposition": {
- "version": "0.5.3",
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"dev": true,
"requires": {
- "safe-buffer": "5.1.2"
+ "safe-buffer": "5.2.1"
}
},
"content-type": {
- "version": "1.0.4",
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"dev": true
},
"convert-source-map": {
@@ -10079,16 +10141,15 @@
"dev": true
},
"cookie": {
- "version": "0.4.0",
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
"dev": true
},
"cookie-signature": {
"version": "1.0.6",
"dev": true
},
- "core-util-is": {
- "version": "1.0.3"
- },
"create-require": {
"version": "1.1.1",
"dev": true,
@@ -10151,7 +10212,9 @@
}
},
"depd": {
- "version": "1.1.2",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"dev": true
},
"dequal": {
@@ -10162,7 +10225,9 @@
"peer": true
},
"destroy": {
- "version": "1.0.4",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
"dev": true
},
"detect-newline": {
@@ -10202,6 +10267,8 @@
},
"ee-first": {
"version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
"dev": true
},
"electron-to-chromium": {
@@ -10225,6 +10292,8 @@
},
"encodeurl": {
"version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
"dev": true
},
"enquirer": {
@@ -10365,6 +10434,8 @@
},
"escape-html": {
"version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
"dev": true
},
"escape-string-regexp": {
@@ -10921,6 +10992,8 @@
},
"etag": {
"version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
"dev": true
},
"execa": {
@@ -10961,36 +11034,39 @@
}
},
"express": {
- "version": "4.17.1",
+ "version": "4.18.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
+ "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
"dev": true,
"requires": {
- "accepts": "~1.3.7",
+ "accepts": "~1.3.8",
"array-flatten": "1.1.1",
- "body-parser": "1.19.0",
- "content-disposition": "0.5.3",
+ "body-parser": "1.20.1",
+ "content-disposition": "0.5.4",
"content-type": "~1.0.4",
- "cookie": "0.4.0",
+ "cookie": "0.5.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
- "depd": "~1.1.2",
+ "depd": "2.0.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
- "finalhandler": "~1.1.2",
+ "finalhandler": "1.2.0",
"fresh": "0.5.2",
+ "http-errors": "2.0.0",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
- "on-finished": "~2.3.0",
+ "on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
- "proxy-addr": "~2.0.5",
- "qs": "6.7.0",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.11.0",
"range-parser": "~1.2.1",
- "safe-buffer": "5.1.2",
- "send": "0.17.1",
- "serve-static": "1.14.1",
- "setprototypeof": "1.1.1",
- "statuses": "~1.5.0",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
@@ -11053,7 +11129,9 @@
}
},
"fecha": {
- "version": "4.2.1"
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
+ "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="
},
"file-entry-cache": {
"version": "6.0.1",
@@ -11070,20 +11148,24 @@
}
},
"finalhandler": {
- "version": "1.1.2",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
"dev": true,
"requires": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
- "on-finished": "~2.3.0",
+ "on-finished": "2.4.1",
"parseurl": "~1.3.3",
- "statuses": "~1.5.0",
+ "statuses": "2.0.1",
"unpipe": "~1.0.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"requires": {
"ms": "2.0.0"
@@ -11091,6 +11173,8 @@
},
"ms": {
"version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"dev": true
}
}
@@ -11132,6 +11216,8 @@
},
"fresh": {
"version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
"dev": true
},
"fs-extra": {
@@ -11359,20 +11445,16 @@
"dev": true
},
"http-errors": {
- "version": "1.7.2",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"dev": true,
"requires": {
- "depd": "~1.1.2",
- "inherits": "2.0.3",
- "setprototypeof": "1.1.1",
- "statuses": ">= 1.5.0 < 2",
- "toidentifier": "1.0.0"
- },
- "dependencies": {
- "inherits": {
- "version": "2.0.3",
- "dev": true
- }
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
}
},
"human-signals": {
@@ -11383,6 +11465,8 @@
},
"iconv-lite": {
"version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dev": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
@@ -11653,9 +11737,6 @@
"call-bind": "^1.0.2"
}
},
- "isarray": {
- "version": "1.0.0"
- },
"isexe": {
"version": "2.0.0",
"dev": true
@@ -12344,12 +12425,15 @@
"peer": true
},
"logform": {
- "version": "2.3.0",
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz",
+ "integrity": "sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==",
"requires": {
- "colors": "^1.2.1",
+ "@colors/colors": "1.5.0",
+ "@types/triple-beam": "^1.3.2",
"fecha": "^4.2.0",
"ms": "^2.1.1",
- "safe-stable-stringify": "^1.1.0",
+ "safe-stable-stringify": "^2.3.1",
"triple-beam": "^1.3.0"
}
},
@@ -12402,6 +12486,8 @@
},
"media-typer": {
"version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
"dev": true
},
"merge-descriptors": {
@@ -12432,17 +12518,23 @@
},
"mime": {
"version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"dev": true
},
"mime-db": {
- "version": "1.50.0",
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true
},
"mime-types": {
- "version": "2.1.33",
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"requires": {
- "mime-db": "1.50.0"
+ "mime-db": "1.52.0"
}
},
"mimic-fn": {
@@ -12461,7 +12553,9 @@
}
},
"minimist": {
- "version": "1.2.5",
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true
},
"ms": {
@@ -12472,7 +12566,9 @@
"dev": true
},
"negotiator": {
- "version": "0.6.2",
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"dev": true
},
"node-id3": {
@@ -12591,7 +12687,9 @@
}
},
"on-finished": {
- "version": "2.3.0",
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"dev": true,
"requires": {
"ee-first": "1.1.1"
@@ -12683,6 +12781,8 @@
},
"parseurl": {
"version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
"dev": true
},
"path-exists": {
@@ -12762,9 +12862,6 @@
}
}
},
- "process-nextick-args": {
- "version": "2.0.1"
- },
"progress": {
"version": "2.0.3",
"dev": true
@@ -12819,8 +12916,13 @@
"dev": true
},
"qs": {
- "version": "6.7.0",
- "dev": true
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "dev": true,
+ "requires": {
+ "side-channel": "^1.0.4"
+ }
},
"queue-microtask": {
"version": "1.2.3",
@@ -12828,14 +12930,18 @@
},
"range-parser": {
"version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
"dev": true
},
"raw-body": {
- "version": "2.4.0",
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+ "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
"dev": true,
"requires": {
- "bytes": "3.1.0",
- "http-errors": "1.7.2",
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
}
@@ -12980,7 +13086,9 @@
}
},
"safe-buffer": {
- "version": "5.1.2"
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"safe-regex-test": {
"version": "1.0.0",
@@ -12994,7 +13102,9 @@
}
},
"safe-stable-stringify": {
- "version": "1.1.1"
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz",
+ "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g=="
},
"safer-buffer": {
"version": "2.1.2"
@@ -13009,26 +13119,30 @@
}
},
"send": {
- "version": "0.17.1",
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
"dev": true,
"requires": {
"debug": "2.6.9",
- "depd": "~1.1.2",
- "destroy": "~1.0.4",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
- "http-errors": "~1.7.2",
+ "http-errors": "2.0.0",
"mime": "1.6.0",
- "ms": "2.1.1",
- "on-finished": "~2.3.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
"range-parser": "~1.2.1",
- "statuses": "~1.5.0"
+ "statuses": "2.0.1"
},
"dependencies": {
"debug": {
"version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"requires": {
"ms": "2.0.0"
@@ -13036,39 +13150,30 @@
"dependencies": {
"ms": {
"version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"dev": true
}
}
- },
- "http-errors": {
- "version": "1.7.3",
- "dev": true,
- "requires": {
- "depd": "~1.1.2",
- "inherits": "2.0.4",
- "setprototypeof": "1.1.1",
- "statuses": ">= 1.5.0 < 2",
- "toidentifier": "1.0.0"
- }
- },
- "ms": {
- "version": "2.1.1",
- "dev": true
}
}
},
"serve-static": {
- "version": "1.14.1",
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
"dev": true,
"requires": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
- "send": "0.17.1"
+ "send": "0.18.0"
}
},
"setprototypeof": {
- "version": "1.1.1",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
"dev": true
},
"shebang-command": {
@@ -13164,18 +13269,15 @@
}
},
"statuses": {
- "version": "1.5.0",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"dev": true
},
"string_decoder": {
"version": "1.3.0",
"requires": {
"safe-buffer": "~5.2.0"
- },
- "dependencies": {
- "safe-buffer": {
- "version": "5.2.1"
- }
}
},
"string-length": {
@@ -13353,11 +13455,15 @@
}
},
"toidentifier": {
- "version": "1.0.0",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"dev": true
},
"triple-beam": {
- "version": "1.3.0"
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
+ "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg=="
},
"ts-jest": {
"version": "29.1.1",
@@ -13415,7 +13521,9 @@
},
"dependencies": {
"json5": {
- "version": "1.0.1",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+ "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
@@ -13458,6 +13566,8 @@
},
"type-is": {
"version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"dev": true,
"requires": {
"media-typer": "0.3.0",
@@ -13542,6 +13652,8 @@
},
"unpipe": {
"version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
"dev": true
},
"update-browserslist-db": {
@@ -13654,48 +13766,37 @@
}
},
"winston": {
- "version": "3.3.3",
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/winston/-/winston-3.10.0.tgz",
+ "integrity": "sha512-nT6SIDaE9B7ZRO0u3UvdrimG0HkB7dSTAgInQnNR2SOPJ4bvq5q79+pXLftKmP52lJGW15+H5MCK0nM9D3KB/g==",
"requires": {
+ "@colors/colors": "1.5.0",
"@dabh/diagnostics": "^2.0.2",
- "async": "^3.1.0",
+ "async": "^3.2.3",
"is-stream": "^2.0.0",
- "logform": "^2.2.0",
+ "logform": "^2.4.0",
"one-time": "^1.0.0",
"readable-stream": "^3.4.0",
+ "safe-stable-stringify": "^2.3.1",
"stack-trace": "0.0.x",
"triple-beam": "^1.3.0",
- "winston-transport": "^4.4.0"
+ "winston-transport": "^4.5.0"
}
},
"winston-transport": {
- "version": "4.4.0",
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz",
+ "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==",
"requires": {
- "readable-stream": "^2.3.7",
- "triple-beam": "^1.2.0"
- },
- "dependencies": {
- "readable-stream": {
- "version": "2.3.7",
- "requires": {
- "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"
- }
- },
- "string_decoder": {
- "version": "1.1.1",
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- }
+ "logform": "^2.3.2",
+ "readable-stream": "^3.6.0",
+ "triple-beam": "^1.3.0"
}
},
"word-wrap": {
- "version": "1.2.3",
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"dev": true
},
"wrap-ansi": {
diff --git a/package.json b/package.json
index 20e17e4..547ad31 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@fridgefm/radio-core",
"author": "Grigory Gorshkov",
- "version": "3.1.5",
+ "version": "3.2.5",
"description": "internet radio engine made on NodeJS platform",
"license": "MIT",
"main": "./lib/index.js",
@@ -28,6 +28,7 @@
"test:unit:cov": "jest --config jest.config.json --collectCoverage=true"
},
"dependencies": {
+ "@fridgefm/inverter": "^0.1.9",
"chalk": "^4.1.2",
"dev-null": "^0.1.1",
"fs-extra": "^11.0.1",
@@ -36,7 +37,7 @@
"klaw-sync": "^6.0.0",
"node-id3": "^0.2.6",
"typed-emitter": "^2.1.0",
- "winston": "^3.3.3"
+ "winston": "^3.10.0"
},
"devDependencies": {
"@types/express": "^4.17.13",
diff --git a/src/__tests__/fail-path/common.fp.test.ts b/src/__tests__/fail-path/common.fp.spec.ts
similarity index 100%
rename from src/__tests__/fail-path/common.fp.test.ts
rename to src/__tests__/fail-path/common.fp.spec.ts
diff --git a/src/__tests__/happy-path/event.hp.test.ts b/src/__tests__/happy-path/event.hp.spec.ts
similarity index 100%
rename from src/__tests__/happy-path/event.hp.test.ts
rename to src/__tests__/happy-path/event.hp.spec.ts
diff --git a/src/__tests__/happy-path/station.hp.test.ts b/src/__tests__/happy-path/station.hp.spec.ts
similarity index 100%
rename from src/__tests__/happy-path/station.hp.test.ts
rename to src/__tests__/happy-path/station.hp.spec.ts
diff --git a/src/__tests__/test-utils.mock.ts b/src/__tests__/test-utils.mock.ts
index 9a83087..10f3ed8 100644
--- a/src/__tests__/test-utils.mock.ts
+++ b/src/__tests__/test-utils.mock.ts
@@ -29,12 +29,3 @@ export class TestFile {
fs.removeSync(this.fullPath);
}
}
-
-// describe('test-utils', () => {
-// it('new TestFile', () => {
-// const t1 = new TestFile();
-// expect(fs.statSync(t1.fullPath).isFile()).toEqual(true);
-// t1.remove();
-// expect(() => fs.statSync(t1.fullPath).isFile()).toThrow();
-// });
-// });
diff --git a/src/base/Playlist/Playlist.ts b/src/base/Playlist/Playlist.ts
deleted file mode 100644
index d0893c4..0000000
--- a/src/base/Playlist/Playlist.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import { createList } from '../../utils/fs';
-import { captureTime } from '../../utils/time';
-import { PUBLIC_EVENTS } from '../../features/EventBus/events';
-import { createTrackMap } from './methods';
-
-import type { TPlaylist, TrackMap, ReorderCb, PathList } from './Playlist.types';
-import type { EventBus } from '../../features/EventBus/EventBus';
-import type { InfoEvent } from '../../features/EventBus/events';
-import type { TTrack } from '../Track/Track.types';
-
-type Deps = { eventBus: EventBus };
-
-export const createPlaylist = (deps: Deps) => {
- const folders = new Set
();
- const emitInfo = (a: InfoEvent) => deps.eventBus.emit(PUBLIC_EVENTS.INFO, { name: 'playlist', ...a });
-
- let currentIndex = -1;
- let list: PathList = [];
- let tracksMap: TrackMap = new Map();
-
- const instance: TPlaylist = {
- addFolder: (folder: string) => {
- folders.add(folder);
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
- return revalidate();
- },
- getList: () => {
- return list.map((v, i) => {
- const tra = tracksMap.get(v) as TTrack;
-
- return {
- ...tra,
- isPlaying: currentIndex === i,
- };
- });
- },
- reorder: (cb: ReorderCb) => {
- const ct = captureTime();
- const prevList = instance.getList();
- const currentlyPlaying = prevList.find((v) => !!v.isPlaying);
-
- list = cb(prevList).map((b) => b.fsStats.fullPath);
- currentIndex = list.findIndex((v) => v === currentlyPlaying?.fsStats.fullPath);
-
- emitInfo({
- level: 'info',
- event: 'reorder',
- message: 'Playlist reordered',
- timings: ct(),
- });
-
- return instance.getList();
- },
- getNext: () => {
- if (list.length - 1 === currentIndex) {
- // the playlist drained
- const ct = captureTime();
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
- revalidate();
- currentIndex = 0;
- deps.eventBus.emit(PUBLIC_EVENTS.RESTART, instance.getList(), ct());
- } else {
- currentIndex += 1;
- }
- const nextPath = list[currentIndex] as string;
- const nextTrack = tracksMap.get(nextPath);
-
- if (!nextTrack) {
- emitInfo({ level: 'warn', event: 'no-next-track', message: `No next track found for ${nextPath}` });
- // try next tracks
- return instance.getNext();
- }
- nextTrack.playCount += 1;
-
- return { ...nextTrack, isPlaying: true };
- },
- };
-
- const revalidate = () => {
- const ct = captureTime();
- list = createList(Array.from(folders));
- tracksMap = createTrackMap(list);
-
- const result = instance.getList();
- emitInfo({ event: 'revalidate', message: 'Playlist revalidated', timings: ct() });
- return result;
- };
-
- return instance;
-};
diff --git a/src/base/Playlist/__tests__/methods.test.ts b/src/base/Playlist/__tests__/methods.test.ts
deleted file mode 100644
index 420d14b..0000000
--- a/src/base/Playlist/__tests__/methods.test.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { createTrackMap } from '../methods';
-import { tracks } from '../../../__tests__/test-utils.mock';
-
-const tracksArr = tracks.map((v) => v.fullPath);
-
-describe('base/Playlist/createTrackMap', () => {
- it('dedupes by path', () => {
- const map = createTrackMap([...tracksArr, ...tracksArr]);
- expect(Array.from(map)).toHaveLength(2);
- });
-
- it('inits with zero values', () => {
- const map = createTrackMap(tracksArr);
- expect(Array.from(map).every(([, tr]) => tr.playCount === 0)).toEqual(true);
- });
-});
diff --git a/src/base/Playlist/methods.ts b/src/base/Playlist/methods.ts
deleted file mode 100644
index cb424dd..0000000
--- a/src/base/Playlist/methods.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import Mp3 from '../../utils/mp3';
-import { extractLast, shuffleArray } from '../../utils/funcs';
-import { createTrack } from '../Track/Track';
-
-import type { TrackList, TrackMap } from './Playlist.types';
-
-export const createTrackMap = (paths: readonly string[]): TrackMap =>
- paths
- .filter((path) => {
- const f = extractLast(path, '/');
-
- return Mp3.isSupported(f[1]);
- })
- .reduce((acc, path) => {
- // deduplicate if already in map
- if (acc.has(path)) {
- return acc;
- }
-
- return acc.set(path, createTrack(path));
- }, new Map() as TrackMap);
-
-export const SHUFFLE_METHODS = {
- rearrange:
- ({ to, from }: { to: number; from: number }) =>
- (arr: TrackList) => {
- const movedElement = arr.splice(from, 1)[0];
- if (movedElement) {
- arr.splice(to, 0, movedElement);
- }
-
- return arr;
- },
- randomShuffle: () => shuffleArray,
-};
diff --git a/src/base/Queuestream.ts b/src/base/Queuestream.ts
deleted file mode 100644
index f9c39cf..0000000
--- a/src/base/Queuestream.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import { Readable, Transform, Writable } from 'stream';
-import devnull from 'dev-null';
-import { captureTime } from '../utils/time';
-import { createPrebuffer } from '../features/Prebuffer';
-import { PUBLIC_EVENTS } from '../features/EventBus/events';
-
-import type { EventBus } from '../features/EventBus/EventBus';
-import type { TPlaylist } from './Playlist/Playlist.types';
-
-type Deps = {
- playlist: TPlaylist;
- eventBus: EventBus;
-};
-
-export class QueueStream {
- private _deps: Deps;
-
- // this stream is always live
- private _current = new Transform({
- transform: (chunk, _, callback) => {
- this._prebuffer.modify([chunk]);
- callback(undefined, chunk);
- },
- });
-
- // this stream switches on each track
- private _trackStream: Readable;
-
- // prebuffering for faster client response (side-effect)
- private _prebuffer = createPrebuffer();
-
- constructor(deps: Deps) {
- this._deps = deps;
- this.currentPipe(devnull(), { end: false });
- this._trackStream = new Readable();
- }
-
- private _handleError(error: Error, event: string) {
- this._deps.eventBus.emit(PUBLIC_EVENTS.ERROR, {
- name: 'queuestream',
- error,
- event,
- });
- this.next();
- }
-
- public getPrebuffer = () => this._prebuffer.getStorage();
-
- public currentPipe = (wrstr: Writable, opts = {}) => this._current.pipe(wrstr, opts);
-
- public next = () => {
- const ct = captureTime();
- const { playlist, eventBus } = this._deps;
- const nextTrack = playlist.getNext();
-
- // destroy previous track stream if there was one
- this._trackStream?.destroy();
-
- // populate newly created stream with some handlers
- const [error, newStream] = nextTrack.getSound();
- if (error) {
- this._handleError(error, 'get-sound-error');
- return;
- }
-
- newStream.once('error', (e) => this._handleError(e, 'stream-error'));
- newStream.once('end', this.next);
- newStream.pipe(this._current, { end: false });
-
- this._trackStream = newStream;
-
- eventBus.emit(PUBLIC_EVENTS.NEXT_TRACK, nextTrack, ct());
- };
-}
diff --git a/src/base/Station.ts b/src/base/Station.ts
deleted file mode 100644
index ab60046..0000000
--- a/src/base/Station.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import { createEventBus, EventBus } from '../features/EventBus/EventBus';
-import { PUBLIC_EVENTS } from '../features/EventBus/events';
-import { captureTime } from '../utils/time';
-import { mergeConfig, Config } from '../config/index';
-import { createPlaylist } from './Playlist/Playlist';
-import { QueueStream } from './Queuestream';
-
-import type { ClientRequest, ServerResponse } from 'http';
-import type { TStation } from '../types/public';
-import type { TEmitter } from '../features/EventBus/events';
-import type { TPlaylist, ReorderCb } from './Playlist/Playlist.types';
-
-type StationDeps = {
- queuestream: QueueStream;
- eventBus: EventBus;
- playlist: TPlaylist;
- config: Config;
-};
-
-export class Station implements TStation {
- private _deps: StationDeps;
-
- constructor(extConfig?: Partial) {
- const config = mergeConfig(extConfig || {});
- const eventBus = createEventBus({ config });
- const playlist = createPlaylist({ eventBus });
- const queuestream = new QueueStream({ playlist, eventBus });
-
- this._deps = {
- playlist,
- eventBus,
- queuestream,
- config,
- };
- }
-
- public start() {
- const ct = captureTime();
- const { eventBus, queuestream } = this._deps;
-
- if (this.getPlaylist().length) {
- queuestream.next();
- }
-
- eventBus.emit(PUBLIC_EVENTS.START, this.getPlaylist(), ct());
- }
-
- public togglePause(): void {}
-
- public addFolder(folder: string) {
- return this._deps.playlist.addFolder(folder);
- }
-
- public next() {
- return this._deps.queuestream.next();
- }
-
- public getPlaylist() {
- return this._deps.playlist.getList();
- }
-
- public connectListener(_: ClientRequest, res: ServerResponse, cb = () => {}) {
- const { currentPipe, getPrebuffer } = this._deps.queuestream;
-
- res.writeHead(200, this._deps.config.responseHeaders);
- res.write(getPrebuffer());
- currentPipe(res);
- cb();
- }
-
- public reorderPlaylist(cb: ReorderCb) {
- return this._deps.playlist.reorder(cb);
- }
-
- public on: TEmitter['on'] = (...args) => this._deps.eventBus.on(...args);
-}
diff --git a/src/base/Track/Track.ts b/src/base/Track/Track.ts
deleted file mode 100644
index 669fe81..0000000
--- a/src/base/Track/Track.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { createSoundStream, getMetaAsync, getStats } from './methods';
-import type { TTrack } from './Track.types';
-
-export const createTrack = (fullPath: string): TTrack => {
- const fsStats = getStats(fullPath);
-
- return {
- fsStats,
- playCount: 0,
- getMetaAsync: () => getMetaAsync(fsStats),
- getSound: () => createSoundStream(fsStats),
- };
-};
diff --git a/src/base/__tests__/Queuestream.test.ts b/src/base/__tests__/Queuestream.test.ts
deleted file mode 100644
index e7d07ce..0000000
--- a/src/base/__tests__/Queuestream.test.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-describe('base/Queuestream', () => {
- it.todo('test all methods');
-});
diff --git a/src/config/index.ts b/src/config/index.ts
deleted file mode 100644
index f60c704..0000000
--- a/src/config/index.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { responseHeaders } from './responseHeaders';
-
-export const defaultConfig = {
- /**
- * Pass your custom response headers from the station endpoint
- */
- responseHeaders: responseHeaders(),
- /**
- * If set to true enables verbose info logging
- */
- verbose: false,
-};
-
-export const mergeConfig = (cfg: Partial) =>
- ({
- ...cfg,
- responseHeaders: responseHeaders(cfg.responseHeaders),
- } as Config);
-
-export type Config = typeof defaultConfig;
diff --git a/src/config/responseHeaders.ts b/src/config/responseHeaders.ts
deleted file mode 100644
index 1c801bf..0000000
--- a/src/config/responseHeaders.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-export const responseHeaders = (cfg?: Record) =>
- ({
- ...(cfg || {
- 'icy-br': '56',
- 'icy-genre': 'house',
- 'icy-metaint': '0',
- 'icy-pub': '0',
- 'icy-url': 'https://',
- }),
- 'icy-name': '@fridgefm/radio-engine',
- 'icy-notice1': 'Live radio powered by https://www.npmjs.com/package/@fridgefm/radio-engine',
- 'Cache-Control': 'no-cache,no-store,must-revalidate,max-age=0',
- 'Content-Type': 'audio/mpeg',
- } as Record);
diff --git a/src/constants.ts b/src/constants.ts
deleted file mode 100644
index cfa514f..0000000
--- a/src/constants.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export const DEFAULTS = {
- PREBUFFER_LENGTH: 12,
-};
diff --git a/src/features/EventBus/EventBus.ts b/src/features/EventBus/EventBus.ts
deleted file mode 100644
index a35a22d..0000000
--- a/src/features/EventBus/EventBus.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { EventEmitter } from 'events';
-import { logger } from '../../utils/logger';
-import { defaultConfig } from '../../config/index';
-import { PUBLIC_EVENTS } from './events';
-
-import type { TEmitter, InfoEvent, ErrorEvent } from './events';
-
-/**
- * This entity enables event system, its emitting and listenings.
- */
-export const createEventBus = ({ config } = { config: defaultConfig }) => {
- const emitter = new EventEmitter() as TEmitter;
- const on: TEmitter['on'] = (eventName, handler) => emitter.on(eventName, handler);
- const emit: TEmitter['emit'] = (eventName, ...args) => emitter.emit(eventName, ...args);
-
- on(PUBLIC_EVENTS.NEXT_TRACK, (tr, timings) =>
- emit(PUBLIC_EVENTS.INFO, { event: PUBLIC_EVENTS.NEXT_TRACK, message: tr.fsStats.stringified, timings }),
- );
- on(PUBLIC_EVENTS.START, (_, timings) =>
- emit(PUBLIC_EVENTS.INFO, { event: PUBLIC_EVENTS.START, message: 'Station started', timings }),
- );
- on(PUBLIC_EVENTS.RESTART, (_, timings) =>
- emit(PUBLIC_EVENTS.INFO, { event: PUBLIC_EVENTS.RESTART, message: 'Station restarted', timings }),
- );
-
- if (config.verbose) {
- on(PUBLIC_EVENTS.INFO, ({ level, ...rest }: InfoEvent) => logger.log(level || 'info', { ...rest }));
- on(PUBLIC_EVENTS.ERROR, (event: ErrorEvent) => logger.log('error', { ...event, message: event.error.message }));
- }
-
- return { on, emit };
-};
-
-export type EventBus = ReturnType;
diff --git a/src/features/Prebuffer.ts b/src/features/Prebuffer.ts
deleted file mode 100644
index c003adc..0000000
--- a/src/features/Prebuffer.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { Buffer } from 'buffer';
-import { DEFAULTS } from '../constants';
-
-type PrebufferArgs = { prebufferLength?: number };
-
-/**
- * Helper object that stores previous [prebufferLength] of Buffers.
- * It enables prebuffering, simply put it just immediately returns [prebufferLength] previous seconds of the stream.
- */
-export const createPrebuffer = (args: PrebufferArgs = {}) => {
- const prebufferLength = args.prebufferLength || DEFAULTS.PREBUFFER_LENGTH;
- const storage: Buffer[] = [];
-
- return {
- modify: (chunks: Buffer[]) => {
- chunks.forEach((ch) => {
- if (storage.length >= prebufferLength) {
- storage.shift();
- }
-
- storage.push(ch);
- });
- },
- getStorage: () => {
- const totalPrebufferLength = (storage[0] || []).length * prebufferLength;
-
- return Buffer.concat(storage, totalPrebufferLength);
- },
- };
-};
diff --git a/src/index.ts b/src/index.ts
index d7133b7..ab1a659 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,9 +1,6 @@
-import { Station } from './base/Station';
-import { PUBLIC_EVENTS } from './features/EventBus/events';
-import { SHUFFLE_METHODS } from './base/Playlist/methods';
-import { DEFAULTS } from './constants';
+export { Station } from './providers/station';
+export { PUBLIC_EVENTS } from './providers/events/events.provider';
+export { SHUFFLE_METHODS } from './providers/playlist/playlist.methods';
+export { DEFAULTS } from './providers/config';
-export { Station, PUBLIC_EVENTS, SHUFFLE_METHODS, DEFAULTS };
-export type { ShallowTrackMeta, TTrack, TrackStats } from './base/Track/Track.types';
-export type { ReorderCb, TrackList, TPlaylist } from './base/Playlist/Playlist.types';
-export type { TStation } from './types/public';
+export type * from './types/public.types';
diff --git a/src/providers/config.ts b/src/providers/config.ts
new file mode 100644
index 0000000..445f6a7
--- /dev/null
+++ b/src/providers/config.ts
@@ -0,0 +1,30 @@
+export type Config = {
+ responseHeaders: Record;
+ verbose: boolean;
+ prebufferLength: number;
+};
+
+const responseHeaders = (cfg?: Record) => ({
+ ...(cfg || {
+ 'icy-br': '56',
+ 'icy-genre': 'house',
+ 'icy-metaint': '0',
+ 'icy-pub': '0',
+ 'icy-url': 'https://',
+ }),
+ 'icy-name': '@fridgefm/radio-core',
+ 'icy-notice1': 'Live radio powered by https://www.npmjs.com/package/@fridgefm/radio-core',
+ 'Cache-Control': 'no-cache,no-store,must-revalidate,max-age=0',
+ 'Content-Type': 'audio/mpeg',
+});
+
+export const createConfig = (cfg: Partial): Config => ({
+ verbose: false,
+ prebufferLength: 12,
+ ...cfg,
+ responseHeaders: responseHeaders(cfg.responseHeaders),
+});
+
+export const DEFAULTS = {
+ PREBUFFER_LENGTH: 12,
+};
diff --git a/src/features/__tests__/EventBus.test.ts b/src/providers/events/__tests__/events.spec.ts
similarity index 88%
rename from src/features/__tests__/EventBus.test.ts
rename to src/providers/events/__tests__/events.spec.ts
index 96efeea..88e8b32 100644
--- a/src/features/__tests__/EventBus.test.ts
+++ b/src/providers/events/__tests__/events.spec.ts
@@ -1,5 +1,4 @@
-import { PUBLIC_EVENTS } from '../EventBus/events';
-import { createEventBus } from '../EventBus/EventBus';
+import { eventBusFactory, PUBLIC_EVENTS } from '../events.provider';
const createMocks = () => ({
start: jest.fn(),
@@ -15,7 +14,7 @@ describe('features/EventBus', () => {
['NEXT_TRACK', { message: 'stringified-mock', payload: { fsStats: { stringified: 'stringified-mock' } } }],
])('"%s" infos public event', (eventName, { message, payload }) => {
const mocks = createMocks();
- const instance = createEventBus();
+ const instance = eventBusFactory({});
const lowerCased = eventName.toLowerCase();
instance.on(PUBLIC_EVENTS.INFO, mocks.info);
diff --git a/src/providers/events/events.provider.ts b/src/providers/events/events.provider.ts
new file mode 100644
index 0000000..21f3817
--- /dev/null
+++ b/src/providers/events/events.provider.ts
@@ -0,0 +1,65 @@
+import { EventEmitter } from 'events';
+import { injectable, createToken } from '@fridgefm/inverter';
+import { logger } from '../../utils/logger';
+import { CONFIG_TOKEN } from '../tokens';
+
+import type { ErrorEvent, InfoEvent, TEmitter } from './events.types';
+import type { Config } from '../config';
+
+export const EVENT_BUS_TOKEN = createToken>('event_bus');
+
+export const PUBLIC_EVENTS = {
+ ERROR: 'error',
+ INFO: 'einfo',
+ START: 'estart',
+ RESTART: 'erestart',
+ NEXT_TRACK: 'enexttrack',
+} as const;
+
+export const eventBusFactory = (config: Config) => {
+ const emitter = new EventEmitter() as TEmitter;
+ const publicEventBus: Pick = {
+ on: (eventName, handler) => emitter.on(eventName, handler),
+ emit: (eventName, ...args) => emitter.emit(eventName, ...args),
+ };
+
+ if (config.verbose) {
+ publicEventBus.on(PUBLIC_EVENTS.INFO, ({ level, ...rest }: InfoEvent) => logger.log(level || 'info', { ...rest }));
+
+ publicEventBus.on(PUBLIC_EVENTS.ERROR, (event: ErrorEvent) =>
+ logger.log('error', { ...event, message: event.error.message }),
+ );
+ }
+
+ publicEventBus.on(PUBLIC_EVENTS.NEXT_TRACK, (tr, timings) =>
+ publicEventBus.emit(PUBLIC_EVENTS.INFO, {
+ event: PUBLIC_EVENTS.NEXT_TRACK,
+ message: tr.fsStats.stringified,
+ timings,
+ }),
+ );
+
+ publicEventBus.on(PUBLIC_EVENTS.START, (_, timings) =>
+ publicEventBus.emit(PUBLIC_EVENTS.INFO, {
+ event: PUBLIC_EVENTS.START,
+ message: 'Station started',
+ timings,
+ }),
+ );
+
+ publicEventBus.on(PUBLIC_EVENTS.RESTART, (_, timings) =>
+ publicEventBus.emit(PUBLIC_EVENTS.INFO, {
+ event: PUBLIC_EVENTS.RESTART,
+ message: 'Station restarted',
+ timings,
+ }),
+ );
+
+ return publicEventBus;
+};
+
+export const eventBusProvider = injectable({
+ provide: EVENT_BUS_TOKEN,
+ useFactory: eventBusFactory,
+ inject: [CONFIG_TOKEN] as const,
+});
diff --git a/src/features/EventBus/events.ts b/src/providers/events/events.types.ts
similarity index 70%
rename from src/features/EventBus/events.ts
rename to src/providers/events/events.types.ts
index 6dcf01f..ad7c217 100644
--- a/src/features/EventBus/events.ts
+++ b/src/providers/events/events.types.ts
@@ -1,14 +1,7 @@
import type TypedEmitter from 'typed-emitter';
-import type { TrackList } from '../../base/Playlist/Playlist.types';
-import type { TTrack } from '../../base/Track/Track.types';
-
-export const PUBLIC_EVENTS = {
- ERROR: 'error',
- INFO: 'einfo',
- START: 'estart',
- RESTART: 'erestart',
- NEXT_TRACK: 'enexttrack',
-} as const;
+import type { PUBLIC_EVENTS } from './events.provider';
+import type { TrackList } from '../playlist/playlist.types';
+import type { TTrack } from '../track/track.types';
type BaseEvent = {
event: string;
diff --git a/src/base/Playlist/__tests__/Playlist.test.ts b/src/providers/playlist/__tests__/playlist.spec.ts
similarity index 100%
rename from src/base/Playlist/__tests__/Playlist.test.ts
rename to src/providers/playlist/__tests__/playlist.spec.ts
diff --git a/src/providers/playlist/playlist.methods.ts b/src/providers/playlist/playlist.methods.ts
new file mode 100644
index 0000000..8c02a09
--- /dev/null
+++ b/src/providers/playlist/playlist.methods.ts
@@ -0,0 +1,16 @@
+import { shuffleArray } from '../../utils/funcs';
+import type { TrackList } from './playlist.types';
+
+export const SHUFFLE_METHODS = {
+ rearrange:
+ ({ to, from }: { to: number; from: number }) =>
+ (arr: TrackList) => {
+ const movedElement = arr.splice(from, 1)[0];
+ if (movedElement) {
+ arr.splice(to, 0, movedElement);
+ }
+
+ return arr;
+ },
+ randomShuffle: () => shuffleArray,
+};
diff --git a/src/providers/playlist/playlist.provider.ts b/src/providers/playlist/playlist.provider.ts
new file mode 100644
index 0000000..7a3214b
--- /dev/null
+++ b/src/providers/playlist/playlist.provider.ts
@@ -0,0 +1,109 @@
+import { injectable, createToken } from '@fridgefm/inverter';
+import { createList } from '../../utils/fs';
+import { captureTime } from '../../utils/time';
+import { PUBLIC_EVENTS, EVENT_BUS_TOKEN } from '../events/events.provider';
+import { TRACK_FACTORY_TOKEN } from '../track/track.provider';
+import { extractLast } from '../../utils/funcs';
+import Mp3 from '../../utils/mp3';
+
+import type { TTrack } from '../track/track.types';
+import type { InfoEvent } from '../events/events.types';
+import type { TrackMap, TrackList, ReorderCb, PathList, PlaylistElement, TPlaylist } from './playlist.types';
+
+export const PLAYLIST_TOKEN = createToken('playlist');
+
+export const playlistProvider = injectable({
+ provide: PLAYLIST_TOKEN,
+ scope: 'singleton',
+ useFactory: (createTrack, eventBus) => {
+ const folders: Set = new Set();
+ let currentIndex = -1;
+ let tracksMap: TrackMap = new Map();
+ let list: PathList = [];
+
+ const emitInfo = (a: InfoEvent) => {
+ eventBus.emit(PUBLIC_EVENTS.INFO, { name: 'playlist', ...a });
+ };
+
+ const revalidate = () => {
+ const ct = captureTime();
+ list = createList(Array.from(folders));
+ tracksMap = list
+ .filter((path) => {
+ const f = extractLast(path, '/');
+
+ return Mp3.isSupported(f[1]);
+ })
+ .reduce((acc, path) => {
+ // deduplicate if already in map
+ if (acc.has(path)) {
+ return acc;
+ }
+
+ return acc.set(path, createTrack(path));
+ }, new Map() as TrackMap);
+
+ const result = publicPlaylist.getList();
+ emitInfo({ event: 'revalidate', message: 'Playlist revalidated', timings: ct() });
+ return result;
+ };
+
+ const publicPlaylist = {
+ getList: (): TrackList =>
+ list.map((v, i) => {
+ const tra = tracksMap.get(v) as TTrack;
+
+ return {
+ ...tra,
+ isPlaying: currentIndex === i,
+ };
+ }),
+ getNext: (): PlaylistElement => {
+ if (list.length - 1 === currentIndex) {
+ // the playlist drained
+ const ct = captureTime();
+ revalidate();
+ currentIndex = 0;
+ eventBus.emit(PUBLIC_EVENTS.RESTART, publicPlaylist.getList(), ct());
+ } else {
+ currentIndex += 1;
+ }
+ const nextPath = list[currentIndex] as string;
+ const nextTrack = tracksMap.get(nextPath);
+
+ if (!nextTrack) {
+ emitInfo({ level: 'warn', event: 'no-next-track', message: `No next track found for ${nextPath}` });
+ // try next tracks
+ return publicPlaylist.getNext();
+ }
+ nextTrack.playCount += 1;
+
+ return { ...nextTrack, isPlaying: true };
+ },
+ addFolder: (folder: string) => {
+ folders.add(folder);
+ return revalidate();
+ },
+ reorder: (cb: ReorderCb) => {
+ const ct = captureTime();
+ const prevList = publicPlaylist.getList();
+ const currentlyPlaying = prevList.find((v) => !!v.isPlaying);
+
+ list = cb(prevList).map((b) => b.fsStats.fullPath);
+ currentIndex = list.findIndex((v) => v === currentlyPlaying?.fsStats.fullPath);
+
+ emitInfo({
+ level: 'info',
+ event: 'reorder',
+ message: 'Playlist reordered',
+ timings: ct(),
+ });
+
+ return publicPlaylist.getList();
+ },
+ };
+
+ return publicPlaylist;
+ },
+ inject: [TRACK_FACTORY_TOKEN, EVENT_BUS_TOKEN] as const,
+});
diff --git a/src/base/Playlist/Playlist.types.ts b/src/providers/playlist/playlist.types.ts
similarity index 87%
rename from src/base/Playlist/Playlist.types.ts
rename to src/providers/playlist/playlist.types.ts
index 8651c33..afc3aad 100644
--- a/src/base/Playlist/Playlist.types.ts
+++ b/src/providers/playlist/playlist.types.ts
@@ -1,4 +1,4 @@
-import type { TTrack, TrackPath } from '../Track/Track.types';
+import type { TTrack, TrackPath } from '../track/track.types';
export type PlaylistElement = {
isPlaying: boolean;
diff --git a/src/features/__tests__/Prebuffer.test.ts b/src/providers/prebuffer/__tests__/prebuffer.spec.ts
similarity index 71%
rename from src/features/__tests__/Prebuffer.test.ts
rename to src/providers/prebuffer/__tests__/prebuffer.spec.ts
index 53abd81..2138971 100644
--- a/src/features/__tests__/Prebuffer.test.ts
+++ b/src/providers/prebuffer/__tests__/prebuffer.spec.ts
@@ -1,11 +1,11 @@
import { Buffer } from 'buffer';
-import { createPrebuffer } from '../Prebuffer';
+import { prebufferFactory } from '../prebuffer.provider';
const createChunks = (from: string) => from.split('').map((v) => Buffer.from([Number(v)]));
describe('features/Prebuffer', () => {
it('adds chunks up to max', () => {
- const instance = createPrebuffer({ prebufferLength: 10 });
+ const instance = prebufferFactory({ prebufferLength: 10 });
expect(instance.getStorage()).toHaveLength(0);
instance.modify(createChunks('1'));
@@ -15,7 +15,7 @@ describe('features/Prebuffer', () => {
});
it('does not overflow max values', () => {
- const instance = createPrebuffer({ prebufferLength: 10 });
+ const instance = prebufferFactory({ prebufferLength: 10 });
instance.modify(createChunks('1234567890'));
expect(instance.getStorage()).toHaveLength(10);
@@ -28,11 +28,4 @@ describe('features/Prebuffer', () => {
instance.modify(createChunks('1234'));
expect(instance.getStorage().join('')).toEqual('9012341234');
});
-
- it('uses default if length not set', () => {
- const instance = createPrebuffer();
- instance.modify(createChunks('1'));
-
- expect(instance.getStorage()).toHaveLength(12);
- });
});
diff --git a/src/providers/prebuffer/prebuffer.provider.ts b/src/providers/prebuffer/prebuffer.provider.ts
new file mode 100644
index 0000000..037c9e7
--- /dev/null
+++ b/src/providers/prebuffer/prebuffer.provider.ts
@@ -0,0 +1,38 @@
+import { injectable, createToken } from '@fridgefm/inverter';
+import { CONFIG_TOKEN } from '../tokens';
+
+type PrebufferArgs = { prebufferLength: number };
+type PrebufferT = {
+ getStorage: () => Buffer;
+ modify: (chunks: Buffer[]) => void;
+};
+
+export const PREBUFFER_TOKEN = createToken('prebuffer');
+
+export const prebufferFactory = (config: PrebufferArgs) => {
+ const { prebufferLength } = config;
+ const storage: Buffer[] = [];
+
+ return {
+ modify: (chunks: Buffer[]) => {
+ chunks.forEach((ch) => {
+ if (storage.length >= prebufferLength) {
+ storage.shift();
+ }
+
+ storage.push(ch);
+ });
+ },
+ getStorage: () => {
+ const totalPrebufferLength = (storage[0] || []).length * prebufferLength;
+ return Buffer.concat(storage, totalPrebufferLength);
+ },
+ };
+};
+
+export const prebufferProvider = injectable({
+ provide: PREBUFFER_TOKEN,
+ scope: 'scoped',
+ useFactory: prebufferFactory,
+ inject: [CONFIG_TOKEN] as const,
+});
diff --git a/src/providers/queuestream/queuestream.provider.ts b/src/providers/queuestream/queuestream.provider.ts
new file mode 100644
index 0000000..b26708a
--- /dev/null
+++ b/src/providers/queuestream/queuestream.provider.ts
@@ -0,0 +1,65 @@
+import { Readable, Transform, Writable } from 'stream';
+import { injectable, createToken } from '@fridgefm/inverter';
+import devnull from 'dev-null';
+import { captureTime } from '../../utils/time';
+import { PUBLIC_EVENTS, EVENT_BUS_TOKEN } from '../events/events.provider';
+import { PREBUFFER_TOKEN } from '../prebuffer/prebuffer.provider';
+import { PLAYLIST_TOKEN } from '../playlist/playlist.provider';
+import type { Queuestream } from './queuestream.types';
+
+export const QUEUESTREAM_TOKEN = createToken('queuestream');
+
+export const queuestreamProvider = injectable({
+ provide: QUEUESTREAM_TOKEN,
+ scope: 'singleton',
+ useFactory: (eventBus, playlist, prebuffer) => {
+ let trackStream = new Readable();
+ const currentStream = new Transform({
+ transform: (chunk, _, callback) => {
+ prebuffer.modify([chunk]);
+ callback(undefined, chunk);
+ },
+ });
+
+ const handleError = (error: Error, event: string) => {
+ eventBus.emit(PUBLIC_EVENTS.ERROR, {
+ name: 'queuestream',
+ error,
+ event,
+ });
+ publicQueuestream.next();
+ };
+
+ const publicQueuestream = {
+ getPrebuffer: () => prebuffer.getStorage(),
+ currentPipe: (wrstr: Writable, opts?: { end?: boolean }) => currentStream.pipe(wrstr, opts),
+ next: () => {
+ const ct = captureTime();
+ const nextTrack = playlist.getNext();
+
+ // destroy previous track stream if there was one
+ trackStream?.destroy();
+
+ // populate newly created stream with some handlers
+ const [error, newStream] = nextTrack.getSound();
+ if (error) {
+ handleError(error, 'get-sound-error');
+ return;
+ }
+
+ newStream.once('error', (e) => handleError(e, 'stream-error'));
+ newStream.once('end', publicQueuestream.next);
+ newStream.pipe(currentStream, { end: false });
+
+ trackStream = newStream;
+
+ eventBus.emit(PUBLIC_EVENTS.NEXT_TRACK, nextTrack, ct());
+ },
+ };
+
+ publicQueuestream.currentPipe(devnull(), { end: false });
+
+ return publicQueuestream;
+ },
+ inject: [EVENT_BUS_TOKEN, PLAYLIST_TOKEN, PREBUFFER_TOKEN] as const,
+});
diff --git a/src/providers/queuestream/queuestream.types.ts b/src/providers/queuestream/queuestream.types.ts
new file mode 100644
index 0000000..de8e4ce
--- /dev/null
+++ b/src/providers/queuestream/queuestream.types.ts
@@ -0,0 +1,7 @@
+import type { Writable } from 'stream';
+
+export type Queuestream = {
+ getPrebuffer: () => Buffer;
+ currentPipe: (wrstr: Writable, opts?: { end?: boolean }) => Writable;
+ next: () => void;
+};
diff --git a/src/providers/station.ts b/src/providers/station.ts
new file mode 100644
index 0000000..ae8ae06
--- /dev/null
+++ b/src/providers/station.ts
@@ -0,0 +1,61 @@
+import { declareContainer, injectable } from '@fridgefm/inverter';
+import { createConfig, Config } from './config';
+import { eventBusProvider } from './events/events.provider';
+import { playlistProvider } from './playlist/playlist.provider';
+import { queuestreamProvider } from './queuestream/queuestream.provider';
+import { prebufferProvider } from './prebuffer/prebuffer.provider';
+import { trackProvider } from './track/track.provider';
+import { stationProvider, STATION_PUBLIC_TOKEN } from './station/station.provider';
+import { CONFIG_TOKEN } from './tokens';
+
+import type { TStation } from '../types/public.types';
+import type { ReorderCb } from './playlist/playlist.types';
+import type { ClientRequest, ServerResponse } from 'http';
+import type { TEmitter } from './events/events.types';
+
+export class Station implements TStation {
+ private _station: TStation;
+
+ constructor(extConfig?: Partial) {
+ this._station = declareContainer({
+ providers: [
+ injectable({
+ provide: CONFIG_TOKEN,
+ useValue: createConfig(extConfig || {}),
+ }),
+ trackProvider,
+ eventBusProvider,
+ playlistProvider,
+ prebufferProvider,
+ queuestreamProvider,
+ stationProvider,
+ ],
+ }).get(STATION_PUBLIC_TOKEN);
+ }
+
+ public start() {
+ this._station.start();
+ }
+
+ public addFolder(folder: string) {
+ this._station.addFolder(folder);
+ }
+
+ public next() {
+ this._station.next();
+ }
+
+ public getPlaylist() {
+ return this._station.getPlaylist();
+ }
+
+ public reorderPlaylist(cb: ReorderCb) {
+ return this._station.reorderPlaylist(cb);
+ }
+
+ public connectListener(req: ClientRequest, res: ServerResponse, cb = () => {}) {
+ this._station.connectListener(req, res, cb);
+ }
+
+ public on: TEmitter['on'] = (...args) => this._station.on(...args);
+}
diff --git a/src/providers/station/station.provider.ts b/src/providers/station/station.provider.ts
new file mode 100644
index 0000000..4ef17f0
--- /dev/null
+++ b/src/providers/station/station.provider.ts
@@ -0,0 +1,46 @@
+import { injectable, createToken } from '@fridgefm/inverter';
+import { captureTime } from '../../utils/time';
+import { PLAYLIST_TOKEN } from '../playlist/playlist.provider';
+import { QUEUESTREAM_TOKEN } from '../queuestream/queuestream.provider';
+import { PUBLIC_EVENTS, EVENT_BUS_TOKEN } from '../events/events.provider';
+import { CONFIG_TOKEN } from '../tokens';
+
+import type { ClientRequest, ServerResponse } from 'http';
+import type { ReorderCb } from '../playlist/playlist.types';
+import type { TEmitter } from '../events/events.types';
+import type { TStation } from '../../types/public.types';
+
+export const STATION_PUBLIC_TOKEN = createToken('station_root');
+
+export const stationProvider = injectable({
+ provide: STATION_PUBLIC_TOKEN,
+ useFactory: (config, queuestream, eventBus, playlist) => {
+ const station = {
+ start() {
+ const ct = captureTime();
+
+ if (this.getPlaylist().length) {
+ queuestream.next();
+ }
+
+ eventBus.emit(PUBLIC_EVENTS.START, this.getPlaylist(), ct());
+ },
+ getPlaylist: () => playlist.getList(),
+ addFolder: (folder: string) => playlist.addFolder(folder),
+ next: () => queuestream.next(),
+ connectListener(_: ClientRequest, res: ServerResponse, cb = () => {}) {
+ const { currentPipe, getPrebuffer } = queuestream;
+
+ res.writeHead(200, config.responseHeaders);
+ res.write(getPrebuffer());
+ currentPipe(res);
+ cb();
+ },
+ reorderPlaylist: (cb: ReorderCb) => playlist.reorder(cb),
+ on: (...args: Parameters) => eventBus.on(...args),
+ };
+
+ return station;
+ },
+ inject: [CONFIG_TOKEN, QUEUESTREAM_TOKEN, EVENT_BUS_TOKEN, PLAYLIST_TOKEN] as const,
+});
diff --git a/src/providers/tokens.ts b/src/providers/tokens.ts
new file mode 100644
index 0000000..1814062
--- /dev/null
+++ b/src/providers/tokens.ts
@@ -0,0 +1,5 @@
+import { createToken } from '@fridgefm/inverter';
+
+import type { Config } from './config';
+
+export const CONFIG_TOKEN = createToken('config');
diff --git a/src/base/Track/__tests__/methods.test.ts b/src/providers/track/__tests__/track.spec.ts
similarity index 96%
rename from src/base/Track/__tests__/methods.test.ts
rename to src/providers/track/__tests__/track.spec.ts
index bfe3877..3eed839 100644
--- a/src/base/Track/__tests__/methods.test.ts
+++ b/src/providers/track/__tests__/track.spec.ts
@@ -1,8 +1,8 @@
import devnull from 'dev-null';
-import { getStats, getMetaAsync, createSoundStream } from '../methods';
+import { getStats, getMetaAsync, createSoundStream } from '../track.provider';
import { pathToMusic, tracks, TestFile } from '../../../__tests__/test-utils.mock';
-describe('base/Track/methods', () => {
+describe('track/methods', () => {
it('getStats', () => {
const common = {
bitrate: 16018,
diff --git a/src/base/Track/methods.ts b/src/providers/track/track.provider.ts
similarity index 69%
rename from src/base/Track/methods.ts
rename to src/providers/track/track.provider.ts
index 6c00d2b..7461a25 100644
--- a/src/base/Track/methods.ts
+++ b/src/providers/track/track.provider.ts
@@ -1,15 +1,17 @@
+import { createToken, injectable } from '@fridgefm/inverter';
import fs from 'fs-extra';
import _ from 'highland';
import id3 from 'node-id3';
import { extractLast } from '../../utils/funcs';
import { getDateFromMsecs } from '../../utils/time';
import Mp3 from '../../utils/mp3';
-
+import type { TTrack, TrackStats, ShallowTrackMeta, TrackPath } from './track.types';
import type { Readable } from 'stream';
import type { Tags } from 'node-id3';
-import type { ShallowTrackMeta, TrackPath, TrackStats } from './Track.types';
-const getMetaAsync = async (stats: TrackStats): Promise => {
+export const TRACK_FACTORY_TOKEN = createToken<(path: string) => TTrack>('track');
+
+export const getMetaAsync = async (stats: TrackStats): Promise => {
const { fullPath, name } = stats;
return new Promise((res) =>
@@ -30,7 +32,7 @@ const getMetaAsync = async (stats: TrackStats): Promise => {
);
};
-const getStats = (fullPath: TrackPath): TrackStats => {
+export const getStats = (fullPath: TrackPath): TrackStats => {
const file = fs.readFileSync(fullPath);
const [directory, fullName] = extractLast(fullPath, '/');
const duration = Mp3.getDuration(file);
@@ -51,7 +53,7 @@ const getStats = (fullPath: TrackPath): TrackStats => {
};
};
-const createSoundStream = ({ fullPath, bitrate, tagsSize }: TrackStats): [Error | null, Readable] => {
+export const createSoundStream = ({ fullPath, bitrate, tagsSize }: TrackStats): [Error | null, Readable] => {
try {
if (!fs.statSync(fullPath).isFile()) {
throw new Error(`Not a file: '${fullPath}'`);
@@ -64,7 +66,7 @@ const createSoundStream = ({ fullPath, bitrate, tagsSize }: TrackStats): [Error
// @ts-ignore
_.drop(Math.floor(tagsSize / bitrate)), // remove id3tags from stream
// @ts-ignore
- // _.slice(60, 80), // for debuggine purposes
+ _.slice(60, 80), // for debuggine purposes
// @ts-ignore
_.ratelimit(1, 1000),
);
@@ -77,4 +79,16 @@ const createSoundStream = ({ fullPath, bitrate, tagsSize }: TrackStats): [Error
}
};
-export { createSoundStream, getMetaAsync, getStats };
+export const trackProvider = injectable({
+ provide: TRACK_FACTORY_TOKEN,
+ useValue: (fullPath: string) => {
+ const fsStats = getStats(fullPath);
+
+ return {
+ getMetaAsync: () => getMetaAsync(fsStats),
+ getSound: () => createSoundStream(fsStats),
+ fsStats,
+ playCount: 0,
+ };
+ },
+});
diff --git a/src/base/Track/Track.types.ts b/src/providers/track/track.types.ts
similarity index 100%
rename from src/base/Track/Track.types.ts
rename to src/providers/track/track.types.ts
diff --git a/src/types/public.d.ts b/src/types/public.types.ts
similarity index 68%
rename from src/types/public.d.ts
rename to src/types/public.types.ts
index 8362acc..e570e50 100644
--- a/src/types/public.d.ts
+++ b/src/types/public.types.ts
@@ -1,6 +1,6 @@
import type { ClientRequest, ServerResponse } from 'http';
-import type { TrackList, ReorderCb } from '../base/Playlist/Playlist.types';
-import type { TEmitter } from '../features/EventBus/events';
+import type { TrackList, ReorderCb } from '../providers/playlist/playlist.types';
+import type { TEmitter } from '../providers/events/events.types';
export type TStation = {
/**
@@ -32,3 +32,6 @@ export type TStation = {
*/
on: TEmitter['on'];
};
+
+export type { ReorderCb, TrackList, TPlaylist } from '../providers/playlist/playlist.types';
+export type { ShallowTrackMeta, TTrack, TrackStats } from '../providers/track/track.types';
diff --git a/src/utils/__tests__/funcs.test.ts b/src/utils/__tests__/funcs.spec.ts
similarity index 100%
rename from src/utils/__tests__/funcs.test.ts
rename to src/utils/__tests__/funcs.spec.ts
diff --git a/tsconfig.json b/tsconfig.json
index 3e62072..531c1f8 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -33,5 +33,8 @@
},
"include": ["src/**/*"],
"exclude": ["node_modules/**", "**/__tests__/"],
- "compileOnSave": false
+ "compileOnSave": false,
+ "ts-node": {
+ "files": true
+ }
}