Service decorators - oh the evil I have wraught....
This commit is contained in:
+2
-1
@@ -1,2 +1,3 @@
|
|||||||
.idea
|
.idea
|
||||||
node_modules
|
node_modules/
|
||||||
|
database/
|
||||||
@@ -1,14 +1,24 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import '@tsmetadata/polyfill';
|
import '@tsmetadata/polyfill';
|
||||||
import Koa from 'koa';
|
|
||||||
import {SubsonicRouter} from "./src/subsonic/router";
|
import {SubsonicRouter} from "./src/subsonic/router";
|
||||||
|
import ScanFoldersTask from "./src/tasks/ScanFoldersTask";
|
||||||
|
import {ServiceManager} from "./src/core/service";
|
||||||
|
import WebserverService from "./src/services/WebserverService";
|
||||||
|
import TaskService from "./src/services/TaskService";
|
||||||
|
import * as Services from "./src/services";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const app = new Koa();
|
const services = ServiceManager.get().mount(Services);
|
||||||
(new SubsonicRouter()).injectInto(app);
|
|
||||||
|
|
||||||
app.listen(8080);
|
const webserver = services.getService<WebserverService>('webserverService');
|
||||||
|
webserver.add(new SubsonicRouter());
|
||||||
|
|
||||||
|
const taskService = services.getService<TaskService>('taskService');
|
||||||
|
taskService.addTask(new ScanFoldersTask('/root/jukesquare/public'));
|
||||||
|
|
||||||
|
await services.start();
|
||||||
|
webserver.listen();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+564
@@ -10,15 +10,30 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@koa/router": "^15.4.0",
|
"@koa/router": "^15.4.0",
|
||||||
|
"@root/walk": "^1.1.0",
|
||||||
"@tsmetadata/polyfill": "^1.1.3",
|
"@tsmetadata/polyfill": "^1.1.3",
|
||||||
|
"better-sqlite3": "^12.9.0",
|
||||||
|
"file-type": "^22.0.1",
|
||||||
"koa": "^3.2.0",
|
"koa": "^3.2.0",
|
||||||
"xmlbuilder2": "^4.0.3"
|
"xmlbuilder2": "^4.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/better-sqlite3": "^7.6.13",
|
||||||
"@types/koa": "^3.0.2",
|
"@types/koa": "^3.0.2",
|
||||||
|
"@types/node": "^25.6.0",
|
||||||
"typescript": "^6.0.2"
|
"typescript": "^6.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@borewit/text-codec": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Borewit"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@koa/router": {
|
"node_modules/@koa/router": {
|
||||||
"version": "15.4.0",
|
"version": "15.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@koa/router/-/router-15.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@koa/router/-/router-15.4.0.tgz",
|
||||||
@@ -90,6 +105,35 @@
|
|||||||
"node": ">=20.0"
|
"node": ">=20.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@root/walk": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@root/walk/-/walk-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-FfXPAta9u2dBuaXhPRawBcijNC9rmKVApmbi6lIZyg36VR/7L02ytxoY5K/14PJlHqiBUoYII73cTlekdKTUOw==",
|
||||||
|
"license": "MPL-2.0"
|
||||||
|
},
|
||||||
|
"node_modules/@tokenizer/inflate": {
|
||||||
|
"version": "0.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz",
|
||||||
|
"integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.4.3",
|
||||||
|
"token-types": "^6.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Borewit"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tokenizer/token": {
|
||||||
|
"version": "0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
|
||||||
|
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@tsmetadata/polyfill": {
|
"node_modules/@tsmetadata/polyfill": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tsmetadata/polyfill/-/polyfill-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tsmetadata/polyfill/-/polyfill-1.1.3.tgz",
|
||||||
@@ -106,6 +150,16 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/better-sqlite3": {
|
||||||
|
"version": "7.6.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.13.tgz",
|
||||||
|
"integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/body-parser": {
|
"node_modules/@types/body-parser": {
|
||||||
"version": "1.19.6",
|
"version": "1.19.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
|
||||||
@@ -305,6 +359,90 @@
|
|||||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
"license": "Python-2.0"
|
"license": "Python-2.0"
|
||||||
},
|
},
|
||||||
|
"node_modules/base64-js": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||||
|
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/better-sqlite3": {
|
||||||
|
"version": "12.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.9.0.tgz",
|
||||||
|
"integrity": "sha512-wqUv4Gm3toFpHDQmaKD4QhZm3g1DjUBI0yzS4UBl6lElUmXFYdTQmmEDpAFa5o8FiFiymURypEnfVHzILKaxqQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"bindings": "^1.5.0",
|
||||||
|
"prebuild-install": "^7.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "20.x || 22.x || 23.x || 24.x || 25.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/bindings": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"file-uri-to-path": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/bl": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"buffer": "^5.5.0",
|
||||||
|
"inherits": "^2.0.4",
|
||||||
|
"readable-stream": "^3.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/buffer": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
|
"ieee754": "^1.1.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/chownr": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/content-disposition": {
|
"node_modules/content-disposition": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
|
||||||
@@ -357,12 +495,36 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/decompress-response": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"mimic-response": "^3.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/deep-equal": {
|
"node_modules/deep-equal": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
|
||||||
"integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==",
|
"integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/deep-extend": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/delegates": {
|
"node_modules/delegates": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||||
@@ -388,6 +550,15 @@
|
|||||||
"npm": "1.2.8000 || >= 1.4.16"
|
"npm": "1.2.8000 || >= 1.4.16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/detect-libc": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ee-first": {
|
"node_modules/ee-first": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
@@ -403,12 +574,54 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/end-of-stream": {
|
||||||
|
"version": "1.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
|
||||||
|
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"once": "^1.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/escape-html": {
|
"node_modules/escape-html": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||||
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
|
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/expand-template": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
|
||||||
|
"license": "(MIT OR WTFPL)",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/file-type": {
|
||||||
|
"version": "22.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/file-type/-/file-type-22.0.1.tgz",
|
||||||
|
"integrity": "sha512-ww5Mhre0EE+jmBvOXTmXAbEMuZE7uX4a3+oRCQFNj8w++g3ev913N6tXQz0XTXbueQ5TWQfm6BdaViEHHn8bhA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@tokenizer/inflate": "^0.4.1",
|
||||||
|
"strtok3": "^10.3.5",
|
||||||
|
"token-types": "^6.1.2",
|
||||||
|
"uint8array-extras": "^1.5.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=22"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sindresorhus/file-type?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/file-uri-to-path": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/fresh": {
|
"node_modules/fresh": {
|
||||||
"version": "0.5.2",
|
"version": "0.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||||
@@ -418,6 +631,18 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fs-constants": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/github-from-package": {
|
||||||
|
"version": "0.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
|
||||||
|
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/http-assert": {
|
"node_modules/http-assert": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz",
|
||||||
@@ -485,12 +710,38 @@
|
|||||||
"url": "https://opencollective.com/express"
|
"url": "https://opencollective.com/express"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ieee754": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
"node_modules/inherits": {
|
"node_modules/inherits": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/ini": {
|
||||||
|
"version": "1.3.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||||
|
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||||
@@ -584,12 +835,45 @@
|
|||||||
"url": "https://opencollective.com/express"
|
"url": "https://opencollective.com/express"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mimic-response": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minimist": {
|
||||||
|
"version": "1.2.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||||
|
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mkdirp-classic": {
|
||||||
|
"version": "0.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||||
|
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/napi-build-utils": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/negotiator": {
|
"node_modules/negotiator": {
|
||||||
"version": "0.6.3",
|
"version": "0.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||||
@@ -599,6 +883,18 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-abi": {
|
||||||
|
"version": "3.89.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.89.0.tgz",
|
||||||
|
"integrity": "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"semver": "^7.3.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/on-finished": {
|
"node_modules/on-finished": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
||||||
@@ -611,6 +907,15 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/once": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"wrappy": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/parseurl": {
|
"node_modules/parseurl": {
|
||||||
"version": "1.3.3",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||||
@@ -630,12 +935,155 @@
|
|||||||
"url": "https://opencollective.com/express"
|
"url": "https://opencollective.com/express"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prebuild-install": {
|
||||||
|
"version": "7.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
|
||||||
|
"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
|
||||||
|
"deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"detect-libc": "^2.0.0",
|
||||||
|
"expand-template": "^2.0.3",
|
||||||
|
"github-from-package": "0.0.0",
|
||||||
|
"minimist": "^1.2.3",
|
||||||
|
"mkdirp-classic": "^0.5.3",
|
||||||
|
"napi-build-utils": "^2.0.0",
|
||||||
|
"node-abi": "^3.3.0",
|
||||||
|
"pump": "^3.0.0",
|
||||||
|
"rc": "^1.2.7",
|
||||||
|
"simple-get": "^4.0.0",
|
||||||
|
"tar-fs": "^2.0.0",
|
||||||
|
"tunnel-agent": "^0.6.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"prebuild-install": "bin.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pump": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"end-of-stream": "^1.1.0",
|
||||||
|
"once": "^1.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rc": {
|
||||||
|
"version": "1.2.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
||||||
|
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
||||||
|
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
|
||||||
|
"dependencies": {
|
||||||
|
"deep-extend": "^0.6.0",
|
||||||
|
"ini": "~1.3.0",
|
||||||
|
"minimist": "^1.2.0",
|
||||||
|
"strip-json-comments": "~2.0.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rc": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/readable-stream": {
|
||||||
|
"version": "3.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||||
|
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/safe-buffer": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/semver": {
|
||||||
|
"version": "7.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||||
|
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/setprototypeof": {
|
"node_modules/setprototypeof": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||||
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/simple-concat": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
|
||||||
|
"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/simple-get": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"decompress-response": "^6.0.0",
|
||||||
|
"once": "^1.3.1",
|
||||||
|
"simple-concat": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/statuses": {
|
"node_modules/statuses": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
||||||
@@ -645,6 +1093,68 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/string_decoder": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "~5.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/strip-json-comments": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/strtok3": {
|
||||||
|
"version": "10.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz",
|
||||||
|
"integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@tokenizer/token": "^0.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Borewit"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tar-fs": {
|
||||||
|
"version": "2.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
|
||||||
|
"integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"chownr": "^1.1.1",
|
||||||
|
"mkdirp-classic": "^0.5.2",
|
||||||
|
"pump": "^3.0.0",
|
||||||
|
"tar-stream": "^2.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tar-stream": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"bl": "^4.0.3",
|
||||||
|
"end-of-stream": "^1.4.1",
|
||||||
|
"fs-constants": "^1.0.0",
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"readable-stream": "^3.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/toidentifier": {
|
"node_modules/toidentifier": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||||
@@ -654,6 +1164,24 @@
|
|||||||
"node": ">=0.6"
|
"node": ">=0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/token-types": {
|
||||||
|
"version": "6.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz",
|
||||||
|
"integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@borewit/text-codec": "^0.2.1",
|
||||||
|
"@tokenizer/token": "^0.3.0",
|
||||||
|
"ieee754": "^1.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.16"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Borewit"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tsscmp": {
|
"node_modules/tsscmp": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",
|
||||||
@@ -663,6 +1191,18 @@
|
|||||||
"node": ">=0.6.x"
|
"node": ">=0.6.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tunnel-agent": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/type-is": {
|
"node_modules/type-is": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
|
||||||
@@ -691,6 +1231,18 @@
|
|||||||
"node": ">=14.17"
|
"node": ">=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/uint8array-extras": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
"version": "7.19.2",
|
"version": "7.19.2",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz",
|
||||||
@@ -698,6 +1250,12 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/util-deprecate": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/vary": {
|
"node_modules/vary": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
@@ -707,6 +1265,12 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/wrappy": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/xmlbuilder2": {
|
"node_modules/xmlbuilder2": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-4.0.3.tgz",
|
||||||
|
|||||||
@@ -15,12 +15,17 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@koa/router": "^15.4.0",
|
"@koa/router": "^15.4.0",
|
||||||
|
"@root/walk": "^1.1.0",
|
||||||
"@tsmetadata/polyfill": "^1.1.3",
|
"@tsmetadata/polyfill": "^1.1.3",
|
||||||
|
"better-sqlite3": "^12.9.0",
|
||||||
|
"file-type": "^22.0.1",
|
||||||
"koa": "^3.2.0",
|
"koa": "^3.2.0",
|
||||||
"xmlbuilder2": "^4.0.3"
|
"xmlbuilder2": "^4.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/better-sqlite3": "^7.6.13",
|
||||||
"@types/koa": "^3.0.2",
|
"@types/koa": "^3.0.2",
|
||||||
|
"@types/node": "^25.6.0",
|
||||||
"typescript": "^6.0.2"
|
"typescript": "^6.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
import Router from "@koa/router";
|
|
||||||
import Koa from "koa";
|
|
||||||
|
|
||||||
type Constructor<T = {}> = new (...args: any[]) => T;
|
|
||||||
|
|
||||||
type Route = {
|
|
||||||
method: string;
|
|
||||||
path: string;
|
|
||||||
fn: any;
|
|
||||||
};
|
|
||||||
|
|
||||||
const routeSymbol = Symbol("routeSymbol");
|
|
||||||
|
|
||||||
export function get(path: string) {
|
|
||||||
return function getDecorator (originalMethod: any, context: ClassMethodDecoratorContext) {
|
|
||||||
if (context.metadata) {
|
|
||||||
if (!context.metadata[routeSymbol]) {
|
|
||||||
context.metadata[routeSymbol] = [] as Route[];
|
|
||||||
}
|
|
||||||
// @ts-ignore
|
|
||||||
context.metadata[routeSymbol].push({method: 'get', path, fn: originalMethod});
|
|
||||||
}
|
|
||||||
return originalMethod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function post(path: string) {
|
|
||||||
return function getDecorator (originalMethod: any, context: ClassMethodDecoratorContext) {
|
|
||||||
if (context.metadata) {
|
|
||||||
if (!context.metadata[routeSymbol]) {
|
|
||||||
context.metadata[routeSymbol] = [] as Route[];
|
|
||||||
}
|
|
||||||
// @ts-ignore
|
|
||||||
context.metadata[routeSymbol].push({method: 'post', path, fn: originalMethod});
|
|
||||||
}
|
|
||||||
return originalMethod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function middleware(fn: any, path: string = '') {
|
|
||||||
return function middlewareDecorator (constructor: any, context: ClassDecoratorContext) {
|
|
||||||
if (context.metadata) {
|
|
||||||
if (!context.metadata[routeSymbol]) {
|
|
||||||
context.metadata[routeSymbol] = [];
|
|
||||||
}
|
|
||||||
// @ts-ignore
|
|
||||||
context.metadata[routeSymbol].unshift({method: 'use', path, fn});
|
|
||||||
}
|
|
||||||
return constructor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function router(prefix: string) {
|
|
||||||
return function routerDecorator<T extends Constructor>(constructor: T, context: ClassDecoratorContext<T>) {
|
|
||||||
return class KoaRouter extends constructor {
|
|
||||||
public router: Router;
|
|
||||||
constructor(...args: any[]) {
|
|
||||||
super(...args);
|
|
||||||
this.router = new Router({prefix});
|
|
||||||
|
|
||||||
for (const route of (context.metadata?.[routeSymbol] || []) as Route[]) switch (route.method) {
|
|
||||||
case "get": this.router.get(route.path, route.fn); break;
|
|
||||||
case "post": this.router.post(route.path, route.fn); break;
|
|
||||||
case 'use': this.router.use(route.fn); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public injectInto(app: Koa) {
|
|
||||||
app.use(this.router.routes()).use(this.router.allowedMethods());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import Router from "@koa/router";
|
||||||
|
import Koa from "koa";
|
||||||
|
|
||||||
|
type Route = {
|
||||||
|
method: string;
|
||||||
|
path: string;
|
||||||
|
fn: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
const routesSymbol = Symbol("symbol.router.routes");
|
||||||
|
const routerSymbol = Symbol("symbol.router.router");
|
||||||
|
|
||||||
|
export class DecoratedRouterCollector {
|
||||||
|
static routers: {[name: string]: Router} = {};
|
||||||
|
|
||||||
|
static addRouter(name: string, router: Router) {
|
||||||
|
this.routers[name] = router;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bindRouterToApp(instance: object, app: Koa) {
|
||||||
|
const router = DecoratedRouterCollector.routers[instance.constructor.name];
|
||||||
|
if (router instanceof Router) {
|
||||||
|
app.use(router.routes()).use(router.allowedMethods());
|
||||||
|
} else {
|
||||||
|
throw new Error(`Could not find router metadata on objec type ${instance.constructor.name} - did you remember to add @router decorator to this class?`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function get(path: string) {
|
||||||
|
return function getDecorator (originalMethod: any, context: ClassMethodDecoratorContext) {
|
||||||
|
if (context.metadata && !context.metadata[routesSymbol]) {
|
||||||
|
context.metadata[routesSymbol] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.metadata && Array.isArray(context.metadata[routesSymbol])) {
|
||||||
|
context.metadata[routesSymbol].push({method: 'get', path, fn: originalMethod});
|
||||||
|
}
|
||||||
|
return originalMethod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function post(path: string) {
|
||||||
|
return function getDecorator (originalMethod: any, context: ClassMethodDecoratorContext) {
|
||||||
|
if (context.metadata && !context.metadata[routesSymbol]) {
|
||||||
|
context.metadata[routesSymbol] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.metadata && Array.isArray(context.metadata[routesSymbol])) {
|
||||||
|
context.metadata[routesSymbol].push({method: 'post', path, fn: originalMethod});
|
||||||
|
}
|
||||||
|
return originalMethod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function middleware(fn: any, path: string = '') {
|
||||||
|
return function middlewareDecorator (constructor: any, context: ClassDecoratorContext) {
|
||||||
|
if (context.metadata && !context.metadata[routesSymbol]) {
|
||||||
|
context.metadata[routesSymbol] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If router hasn't already been created, add middleware to list of add to router instance
|
||||||
|
if (context.metadata && Array.isArray(context.metadata[routesSymbol])) {
|
||||||
|
context.metadata[routesSymbol].push({method: 'use', path, fn});
|
||||||
|
}
|
||||||
|
|
||||||
|
// If router has already been declared, then add middleware to the router directly
|
||||||
|
if (context.metadata && context.metadata[routerSymbol] instanceof Router) {
|
||||||
|
context.metadata[routerSymbol].use(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return constructor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function router(prefix: string) {
|
||||||
|
return function routerDecorator(constructor: any, context: ClassDecoratorContext) {
|
||||||
|
const router = new Router({prefix});
|
||||||
|
context.metadata[routerSymbol] = router;
|
||||||
|
|
||||||
|
for (const route of (context.metadata[routesSymbol] || []) as Route[]) switch (route.method) {
|
||||||
|
case "get": router.get(route.path, route.fn); break;
|
||||||
|
case "post": router.post(route.path, route.fn); break;
|
||||||
|
case 'use': router.use(route.fn); break;
|
||||||
|
}
|
||||||
|
DecoratedRouterCollector.addRouter(constructor.name, router);
|
||||||
|
|
||||||
|
return constructor;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
import ServiceInterface from "../interfaces/ServiceInterface";
|
||||||
|
|
||||||
|
type Constructor = new (...args:any[]) => any;
|
||||||
|
|
||||||
|
const serviceNameSymbol = Symbol("symbol.serviceName");
|
||||||
|
|
||||||
|
export abstract class BaseService implements ServiceInterface {
|
||||||
|
private startPromise: Promise<void> | null = null;
|
||||||
|
|
||||||
|
async start(): Promise<void> {
|
||||||
|
if (!this.startPromise) {
|
||||||
|
await ServiceManager.get().startDependencies(
|
||||||
|
// @ts-ignore
|
||||||
|
this.constructor[Symbol.metadata][serviceNameSymbol]
|
||||||
|
);
|
||||||
|
this.startPromise = new Promise<void>(async (resolve) => {
|
||||||
|
resolve(await this.init());
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return this.startPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract init(): Promise<void>;
|
||||||
|
|
||||||
|
async stop(): Promise<void> {
|
||||||
|
await this.startPromise;
|
||||||
|
await this.destroy();
|
||||||
|
this.startPromise = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract destroy(): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceContainer = {
|
||||||
|
name: string;
|
||||||
|
service: object | null;
|
||||||
|
constructor: Constructor | null;
|
||||||
|
started: boolean;
|
||||||
|
constructing: boolean;
|
||||||
|
dependencies: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ServiceManager {
|
||||||
|
static singleton: ServiceManager;
|
||||||
|
static get() {
|
||||||
|
if (!ServiceManager.singleton) ServiceManager.singleton = new ServiceManager();
|
||||||
|
return ServiceManager.singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
private constructor() {}
|
||||||
|
|
||||||
|
services: Map<string, ServiceContainer> = new Map();
|
||||||
|
|
||||||
|
assertService(name: string): ServiceContainer {
|
||||||
|
if (!this.services.has(name)) {
|
||||||
|
this.services.set(name, {name, constructor: null, service: null, started: false, constructing: false, dependencies: []});
|
||||||
|
}
|
||||||
|
return this.services.get(name) as ServiceContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
addService(name: string, constructor: any) {
|
||||||
|
const serviceContainer = this.assertService(name);
|
||||||
|
serviceContainer.constructor = constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
addDependency(name: string, dependency: string) {
|
||||||
|
const service = this.assertService(name);
|
||||||
|
service.dependencies.push(dependency)
|
||||||
|
}
|
||||||
|
|
||||||
|
mount(...args: any[]) {
|
||||||
|
// Ensure all services have been constructed (and dependency injected)
|
||||||
|
for (const service of this.services.values()) {
|
||||||
|
if (service.constructor) {
|
||||||
|
this.injectService(service.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
async start() {
|
||||||
|
// Start all constructed services
|
||||||
|
for (const service of this.services.values()) {
|
||||||
|
if (service.service && service.service instanceof BaseService) {
|
||||||
|
await service.service.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async startDependencies(name: string) {
|
||||||
|
if (!this.services.has(name)) {
|
||||||
|
throw new Error(`Unknown service ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = this.services.get(name) as ServiceContainer;
|
||||||
|
for (const dependency of service.dependencies) {
|
||||||
|
const dependentService = this.injectService(dependency);
|
||||||
|
await dependentService.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
injectService(name: string) {
|
||||||
|
if (!this.services.has(name)) {
|
||||||
|
throw new Error(`Unknown service ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = this.services.get(name) as ServiceContainer;
|
||||||
|
if (!service.constructor) {
|
||||||
|
throw new Error(`service: ${service.name} has no constructor`);
|
||||||
|
}
|
||||||
|
if (!service.service) {
|
||||||
|
if (service.constructing) {
|
||||||
|
throw new Error(`Dependency cycle detected while constructing service: ${service.name}`);
|
||||||
|
}
|
||||||
|
service.constructing = true;
|
||||||
|
service.service = new service.constructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
return service.service as BaseService;
|
||||||
|
}
|
||||||
|
|
||||||
|
getService<T>(name: string): T {
|
||||||
|
if (!this.services.has(name)) {
|
||||||
|
throw new Error(`Unknown service ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = this.services.get(name) as ServiceContainer;
|
||||||
|
if (!service.constructor) {
|
||||||
|
throw new Error(`service: ${service.name} has no constructor`);
|
||||||
|
}
|
||||||
|
if (!service.service) {
|
||||||
|
if (service.constructing) {
|
||||||
|
throw new Error(`Dependency cycle detected while constructing service: ${service.name}`);
|
||||||
|
}
|
||||||
|
service.constructing = true;
|
||||||
|
service.service = new service.constructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
return service.service as T;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function service(propertyName: string) {
|
||||||
|
return function installService(constructor: any, context: ClassDecoratorContext) {
|
||||||
|
context.metadata[serviceNameSymbol] = propertyName;
|
||||||
|
ServiceManager.get().addService(propertyName, constructor);
|
||||||
|
return constructor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function inject(name: string) {
|
||||||
|
return function injectService(value: unknown, context: ClassAccessorDecoratorContext): ClassAccessorDecoratorResult<any, any> {
|
||||||
|
if (context.metadata[serviceNameSymbol]) {
|
||||||
|
ServiceManager.get().addDependency(context.metadata[serviceNameSymbol] as string, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
get() {
|
||||||
|
return ServiceManager.get().injectService(name);
|
||||||
|
},
|
||||||
|
set(): never {
|
||||||
|
throw new Error('Cannot overwrite injected service');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export default interface DbMigration {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
date: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export default interface ServiceInterface {
|
||||||
|
start(): Promise<void>;
|
||||||
|
init(): Promise<void>;
|
||||||
|
stop(): Promise<void>;
|
||||||
|
destroy(): Promise<void>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export default interface TaskInterface {
|
||||||
|
shouldRun(): boolean;
|
||||||
|
run(): Promise<void>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import Database from "better-sqlite3";
|
||||||
|
|
||||||
|
export type Migration = {
|
||||||
|
name: string;
|
||||||
|
migration: (db: Database.Database) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const baseMigration = (): Migration => {
|
||||||
|
return {
|
||||||
|
name: 'baseMigration',
|
||||||
|
migration: (db) => {
|
||||||
|
db.prepare('CREATE TABLE "audio" (id INTEGER PRIMARY KEY ASC)').run();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getMigrations() : Migration[] {
|
||||||
|
return [
|
||||||
|
baseMigration()
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { spawn } from 'node:child_process';
|
||||||
|
import { once } from 'node:events';
|
||||||
|
|
||||||
|
export async function runCommand(command: string, args: string[]) {
|
||||||
|
const cmd = spawn(command, args);
|
||||||
|
const stdout = [] as string[];
|
||||||
|
const stderr = [] as string[];
|
||||||
|
|
||||||
|
cmd.stdout?.on('data', (data: Buffer) => {
|
||||||
|
stdout.push(data.toString('utf-8'));
|
||||||
|
});
|
||||||
|
|
||||||
|
cmd.stderr?.on('data', (data: Buffer) => {
|
||||||
|
stderr.push(data.toString('utf-8'));
|
||||||
|
});
|
||||||
|
|
||||||
|
const [code] = await once(cmd, 'close');
|
||||||
|
return {
|
||||||
|
stdout: stdout.join(''),
|
||||||
|
stderr: stderr.join(''),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import {getMigrations, Migration} from "../migrations";
|
||||||
|
import {service} from "../core/service";
|
||||||
|
|
||||||
|
@service('configService')
|
||||||
|
export default class ConfigService {
|
||||||
|
public migrations: Migration[] = getMigrations();
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import Database from 'better-sqlite3';
|
||||||
|
import DbMigration from "../dbTableTypes/migration";
|
||||||
|
import {Migration} from "../migrations";
|
||||||
|
import ConfigService from "./ConfigService";
|
||||||
|
import {BaseService, inject, service} from "../core/service";
|
||||||
|
|
||||||
|
const MIGRATION_TABLE_NAME = "migration";
|
||||||
|
|
||||||
|
@service('databaseService')
|
||||||
|
export default class DatabaseService extends BaseService {
|
||||||
|
protected db: Database.Database;
|
||||||
|
|
||||||
|
@inject('configService') protected accessor config!: ConfigService;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.db = new Database('database/core.db');
|
||||||
|
this.db.pragma('journal_mode = WAL');
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
const migrations = this.config.migrations;
|
||||||
|
|
||||||
|
this.assertMigrationTable();
|
||||||
|
|
||||||
|
// Turn array of migrations into dictionary
|
||||||
|
const migrationDict = {} as {[key: string]: Migration};
|
||||||
|
for (const migration of migrations) {
|
||||||
|
migrationDict[migration.name] = migration;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any already run migrations from the dict
|
||||||
|
const existingMigrations = this.getMigrations();
|
||||||
|
for (const existing of existingMigrations) {
|
||||||
|
if (migrationDict[existing.name]) {
|
||||||
|
delete migrationDict[existing.name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run any remaining migrations
|
||||||
|
for (const migration of Object.values(migrationDict)) {
|
||||||
|
migration.migration(this.db);
|
||||||
|
this.saveExecutedMigration(migration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async destroy() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
getMigrations(): DbMigration[] {
|
||||||
|
return this.db.prepare(`SELECT * FROM ${MIGRATION_TABLE_NAME};`).all() as DbMigration[];
|
||||||
|
}
|
||||||
|
|
||||||
|
saveExecutedMigration(migration: Migration) {
|
||||||
|
this.db.prepare(`INSERT into ${MIGRATION_TABLE_NAME}(name) values (:name)`).run({name: migration.name});
|
||||||
|
}
|
||||||
|
|
||||||
|
assertMigrationTable() {
|
||||||
|
const migrationTable = this.db.prepare(`SELECT name FROM sqlite_master WHERE name='${MIGRATION_TABLE_NAME}'`).get();
|
||||||
|
if (!migrationTable) {
|
||||||
|
this.db.prepare(`CREATE TABLE ${MIGRATION_TABLE_NAME} (id INTEGER PRIMARY KEY ASC, name VARCHAR, date TIMESTAMP DEFAULT CURRENT_TIMESTAMP)`).run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import {runCommand} from "./CliService";
|
||||||
|
import {service} from "../core/service";
|
||||||
|
|
||||||
|
@service('ffmpegService')
|
||||||
|
export default class FFMpegService {
|
||||||
|
static async checkFile(filename: string) {
|
||||||
|
const file = await runCommand('ffprobe', [
|
||||||
|
'-v',
|
||||||
|
'quiet',
|
||||||
|
'-print_format',
|
||||||
|
'json',
|
||||||
|
'-show_format',
|
||||||
|
filename
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (file.stderr !== '') {
|
||||||
|
throw new Error('FFMpeg returned error: ' + file.stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const json = JSON.parse(file.stdout);
|
||||||
|
|
||||||
|
if (!json || !json.format) {
|
||||||
|
throw new Error('FFMpeg did not return format block: ' + file.stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: json.format.format_name,
|
||||||
|
duration: parseFloat(json.format.duration),
|
||||||
|
size: parseFloat(json.format.size),
|
||||||
|
tags: {
|
||||||
|
title: json.format.tags?.title || json.format.tags?.TITLE || null,
|
||||||
|
album: json.format.tags?.album || json.format.tags?.ALBUM || null,
|
||||||
|
artist: json.format.tags?.artist || json.format.tags?.ARTIST || null,
|
||||||
|
comment: json.format.tags?.comment || json.format.tags?.COMMENT || null,
|
||||||
|
track: json.format.tags?.track || json.format.tags?.TRACK || null,
|
||||||
|
genre: json.format.tags?.genre || json.format.tags?.GENRE || null,
|
||||||
|
publisher: json.format.tags?.publisher || json.format.tags?.PUBLISHER || null,
|
||||||
|
album_artist: json.format.tags?.album_artist || json.format.tags?.ALBUM_ARTIST || null,
|
||||||
|
composer: json.format.tags?.composer || json.format.tags?.COMPOSER || null,
|
||||||
|
year: json.format.tags?.year || json.format.tags?.YEAR || null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import TaskInterface from "../interfaces/TaskInterface";
|
||||||
|
import {BaseService, service} from "../core/service";
|
||||||
|
|
||||||
|
const FIVE_MINUTES: number = 5 * 60 * 1000;
|
||||||
|
|
||||||
|
@service('taskService')
|
||||||
|
export default class TaskService extends BaseService {
|
||||||
|
protected tasks: TaskInterface[] = [];
|
||||||
|
private timeout: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
|
public addTask(task: TaskInterface) : void {
|
||||||
|
this.tasks.push(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
this.timeout = setTimeout(async () => {
|
||||||
|
await this.run();
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
async run() {
|
||||||
|
this.tasks.forEach(task => {
|
||||||
|
if (task.shouldRun()) task.run();
|
||||||
|
});
|
||||||
|
this.timeout = setTimeout(() => this.run, FIVE_MINUTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
async destroy() {
|
||||||
|
if (this.timeout) clearTimeout(this.timeout);
|
||||||
|
this.timeout = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import Koa from "koa";
|
||||||
|
import {DecoratedRouterCollector} from "../core/router";
|
||||||
|
import {BaseService, service} from "../core/service";
|
||||||
|
|
||||||
|
@service('webserverService')
|
||||||
|
export default class WebserverService extends BaseService {
|
||||||
|
private app: Koa = new Koa();
|
||||||
|
|
||||||
|
add(router: any) {
|
||||||
|
DecoratedRouterCollector.bindRouterToApp(router, this.app);
|
||||||
|
}
|
||||||
|
|
||||||
|
listen(port: number = 8080) {
|
||||||
|
this.app.listen(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {}
|
||||||
|
async destroy() {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export * from './CliService';
|
||||||
|
export * from './TaskService';
|
||||||
|
export * from './ConfigService';
|
||||||
|
export * from './FFMpegService';
|
||||||
|
export * from './DatabaseService';
|
||||||
|
export * from './WebserverService';
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import {get, middleware, post, router} from "../base/router";
|
import {get, middleware, post, router} from "../core/router";
|
||||||
import Koa from "koa";
|
import Koa from "koa";
|
||||||
import {extractSubsonicApiContext, subsonicErrorHandler} from "./middleware";
|
import {extractSubsonicApiContext, subsonicErrorHandler} from "./middleware";
|
||||||
import {Renderer} from "./renderer";
|
import {Renderer} from "./renderer";
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// @ts-ignore
|
||||||
|
import { walk } from '@root/walk';
|
||||||
|
import {Dirent} from "node:fs";
|
||||||
|
import {fileTypeFromFile} from "file-type";
|
||||||
|
import FFMpegService from "../services/FFMpegService";
|
||||||
|
import TaskInterface from "../interfaces/TaskInterface";
|
||||||
|
|
||||||
|
export default class ScanFoldersTask implements TaskInterface {
|
||||||
|
private hasRun: boolean = false;
|
||||||
|
|
||||||
|
constructor(protected mount: string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldRun(): boolean {
|
||||||
|
return !this.hasRun;
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(): Promise<void> {
|
||||||
|
this.hasRun = true;
|
||||||
|
return this.scanFolder();
|
||||||
|
}
|
||||||
|
|
||||||
|
async scanFolder() {
|
||||||
|
return walk(this.mount, async (err: any, pathname: string, dirent: Dirent) => {
|
||||||
|
if (err) return false;
|
||||||
|
if (dirent.isDirectory()) await this.processFolder(pathname, dirent);
|
||||||
|
if (dirent.isFile()) await this.processFile(pathname, dirent);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async processFolder(pathname: string, dirent: Dirent) {
|
||||||
|
console.log('folder', pathname);
|
||||||
|
}
|
||||||
|
|
||||||
|
async processFile(pathname: string, dirent: Dirent) {
|
||||||
|
console.log('file', pathname);
|
||||||
|
const type = await fileTypeFromFile(pathname);
|
||||||
|
if (type === undefined || type.mime.startsWith('audio')) {
|
||||||
|
console.log(await FFMpegService.checkFile(pathname));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es2022",
|
||||||
|
"module": "esnext",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user