File-based response support & static server
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
- Clean up UniversalPath implementation - Use Readable/Writable types correctly for stream methods - Add .list() methods for getting child files - Make Response body specify explicit types and support writing Readable streams to the body - Create a static file server that supports directory listing
This commit is contained in:
parent
b3b5b169e8
commit
f496046461
10
package.json
10
package.json
@ -8,12 +8,14 @@
|
|||||||
"lib": "lib"
|
"lib": "lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@atao60/fse-cli": "^0.1.6",
|
||||||
"@types/bcrypt": "^5.0.0",
|
"@types/bcrypt": "^5.0.0",
|
||||||
"@types/busboy": "^0.2.3",
|
"@types/busboy": "^0.2.3",
|
||||||
"@types/cli-table": "^0.3.0",
|
"@types/cli-table": "^0.3.0",
|
||||||
|
"@types/mime-types": "^2.1.0",
|
||||||
"@types/mkdirp": "^1.0.1",
|
"@types/mkdirp": "^1.0.1",
|
||||||
"@types/negotiator": "^0.6.1",
|
"@types/negotiator": "^0.6.1",
|
||||||
"@types/node": "^14.14.37",
|
"@types/node": "^14.17.4",
|
||||||
"@types/pg": "^8.6.0",
|
"@types/pg": "^8.6.0",
|
||||||
"@types/pluralize": "^0.0.29",
|
"@types/pluralize": "^0.0.29",
|
||||||
"@types/pug": "^2.0.4",
|
"@types/pug": "^2.0.4",
|
||||||
@ -25,6 +27,7 @@
|
|||||||
"cli-table": "^0.3.6",
|
"cli-table": "^0.3.6",
|
||||||
"colors": "^1.4.0",
|
"colors": "^1.4.0",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
|
"mime-types": "^2.1.31",
|
||||||
"mkdirp": "^1.0.4",
|
"mkdirp": "^1.0.4",
|
||||||
"negotiator": "^0.6.2",
|
"negotiator": "^0.6.2",
|
||||||
"pg": "^8.6.0",
|
"pg": "^8.6.0",
|
||||||
@ -38,14 +41,13 @@
|
|||||||
"typedoc-plugin-pages-fork": "^0.0.1",
|
"typedoc-plugin-pages-fork": "^0.0.1",
|
||||||
"typedoc-plugin-sourcefile-url": "^1.0.6",
|
"typedoc-plugin-sourcefile-url": "^1.0.6",
|
||||||
"typescript": "^4.2.3",
|
"typescript": "^4.2.3",
|
||||||
"copyfiles": "^2.4.1",
|
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^8.3.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"prebuild": "pnpm run lint",
|
"prebuild": "pnpm run lint && rimraf lib",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"postbuild": "copyfiles -u 1 \"src/resources/**/*\" lib",
|
"postbuild": "fse copy --all --dereference --preserveTimestamps --keepExisting=false --quiet --errorOnExist=false src/resources lib/resources",
|
||||||
"app": "tsc && node lib/index.js",
|
"app": "tsc && node lib/index.js",
|
||||||
"prepare": "pnpm run build",
|
"prepare": "pnpm run build",
|
||||||
"docs:build": "typedoc --options typedoc.json",
|
"docs:build": "typedoc --options typedoc.json",
|
||||||
|
444
pnpm-lock.yaml
444
pnpm-lock.yaml
@ -1,10 +1,12 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
|
'@atao60/fse-cli': 0.1.6
|
||||||
'@types/bcrypt': 5.0.0
|
'@types/bcrypt': 5.0.0
|
||||||
'@types/busboy': 0.2.3
|
'@types/busboy': 0.2.3
|
||||||
'@types/cli-table': 0.3.0
|
'@types/cli-table': 0.3.0
|
||||||
|
'@types/mime-types': 2.1.0
|
||||||
'@types/mkdirp': 1.0.1
|
'@types/mkdirp': 1.0.1
|
||||||
'@types/negotiator': 0.6.1
|
'@types/negotiator': 0.6.1
|
||||||
'@types/node': 14.14.37
|
'@types/node': 14.17.4
|
||||||
'@types/pg': 8.6.0
|
'@types/pg': 8.6.0
|
||||||
'@types/pluralize': 0.0.29
|
'@types/pluralize': 0.0.29
|
||||||
'@types/pug': 2.0.4
|
'@types/pug': 2.0.4
|
||||||
@ -15,8 +17,8 @@ dependencies:
|
|||||||
busboy: 0.3.1
|
busboy: 0.3.1
|
||||||
cli-table: 0.3.6
|
cli-table: 0.3.6
|
||||||
colors: 1.4.0
|
colors: 1.4.0
|
||||||
copyfiles: 2.4.1
|
|
||||||
dotenv: 8.2.0
|
dotenv: 8.2.0
|
||||||
|
mime-types: 2.1.31
|
||||||
mkdirp: 1.0.4
|
mkdirp: 1.0.4
|
||||||
negotiator: 0.6.2
|
negotiator: 0.6.2
|
||||||
pg: 8.6.0
|
pg: 8.6.0
|
||||||
@ -37,6 +39,26 @@ devDependencies:
|
|||||||
eslint: 7.27.0
|
eslint: 7.27.0
|
||||||
lockfileVersion: 5.2
|
lockfileVersion: 5.2
|
||||||
packages:
|
packages:
|
||||||
|
/@atao60/fse-cli/0.1.6:
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.14.6
|
||||||
|
arg: 5.0.0
|
||||||
|
chalk: 4.1.1
|
||||||
|
core-js: 3.15.2
|
||||||
|
fs-extra: 10.0.0
|
||||||
|
graceful-fs: 4.2.6
|
||||||
|
inquirer: 8.1.1
|
||||||
|
regenerator-runtime: 0.13.7
|
||||||
|
source-map-support: 0.5.19
|
||||||
|
terminal-link: 3.0.0
|
||||||
|
tslib: 2.3.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: ^12.20.0 || ^14.13.1 || >=16.0.0
|
||||||
|
npm: '>=6.14.11'
|
||||||
|
hasBin: true
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-BtUemvHc16zevepkJGjM2vuRVkyU3zIJEHpw/gvvxJRRSWppblw9uqXeR7y72kJ88VcTOnzz/1wNGWHsBHVpKQ==
|
||||||
/@babel/code-frame/7.12.11:
|
/@babel/code-frame/7.12.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/highlight': 7.14.0
|
'@babel/highlight': 7.14.0
|
||||||
@ -66,6 +88,14 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==
|
integrity: sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==
|
||||||
|
/@babel/runtime/7.14.6:
|
||||||
|
dependencies:
|
||||||
|
regenerator-runtime: 0.13.7
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=6.9.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==
|
||||||
/@babel/types/7.13.14:
|
/@babel/types/7.13.14:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/helper-validator-identifier': 7.12.11
|
'@babel/helper-validator-identifier': 7.12.11
|
||||||
@ -156,6 +186,10 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
|
integrity: sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
|
||||||
|
/@types/mime-types/2.1.0:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=
|
||||||
/@types/minimatch/3.0.4:
|
/@types/minimatch/3.0.4:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
@ -182,6 +216,10 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-sld7b/xmFum66AAKuz/rp/CUO8+98fMpyQ3SBfzzBNGMd/1iHBTAg9oyAvcYlAj46bpc74r91jSw2iFdnx29nw==
|
integrity: sha512-sld7b/xmFum66AAKuz/rp/CUO8+98fMpyQ3SBfzzBNGMd/1iHBTAg9oyAvcYlAj46bpc74r91jSw2iFdnx29nw==
|
||||||
|
/@types/node/14.17.4:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-8kQ3+wKGRNN0ghtEn7EGps/B8CzuBz1nXZEIGGLP2GnwbqYn4dbTs7k+VKLTq1HvZLRCIDtN3Snx1Ege8B7L5A==
|
||||||
/@types/pg/8.6.0:
|
/@types/pg/8.6.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 14.17.1
|
'@types/node': 14.17.1
|
||||||
@ -377,6 +415,22 @@ packages:
|
|||||||
node: '>=6'
|
node: '>=6'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
|
integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
|
||||||
|
/ansi-escapes/4.3.2:
|
||||||
|
dependencies:
|
||||||
|
type-fest: 0.21.3
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=8'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
|
||||||
|
/ansi-escapes/5.0.0:
|
||||||
|
dependencies:
|
||||||
|
type-fest: 1.2.1
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=12'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==
|
||||||
/ansi-regex/2.1.1:
|
/ansi-regex/2.1.1:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
@ -418,6 +472,10 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
|
integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
|
||||||
|
/arg/5.0.0:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-4P8Zm2H+BRS+c/xX1LrHw0qKpEhdlZjLCgWy+d78T9vqa2Z2SiD2wMrYuWIAFy5IZUD7nnNXroRttz+0RzlrzQ==
|
||||||
/argparse/1.0.10:
|
/argparse/1.0.10:
|
||||||
dependencies:
|
dependencies:
|
||||||
sprintf-js: 1.0.3
|
sprintf-js: 1.0.3
|
||||||
@ -467,6 +525,10 @@ packages:
|
|||||||
/balanced-match/1.0.2:
|
/balanced-match/1.0.2:
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||||
|
/base64-js/1.5.1:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||||
/bcrypt-pbkdf/1.0.2:
|
/bcrypt-pbkdf/1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
tweetnacl: 0.14.5
|
tweetnacl: 0.14.5
|
||||||
@ -483,6 +545,14 @@ packages:
|
|||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw==
|
integrity: sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw==
|
||||||
|
/bl/4.1.0:
|
||||||
|
dependencies:
|
||||||
|
buffer: 5.7.1
|
||||||
|
inherits: 2.0.4
|
||||||
|
readable-stream: 3.6.0
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
|
||||||
/brace-expansion/1.1.11:
|
/brace-expansion/1.1.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
balanced-match: 1.0.2
|
balanced-match: 1.0.2
|
||||||
@ -507,6 +577,13 @@ packages:
|
|||||||
node: '>=4'
|
node: '>=4'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==
|
integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==
|
||||||
|
/buffer/5.7.1:
|
||||||
|
dependencies:
|
||||||
|
base64-js: 1.5.1
|
||||||
|
ieee754: 1.2.1
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
|
||||||
/busboy/0.3.1:
|
/busboy/0.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
dicer: 0.3.0
|
dicer: 0.3.0
|
||||||
@ -542,7 +619,6 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ansi-styles: 4.3.0
|
ansi-styles: 4.3.0
|
||||||
supports-color: 7.2.0
|
supports-color: 7.2.0
|
||||||
dev: true
|
|
||||||
engines:
|
engines:
|
||||||
node: '>=10'
|
node: '>=10'
|
||||||
resolution:
|
resolution:
|
||||||
@ -553,12 +629,30 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-x84o821LzZdE5f/CxfzeHHMmH8A=
|
integrity: sha1-x84o821LzZdE5f/CxfzeHHMmH8A=
|
||||||
|
/chardet/0.7.0:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
|
||||||
/chownr/2.0.0:
|
/chownr/2.0.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
node: '>=10'
|
node: '>=10'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
|
integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
|
||||||
|
/cli-cursor/3.1.0:
|
||||||
|
dependencies:
|
||||||
|
restore-cursor: 3.1.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=8'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
|
||||||
|
/cli-spinners/2.6.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=6'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==
|
||||||
/cli-table/0.3.6:
|
/cli-table/0.3.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
colors: 1.0.3
|
colors: 1.0.3
|
||||||
@ -567,14 +661,18 @@ packages:
|
|||||||
node: '>= 0.2.0'
|
node: '>= 0.2.0'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ==
|
integrity: sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ==
|
||||||
/cliui/7.0.4:
|
/cli-width/3.0.0:
|
||||||
dependencies:
|
|
||||||
string-width: 4.2.2
|
|
||||||
strip-ansi: 6.0.0
|
|
||||||
wrap-ansi: 7.0.0
|
|
||||||
dev: false
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>= 10'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
|
integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
|
||||||
|
/clone/1.0.4:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.8'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
|
||||||
/code-point-at/1.1.0:
|
/code-point-at/1.1.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
@ -631,19 +729,11 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==
|
integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==
|
||||||
/copyfiles/2.4.1:
|
/core-js/3.15.2:
|
||||||
dependencies:
|
|
||||||
glob: 7.1.7
|
|
||||||
minimatch: 3.0.4
|
|
||||||
mkdirp: 1.0.4
|
|
||||||
noms: 0.0.0
|
|
||||||
through2: 2.0.5
|
|
||||||
untildify: 4.0.0
|
|
||||||
yargs: 16.2.0
|
|
||||||
dev: false
|
dev: false
|
||||||
hasBin: true
|
requiresBuild: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==
|
integrity: sha512-tKs41J7NJVuaya8DxIOCnl8QuPHx5/ZVbFo1oKgVl1qHFBBrDctzQGtuLjPpRdNTWmKPH6oEvgN/MUID+l485Q==
|
||||||
/core-util-is/1.0.2:
|
/core-util-is/1.0.2:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
@ -688,6 +778,12 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
|
integrity: sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
|
||||||
|
/defaults/1.0.3:
|
||||||
|
dependencies:
|
||||||
|
clone: 1.0.4
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=
|
||||||
/delegates/1.0.0:
|
/delegates/1.0.0:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
@ -750,14 +846,7 @@ packages:
|
|||||||
node: '>=8.6'
|
node: '>=8.6'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
|
integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
|
||||||
/escalade/3.1.1:
|
|
||||||
dev: false
|
|
||||||
engines:
|
|
||||||
node: '>=6'
|
|
||||||
resolution:
|
|
||||||
integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
|
|
||||||
/escape-string-regexp/1.0.5:
|
/escape-string-regexp/1.0.5:
|
||||||
dev: true
|
|
||||||
engines:
|
engines:
|
||||||
node: '>=0.8.0'
|
node: '>=0.8.0'
|
||||||
resolution:
|
resolution:
|
||||||
@ -906,6 +995,16 @@ packages:
|
|||||||
node: '>=0.10.0'
|
node: '>=0.10.0'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
|
integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
|
||||||
|
/external-editor/3.1.0:
|
||||||
|
dependencies:
|
||||||
|
chardet: 0.7.0
|
||||||
|
iconv-lite: 0.4.24
|
||||||
|
tmp: 0.0.33
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
|
||||||
/fast-deep-equal/3.1.3:
|
/fast-deep-equal/3.1.3:
|
||||||
dev: true
|
dev: true
|
||||||
resolution:
|
resolution:
|
||||||
@ -937,6 +1036,14 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==
|
integrity: sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==
|
||||||
|
/figures/3.2.0:
|
||||||
|
dependencies:
|
||||||
|
escape-string-regexp: 1.0.5
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=8'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
|
||||||
/file-entry-cache/6.0.1:
|
/file-entry-cache/6.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
flat-cache: 3.0.4
|
flat-cache: 3.0.4
|
||||||
@ -966,6 +1073,16 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==
|
integrity: sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==
|
||||||
|
/fs-extra/10.0.0:
|
||||||
|
dependencies:
|
||||||
|
graceful-fs: 4.2.6
|
||||||
|
jsonfile: 6.1.0
|
||||||
|
universalify: 2.0.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=12'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==
|
||||||
/fs-extra/9.1.0:
|
/fs-extra/9.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
at-least-node: 1.0.0
|
at-least-node: 1.0.0
|
||||||
@ -1009,12 +1126,6 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
|
integrity: sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
|
||||||
/get-caller-file/2.0.5:
|
|
||||||
dev: false
|
|
||||||
engines:
|
|
||||||
node: 6.* || 8.* || >= 10.*
|
|
||||||
resolution:
|
|
||||||
integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
|
||||||
/get-intrinsic/1.1.1:
|
/get-intrinsic/1.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
function-bind: 1.1.1
|
function-bind: 1.1.1
|
||||||
@ -1095,7 +1206,6 @@ packages:
|
|||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
|
integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
|
||||||
/has-flag/4.0.0:
|
/has-flag/4.0.0:
|
||||||
dev: true
|
|
||||||
engines:
|
engines:
|
||||||
node: '>=8'
|
node: '>=8'
|
||||||
resolution:
|
resolution:
|
||||||
@ -1127,6 +1237,18 @@ packages:
|
|||||||
node: '>= 6'
|
node: '>= 6'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==
|
integrity: sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==
|
||||||
|
/iconv-lite/0.4.24:
|
||||||
|
dependencies:
|
||||||
|
safer-buffer: 2.1.2
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
||||||
|
/ieee754/1.2.1:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
||||||
/ignore/4.0.6:
|
/ignore/4.0.6:
|
||||||
dev: true
|
dev: true
|
||||||
engines:
|
engines:
|
||||||
@ -1163,6 +1285,27 @@ packages:
|
|||||||
/inherits/2.0.4:
|
/inherits/2.0.4:
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||||
|
/inquirer/8.1.1:
|
||||||
|
dependencies:
|
||||||
|
ansi-escapes: 4.3.2
|
||||||
|
chalk: 4.1.1
|
||||||
|
cli-cursor: 3.1.0
|
||||||
|
cli-width: 3.0.0
|
||||||
|
external-editor: 3.1.0
|
||||||
|
figures: 3.2.0
|
||||||
|
lodash: 4.17.21
|
||||||
|
mute-stream: 0.0.8
|
||||||
|
ora: 5.4.1
|
||||||
|
run-async: 2.4.1
|
||||||
|
rxjs: 6.6.7
|
||||||
|
string-width: 4.2.2
|
||||||
|
strip-ansi: 6.0.0
|
||||||
|
through: 2.3.8
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=8.0.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-hUDjc3vBkh/uk1gPfMAD/7Z188Q8cvTGl0nxwaCdwSbzFh6ZKkZh+s2ozVxbE5G9ZNRyeY0+lgbAIOUFsFf98w==
|
||||||
/interpret/1.4.0:
|
/interpret/1.4.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
@ -1209,6 +1352,12 @@ packages:
|
|||||||
node: '>=0.10.0'
|
node: '>=0.10.0'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
|
integrity: sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
|
||||||
|
/is-interactive/1.0.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=8'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
|
||||||
/is-number/7.0.0:
|
/is-number/7.0.0:
|
||||||
dev: true
|
dev: true
|
||||||
engines:
|
engines:
|
||||||
@ -1228,10 +1377,12 @@ packages:
|
|||||||
node: '>= 0.4'
|
node: '>= 0.4'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==
|
integrity: sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==
|
||||||
/isarray/0.0.1:
|
/is-unicode-supported/0.1.0:
|
||||||
dev: false
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=10'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
|
integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
|
||||||
/isarray/1.0.0:
|
/isarray/1.0.0:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
@ -1307,6 +1458,15 @@ packages:
|
|||||||
/lodash/4.17.21:
|
/lodash/4.17.21:
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||||
|
/log-symbols/4.1.0:
|
||||||
|
dependencies:
|
||||||
|
chalk: 4.1.1
|
||||||
|
is-unicode-supported: 0.1.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=10'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
|
||||||
/lru-cache/5.1.1:
|
/lru-cache/5.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
yallist: 3.1.1
|
yallist: 3.1.1
|
||||||
@ -1358,6 +1518,26 @@ packages:
|
|||||||
node: '>=8.6'
|
node: '>=8.6'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==
|
integrity: sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==
|
||||||
|
/mime-db/1.48.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>= 0.6'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==
|
||||||
|
/mime-types/2.1.31:
|
||||||
|
dependencies:
|
||||||
|
mime-db: 1.48.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>= 0.6'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==
|
||||||
|
/mimic-fn/2.1.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=6'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
|
||||||
/minimatch/3.0.4:
|
/minimatch/3.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion: 1.1.11
|
brace-expansion: 1.1.11
|
||||||
@ -1394,6 +1574,10 @@ packages:
|
|||||||
/ms/2.1.2:
|
/ms/2.1.2:
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||||
|
/mute-stream/0.0.8:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
|
||||||
/nan/2.14.2:
|
/nan/2.14.2:
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
@ -1423,13 +1607,6 @@ packages:
|
|||||||
node: 4.x || >=6.0.0
|
node: 4.x || >=6.0.0
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
integrity: sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||||
/noms/0.0.0:
|
|
||||||
dependencies:
|
|
||||||
inherits: 2.0.4
|
|
||||||
readable-stream: 1.0.34
|
|
||||||
dev: false
|
|
||||||
resolution:
|
|
||||||
integrity: sha1-2o69nzr51nYJGbJ9nNyAkqczKFk=
|
|
||||||
/nopt/5.0.0:
|
/nopt/5.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
abbrev: 1.1.1
|
abbrev: 1.1.1
|
||||||
@ -1465,6 +1642,14 @@ packages:
|
|||||||
wrappy: 1.0.2
|
wrappy: 1.0.2
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||||
|
/onetime/5.1.2:
|
||||||
|
dependencies:
|
||||||
|
mimic-fn: 2.1.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=6'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
|
||||||
/onigasm/2.2.5:
|
/onigasm/2.2.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
lru-cache: 5.1.1
|
lru-cache: 5.1.1
|
||||||
@ -1484,6 +1669,28 @@ packages:
|
|||||||
node: '>= 0.8.0'
|
node: '>= 0.8.0'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
|
integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
|
||||||
|
/ora/5.4.1:
|
||||||
|
dependencies:
|
||||||
|
bl: 4.1.0
|
||||||
|
chalk: 4.1.1
|
||||||
|
cli-cursor: 3.1.0
|
||||||
|
cli-spinners: 2.6.0
|
||||||
|
is-interactive: 1.0.0
|
||||||
|
is-unicode-supported: 0.1.0
|
||||||
|
log-symbols: 4.1.0
|
||||||
|
strip-ansi: 6.0.0
|
||||||
|
wcwidth: 1.0.1
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=10'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==
|
||||||
|
/os-tmpdir/1.0.2:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
|
||||||
/packet-reader/1.0.0:
|
/packet-reader/1.0.0:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
@ -1736,15 +1943,6 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
||||||
/readable-stream/1.0.34:
|
|
||||||
dependencies:
|
|
||||||
core-util-is: 1.0.2
|
|
||||||
inherits: 2.0.4
|
|
||||||
isarray: 0.0.1
|
|
||||||
string_decoder: 0.10.31
|
|
||||||
dev: false
|
|
||||||
resolution:
|
|
||||||
integrity: sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=
|
|
||||||
/readable-stream/2.3.7:
|
/readable-stream/2.3.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
core-util-is: 1.0.2
|
core-util-is: 1.0.2
|
||||||
@ -1779,18 +1977,16 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
|
integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
|
||||||
|
/regenerator-runtime/0.13.7:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
|
||||||
/regexpp/3.1.0:
|
/regexpp/3.1.0:
|
||||||
dev: true
|
dev: true
|
||||||
engines:
|
engines:
|
||||||
node: '>=8'
|
node: '>=8'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
|
integrity: sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
|
||||||
/require-directory/2.1.1:
|
|
||||||
dev: false
|
|
||||||
engines:
|
|
||||||
node: '>=0.10.0'
|
|
||||||
resolution:
|
|
||||||
integrity: sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
|
|
||||||
/require-from-string/2.0.2:
|
/require-from-string/2.0.2:
|
||||||
dev: true
|
dev: true
|
||||||
engines:
|
engines:
|
||||||
@ -1810,6 +2006,15 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
|
integrity: sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
|
||||||
|
/restore-cursor/3.1.0:
|
||||||
|
dependencies:
|
||||||
|
onetime: 5.1.2
|
||||||
|
signal-exit: 3.0.3
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=8'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
|
||||||
/reusify/1.0.4:
|
/reusify/1.0.4:
|
||||||
dev: true
|
dev: true
|
||||||
engines:
|
engines:
|
||||||
@ -1823,12 +2028,26 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
|
integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
|
||||||
|
/run-async/2.4.1:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.12.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
|
||||||
/run-parallel/1.2.0:
|
/run-parallel/1.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
queue-microtask: 1.2.3
|
queue-microtask: 1.2.3
|
||||||
dev: true
|
dev: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
|
integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
|
||||||
|
/rxjs/6.6.7:
|
||||||
|
dependencies:
|
||||||
|
tslib: 1.14.1
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
npm: '>=2.0.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
|
||||||
/safe-buffer/5.1.2:
|
/safe-buffer/5.1.2:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
@ -1971,10 +2190,6 @@ packages:
|
|||||||
node: '>=8'
|
node: '>=8'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==
|
integrity: sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==
|
||||||
/string_decoder/0.10.31:
|
|
||||||
dev: false
|
|
||||||
resolution:
|
|
||||||
integrity: sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
|
|
||||||
/string_decoder/1.1.1:
|
/string_decoder/1.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.1.2
|
safe-buffer: 5.1.2
|
||||||
@ -2019,11 +2234,19 @@ packages:
|
|||||||
/supports-color/7.2.0:
|
/supports-color/7.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
has-flag: 4.0.0
|
has-flag: 4.0.0
|
||||||
dev: true
|
|
||||||
engines:
|
engines:
|
||||||
node: '>=8'
|
node: '>=8'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
|
integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
|
||||||
|
/supports-hyperlinks/2.2.0:
|
||||||
|
dependencies:
|
||||||
|
has-flag: 4.0.0
|
||||||
|
supports-color: 7.2.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=8'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==
|
||||||
/table/6.7.1:
|
/table/6.7.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
ajv: 8.5.0
|
ajv: 8.5.0
|
||||||
@ -2050,17 +2273,31 @@ packages:
|
|||||||
node: '>= 10'
|
node: '>= 10'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==
|
integrity: sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==
|
||||||
|
/terminal-link/3.0.0:
|
||||||
|
dependencies:
|
||||||
|
ansi-escapes: 5.0.0
|
||||||
|
supports-hyperlinks: 2.2.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=12'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-flFL3m4wuixmf6IfhFJd1YPiLiMuxEc8uHRM1buzIeZPm22Au2pDqBJQgdo7n1WfPU1ONFGv7YDwpFBmHGF6lg==
|
||||||
/text-table/0.2.0:
|
/text-table/0.2.0:
|
||||||
dev: true
|
dev: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
|
integrity: sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
|
||||||
/through2/2.0.5:
|
/through/2.3.8:
|
||||||
dependencies:
|
|
||||||
readable-stream: 2.3.7
|
|
||||||
xtend: 4.0.2
|
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
|
integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
|
||||||
|
/tmp/0.0.33:
|
||||||
|
dependencies:
|
||||||
|
os-tmpdir: 1.0.2
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.6.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
|
||||||
/to-fast-properties/2.0.0:
|
/to-fast-properties/2.0.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
@ -2097,9 +2334,12 @@ packages:
|
|||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==
|
integrity: sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==
|
||||||
/tslib/1.14.1:
|
/tslib/1.14.1:
|
||||||
dev: true
|
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||||
|
/tslib/2.3.0:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
|
||||||
/tsutils/3.21.0_typescript@4.2.3:
|
/tsutils/3.21.0_typescript@4.2.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 1.14.1
|
tslib: 1.14.1
|
||||||
@ -2129,12 +2369,24 @@ packages:
|
|||||||
node: '>=10'
|
node: '>=10'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
|
integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
|
||||||
|
/type-fest/0.21.3:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=10'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
|
||||||
/type-fest/0.8.1:
|
/type-fest/0.8.1:
|
||||||
dev: true
|
dev: true
|
||||||
engines:
|
engines:
|
||||||
node: '>=8'
|
node: '>=8'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
|
integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
|
||||||
|
/type-fest/1.2.1:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=10'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-SbmIRuXhJs8KTneu77Ecylt9zuqL683tuiLYpTRil4H++eIhqCmx6ko6KAFem9dty8sOdnEiX7j4K1nRE628fQ==
|
||||||
/typedoc-default-themes/0.10.2:
|
/typedoc-default-themes/0.10.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
lunr: 2.3.9
|
lunr: 2.3.9
|
||||||
@ -2207,12 +2459,6 @@ packages:
|
|||||||
node: '>= 10.0.0'
|
node: '>= 10.0.0'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
|
integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
|
||||||
/untildify/4.0.0:
|
|
||||||
dev: false
|
|
||||||
engines:
|
|
||||||
node: '>=8'
|
|
||||||
resolution:
|
|
||||||
integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==
|
|
||||||
/uri-js/4.4.1:
|
/uri-js/4.4.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
punycode: 2.1.1
|
punycode: 2.1.1
|
||||||
@ -2242,6 +2488,12 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-c0Q4zYZkcLizeYJ3hNyaVUM2AA8KDhNCA3JvXY8CeZSJuBdAy3bAvSbv46RClC4P3dSO9BdwhnKEx2zOo6vP/w==
|
integrity: sha512-c0Q4zYZkcLizeYJ3hNyaVUM2AA8KDhNCA3JvXY8CeZSJuBdAy3bAvSbv46RClC4P3dSO9BdwhnKEx2zOo6vP/w==
|
||||||
|
/wcwidth/1.0.1:
|
||||||
|
dependencies:
|
||||||
|
defaults: 1.0.3
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=
|
||||||
/which/2.0.2:
|
/which/2.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
isexe: 2.0.0
|
isexe: 2.0.0
|
||||||
@ -2278,16 +2530,6 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
|
integrity: sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
|
||||||
/wrap-ansi/7.0.0:
|
|
||||||
dependencies:
|
|
||||||
ansi-styles: 4.3.0
|
|
||||||
string-width: 4.2.2
|
|
||||||
strip-ansi: 6.0.0
|
|
||||||
dev: false
|
|
||||||
engines:
|
|
||||||
node: '>=10'
|
|
||||||
resolution:
|
|
||||||
integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
|
||||||
/wrappy/1.0.2:
|
/wrappy/1.0.2:
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||||
@ -2297,12 +2539,6 @@ packages:
|
|||||||
node: '>=0.4'
|
node: '>=0.4'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
||||||
/y18n/5.0.8:
|
|
||||||
dev: false
|
|
||||||
engines:
|
|
||||||
node: '>=10'
|
|
||||||
resolution:
|
|
||||||
integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
|
|
||||||
/yallist/3.1.1:
|
/yallist/3.1.1:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
@ -2310,26 +2546,6 @@ packages:
|
|||||||
/yallist/4.0.0:
|
/yallist/4.0.0:
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
||||||
/yargs-parser/20.2.9:
|
|
||||||
dev: false
|
|
||||||
engines:
|
|
||||||
node: '>=10'
|
|
||||||
resolution:
|
|
||||||
integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
|
|
||||||
/yargs/16.2.0:
|
|
||||||
dependencies:
|
|
||||||
cliui: 7.0.4
|
|
||||||
escalade: 3.1.1
|
|
||||||
get-caller-file: 2.0.5
|
|
||||||
require-directory: 2.1.1
|
|
||||||
string-width: 4.2.2
|
|
||||||
y18n: 5.0.8
|
|
||||||
yargs-parser: 20.2.9
|
|
||||||
dev: false
|
|
||||||
engines:
|
|
||||||
node: '>=10'
|
|
||||||
resolution:
|
|
||||||
integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
|
|
||||||
/yn/3.1.1:
|
/yn/3.1.1:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
@ -2337,12 +2553,14 @@ packages:
|
|||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
|
integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
|
||||||
specifiers:
|
specifiers:
|
||||||
|
'@atao60/fse-cli': ^0.1.6
|
||||||
'@types/bcrypt': ^5.0.0
|
'@types/bcrypt': ^5.0.0
|
||||||
'@types/busboy': ^0.2.3
|
'@types/busboy': ^0.2.3
|
||||||
'@types/cli-table': ^0.3.0
|
'@types/cli-table': ^0.3.0
|
||||||
|
'@types/mime-types': ^2.1.0
|
||||||
'@types/mkdirp': ^1.0.1
|
'@types/mkdirp': ^1.0.1
|
||||||
'@types/negotiator': ^0.6.1
|
'@types/negotiator': ^0.6.1
|
||||||
'@types/node': ^14.14.37
|
'@types/node': ^14.17.4
|
||||||
'@types/pg': ^8.6.0
|
'@types/pg': ^8.6.0
|
||||||
'@types/pluralize': ^0.0.29
|
'@types/pluralize': ^0.0.29
|
||||||
'@types/pug': ^2.0.4
|
'@types/pug': ^2.0.4
|
||||||
@ -2355,9 +2573,9 @@ specifiers:
|
|||||||
busboy: ^0.3.1
|
busboy: ^0.3.1
|
||||||
cli-table: ^0.3.6
|
cli-table: ^0.3.6
|
||||||
colors: ^1.4.0
|
colors: ^1.4.0
|
||||||
copyfiles: ^2.4.1
|
|
||||||
dotenv: ^8.2.0
|
dotenv: ^8.2.0
|
||||||
eslint: ^7.27.0
|
eslint: ^7.27.0
|
||||||
|
mime-types: ^2.1.31
|
||||||
mkdirp: ^1.0.4
|
mkdirp: ^1.0.4
|
||||||
negotiator: ^0.6.2
|
negotiator: ^0.6.2
|
||||||
pg: ^8.6.0
|
pg: ^8.6.0
|
||||||
|
@ -10,8 +10,9 @@ export class HTTPError extends ErrorWithContext {
|
|||||||
constructor(
|
constructor(
|
||||||
public readonly status: HTTPStatus = 500,
|
public readonly status: HTTPStatus = 500,
|
||||||
public readonly message: string = '',
|
public readonly message: string = '',
|
||||||
|
context?: {[key: string]: any},
|
||||||
) {
|
) {
|
||||||
super('HTTP ERROR')
|
super('HTTP ERROR', context)
|
||||||
this.message = message || HTTPMessage[status]
|
this.message = message || HTTPMessage[status]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ import {Request} from '../../lifecycle/Request'
|
|||||||
import {plaintext} from '../../response/StringResponseFactory'
|
import {plaintext} from '../../response/StringResponseFactory'
|
||||||
import {ResponseFactory} from '../../response/ResponseFactory'
|
import {ResponseFactory} from '../../response/ResponseFactory'
|
||||||
import {json} from '../../response/JSONResponseFactory'
|
import {json} from '../../response/JSONResponseFactory'
|
||||||
|
import {UniversalPath} from '../../../util'
|
||||||
|
import {file} from '../../response/FileResponseFactory'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for HTTP kernel modules that apply some response from a route handler to the request.
|
* Base class for HTTP kernel modules that apply some response from a route handler to the request.
|
||||||
@ -22,6 +24,8 @@ export abstract class AbstractResolvedRouteHandlerHTTPModule extends HTTPKernelM
|
|||||||
|
|
||||||
if ( object instanceof ResponseFactory ) {
|
if ( object instanceof ResponseFactory ) {
|
||||||
await object.write(request)
|
await object.write(request)
|
||||||
|
} else if ( object instanceof UniversalPath ) {
|
||||||
|
await file(object).write(request)
|
||||||
} else if ( typeof object !== 'undefined' ) {
|
} else if ( typeof object !== 'undefined' ) {
|
||||||
await json(object).write(request)
|
await json(object).write(request)
|
||||||
} else {
|
} else {
|
||||||
|
@ -2,6 +2,7 @@ import {Request} from './Request'
|
|||||||
import {ErrorWithContext, HTTPStatus, BehaviorSubject} from '../../util'
|
import {ErrorWithContext, HTTPStatus, BehaviorSubject} from '../../util'
|
||||||
import {ServerResponse} from 'http'
|
import {ServerResponse} from 'http'
|
||||||
import {HTTPCookieJar} from '../kernel/HTTPCookieJar'
|
import {HTTPCookieJar} from '../kernel/HTTPCookieJar'
|
||||||
|
import {Readable} from 'stream'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error thrown when the server tries to re-send headers after they have been sent once.
|
* Error thrown when the server tries to re-send headers after they have been sent once.
|
||||||
@ -47,7 +48,7 @@ export class Response {
|
|||||||
private isBlockingWriteback = false
|
private isBlockingWriteback = false
|
||||||
|
|
||||||
/** The body contents that should be written to the response. */
|
/** The body contents that should be written to the response. */
|
||||||
public body = ''
|
public body: string | Buffer | Uint8Array | Readable = ''
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Behavior subject fired right before the response content is written.
|
* Behavior subject fired right before the response content is written.
|
||||||
@ -192,11 +193,21 @@ export class Response {
|
|||||||
* Write the headers and specified data to the client.
|
* Write the headers and specified data to the client.
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
public async write(data: unknown): Promise<void> {
|
public async write(data: string | Buffer | Uint8Array | Readable): Promise<void> {
|
||||||
return new Promise<void>((res, rej) => {
|
return new Promise<void>((res, rej) => {
|
||||||
if ( !this.sentHeaders ) {
|
if ( !this.sentHeaders ) {
|
||||||
this.sendHeaders()
|
this.sendHeaders()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( data instanceof Readable ) {
|
||||||
|
data.pipe(this.serverResponse)
|
||||||
|
.on('finish', () => {
|
||||||
|
res()
|
||||||
|
})
|
||||||
|
.on('error', error => {
|
||||||
|
rej(error)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
this.serverResponse.write(data, error => {
|
this.serverResponse.write(data, error => {
|
||||||
if ( error ) {
|
if ( error ) {
|
||||||
rej(error)
|
rej(error)
|
||||||
@ -204,6 +215,7 @@ export class Response {
|
|||||||
res()
|
res()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,9 +224,14 @@ export class Response {
|
|||||||
*/
|
*/
|
||||||
public async send(): Promise<void> {
|
public async send(): Promise<void> {
|
||||||
await this.sending$.next(this)
|
await this.sending$.next(this)
|
||||||
|
|
||||||
|
if ( !(this.body instanceof Readable) ) {
|
||||||
this.setHeader('Content-Length', String(this.body?.length ?? 0))
|
this.setHeader('Content-Length', String(this.body?.length ?? 0))
|
||||||
|
}
|
||||||
|
|
||||||
await this.write(this.body ?? '')
|
await this.write(this.body ?? '')
|
||||||
this.end()
|
this.end()
|
||||||
|
|
||||||
await this.sent$.next(this)
|
await this.sent$.next(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
36
src/http/response/FileResponseFactory.ts
Normal file
36
src/http/response/FileResponseFactory.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import {ResponseFactory} from './ResponseFactory'
|
||||||
|
import {Request} from '../lifecycle/Request'
|
||||||
|
import {ErrorWithContext, UniversalPath} from '../../util'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function that creates a FileResponseFactory for the given path.
|
||||||
|
* @param path
|
||||||
|
*/
|
||||||
|
export function file(path: UniversalPath): FileResponseFactory {
|
||||||
|
return new FileResponseFactory(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP response factory that sends a file referenced by a given UniversalPath.
|
||||||
|
*/
|
||||||
|
export class FileResponseFactory extends ResponseFactory {
|
||||||
|
constructor(
|
||||||
|
/** The file to be sent. */
|
||||||
|
public readonly path: UniversalPath,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
public async write(request: Request): Promise<Request> {
|
||||||
|
if ( !(await this.path.isFile()) ) {
|
||||||
|
throw new ErrorWithContext(`Cannot write non-file resource as response: ${this.path}`, {
|
||||||
|
path: this.path,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
request.response.setHeader('Content-Type', this.path.contentType || 'application/octet-stream')
|
||||||
|
request.response.setHeader('Content-Length', String(await this.path.sizeInBytes()))
|
||||||
|
request.response.body = await this.path.readStream()
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
}
|
169
src/http/servers/static.ts
Normal file
169
src/http/servers/static.ts
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
import {Request} from '../lifecycle/Request'
|
||||||
|
import {ActivatedRoute} from '../routing/ActivatedRoute'
|
||||||
|
import {Config} from '../../service/Config'
|
||||||
|
import {Collection, HTTPStatus, UniversalPath, universalPath} from '../../util'
|
||||||
|
import {Application} from '../../lifecycle/Application'
|
||||||
|
import {HTTPError} from '../HTTPError'
|
||||||
|
import {view, ViewResponseFactory} from '../response/ViewResponseFactory'
|
||||||
|
import {redirect} from '../response/TemporaryRedirectResponseFactory'
|
||||||
|
import {file} from '../response/FileResponseFactory'
|
||||||
|
import {RouteHandler} from '../routing/Route'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the behavior of the static server.
|
||||||
|
*/
|
||||||
|
export interface StaticServerOptions {
|
||||||
|
/** If true, browsing to a directory route will show the directory listing page. */
|
||||||
|
directoryListing?: boolean
|
||||||
|
|
||||||
|
/** The path to the directory whose files should be served. */
|
||||||
|
basePath?: string | string[] | UniversalPath
|
||||||
|
|
||||||
|
/** If specified, only files with these extensions will be served. */
|
||||||
|
allowedExtensions?: string[]
|
||||||
|
|
||||||
|
/** If specified, files with these extensions will not be served. */
|
||||||
|
excludedExtensions?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTPError class thrown by the static server.
|
||||||
|
*/
|
||||||
|
export class StaticServerHTTPError extends HTTPError {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the response factory that shows the directory listing.
|
||||||
|
* @param dirname
|
||||||
|
* @param dirPath
|
||||||
|
*/
|
||||||
|
async function getDirectoryListingResponse(dirname: string, dirPath: UniversalPath): Promise<ViewResponseFactory> {
|
||||||
|
return view('@extollo:static:dirlist', {
|
||||||
|
dirname,
|
||||||
|
contents: (await (await dirPath.list())
|
||||||
|
.promiseMap(async path => {
|
||||||
|
const isDirectory = await path.isDirectory()
|
||||||
|
return {
|
||||||
|
isDirectory,
|
||||||
|
name: path.toBase,
|
||||||
|
size: isDirectory ? '-' : await path.sizeForHumans(),
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.sortBy(row => {
|
||||||
|
return `${row.isDirectory ? 0 : 1}${row.name}`
|
||||||
|
})
|
||||||
|
.all(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given file path has an extension that is allowed by
|
||||||
|
* the static server options.
|
||||||
|
* @param filePath
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
function isValidFileExtension(filePath: UniversalPath, options: StaticServerOptions): boolean {
|
||||||
|
return (
|
||||||
|
(
|
||||||
|
!options.allowedExtensions
|
||||||
|
|| options.allowedExtensions.includes(filePath.ext)
|
||||||
|
)
|
||||||
|
&& (
|
||||||
|
!options.excludedExtensions
|
||||||
|
|| !options.excludedExtensions.includes(filePath.ext)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the configured base path into a universal path.
|
||||||
|
* Defaults to `{app path}/resources/static` if none provided.
|
||||||
|
* @param appPath
|
||||||
|
* @param basePath
|
||||||
|
*/
|
||||||
|
function getBasePath(appPath: UniversalPath, basePath?: string | string[] | UniversalPath): UniversalPath {
|
||||||
|
if ( basePath instanceof UniversalPath ) {
|
||||||
|
return basePath
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !basePath ) {
|
||||||
|
return appPath.concat('resources', 'static')
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( Array.isArray(basePath) ) {
|
||||||
|
return appPath.concat(...basePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( basePath.startsWith('/') ) {
|
||||||
|
return universalPath(basePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
return appPath.concat(basePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a route handler that serves a directory as static files.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
export function staticServer(options: StaticServerOptions = {}): RouteHandler {
|
||||||
|
return async (request: Request) => {
|
||||||
|
const config = <Config> request.make(Config)
|
||||||
|
const route = <ActivatedRoute> request.make(ActivatedRoute)
|
||||||
|
const app = <Application> request.make(Application)
|
||||||
|
|
||||||
|
const staticConfig = config.get('server.builtIns.static', {})
|
||||||
|
const mergedOptions = {
|
||||||
|
...staticConfig,
|
||||||
|
...options,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve the path to the resource on the filesystem
|
||||||
|
const basePath = getBasePath(app.appPath(), mergedOptions.basePath)
|
||||||
|
const filePath = basePath.concat(...Collection.normalize<string>(route.params[0]))
|
||||||
|
|
||||||
|
// If the resolved path is outside of the base path, fail out
|
||||||
|
if ( !filePath.isChildOf(basePath) && !filePath.is(basePath) ) {
|
||||||
|
throw new StaticServerHTTPError(HTTPStatus.NOT_FOUND, 'File not found', {
|
||||||
|
basePath: basePath.toString(),
|
||||||
|
filePath: filePath.toString(),
|
||||||
|
route: route.path,
|
||||||
|
reason: 'Resolved file is not a child of the base path.',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the resolved file is an invalid file extension, fail out
|
||||||
|
if ( !isValidFileExtension(filePath, mergedOptions) ) {
|
||||||
|
throw new StaticServerHTTPError(HTTPStatus.NOT_FOUND, 'File not found', {
|
||||||
|
basePath: basePath.toString(),
|
||||||
|
filePath: filePath.toString(),
|
||||||
|
route: route.path,
|
||||||
|
allowedExtensions: mergedOptions.allowedExtensions,
|
||||||
|
excludedExtensions: mergedOptions.excludedExtensions,
|
||||||
|
reason: 'Resolved file is not an allowed extension type',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the resolved file does not exist on the filesystem, fail out
|
||||||
|
if ( !(await filePath.exists()) ) {
|
||||||
|
throw new StaticServerHTTPError(HTTPStatus.NOT_FOUND, `File not found: ${route.path}`, {
|
||||||
|
basePath: basePath.toString(),
|
||||||
|
filePath: filePath.toString(),
|
||||||
|
route: route.path,
|
||||||
|
reason: 'Resolved file does not exist on the filesystem',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the resolved path is a directory, send the directory listing response
|
||||||
|
if ( await filePath.isDirectory() ) {
|
||||||
|
if ( !route.path.endsWith('/') ) {
|
||||||
|
return redirect(`${route.path}/`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return getDirectoryListingResponse(route.path, filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, just send the file as the response body
|
||||||
|
return file(filePath)
|
||||||
|
}
|
||||||
|
}
|
@ -43,6 +43,7 @@ export * from './http/response/ResponseFactory'
|
|||||||
export * from './http/response/StringResponseFactory'
|
export * from './http/response/StringResponseFactory'
|
||||||
export * from './http/response/TemporaryRedirectResponseFactory'
|
export * from './http/response/TemporaryRedirectResponseFactory'
|
||||||
export * from './http/response/ViewResponseFactory'
|
export * from './http/response/ViewResponseFactory'
|
||||||
|
export * from './http/response/FileResponseFactory'
|
||||||
|
|
||||||
export * from './http/routing/ActivatedRoute'
|
export * from './http/routing/ActivatedRoute'
|
||||||
export * from './http/routing/Route'
|
export * from './http/routing/Route'
|
||||||
@ -57,6 +58,8 @@ export * from './http/session/MemorySession'
|
|||||||
|
|
||||||
export * from './http/Controller'
|
export * from './http/Controller'
|
||||||
|
|
||||||
|
export * from './http/servers/static'
|
||||||
|
|
||||||
export * from './service/Canonical'
|
export * from './service/Canonical'
|
||||||
export * from './service/CanonicalInstantiable'
|
export * from './service/CanonicalInstantiable'
|
||||||
export * from './service/CanonicalRecursive'
|
export * from './service/CanonicalRecursive'
|
||||||
|
45
src/resources/views/static/dirlist.pug
Normal file
45
src/resources/views/static/dirlist.pug
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
doctype html
|
||||||
|
html
|
||||||
|
head
|
||||||
|
title Index of #{dirname}
|
||||||
|
style.
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
td, th {
|
||||||
|
border: 1px solid #dddddd;
|
||||||
|
text-align: left;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:nth-child(even) {
|
||||||
|
background-color: #dddddd;
|
||||||
|
}
|
||||||
|
body
|
||||||
|
h1 Directory Listing
|
||||||
|
h2 #{dirname}
|
||||||
|
table
|
||||||
|
tr
|
||||||
|
th Name
|
||||||
|
th Type
|
||||||
|
th Size
|
||||||
|
tr
|
||||||
|
td 📂
|
||||||
|
a(href='..') ..
|
||||||
|
td Directory
|
||||||
|
td -
|
||||||
|
each entry in contents
|
||||||
|
tr
|
||||||
|
td #{entry.isDirectory ? '📂 ' : ''}
|
||||||
|
a(href='./' + entry.name) #{entry.name}
|
||||||
|
td #{entry.isDirectory ? 'Directory' : 'File'}
|
||||||
|
td #{entry.size}
|
||||||
|
if !config('server.poweredBy.hide', false)
|
||||||
|
hr
|
||||||
|
small retrieved at #{(new Date).toDateString()} #{(new Date).toTimeString()} | powered by <a href="https://extollo.garrettmills.dev/" target="_blank">Extollo</a>
|
@ -50,6 +50,20 @@ class Collection<T> {
|
|||||||
return new Collection(items)
|
return new Collection(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new collection from an item or array of items.
|
||||||
|
* Filters out undefined items.
|
||||||
|
* @param itemOrItems
|
||||||
|
*/
|
||||||
|
public static normalize<T2>(itemOrItems: (CollectionItem<T2> | undefined)[] | CollectionItem<T2> | undefined): Collection<T2> {
|
||||||
|
if ( !Array.isArray(itemOrItems) ) {
|
||||||
|
itemOrItems = [itemOrItems]
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = itemOrItems.filter(x => typeof x !== 'undefined') as CollectionItem<T2>[]
|
||||||
|
return new Collection<T2>(items)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a collection of "undefined" elements of a given size.
|
* Create a collection of "undefined" elements of a given size.
|
||||||
* @param size
|
* @param size
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import * as nodePath from 'path'
|
import * as nodePath from 'path'
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as mkdirp from 'mkdirp'
|
import * as mkdirp from 'mkdirp'
|
||||||
import { Filesystem } from './path/Filesystem'
|
import * as mime from 'mime-types'
|
||||||
import ReadableStream = NodeJS.ReadableStream;
|
import {FileNotFoundError, Filesystem} from './path/Filesystem'
|
||||||
import WritableStream = NodeJS.WritableStream;
|
import {Collection} from '../collection/Collection'
|
||||||
|
import {Readable, Writable} from 'stream'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An item that could represent a path.
|
* An item that could represent a path.
|
||||||
@ -22,6 +23,36 @@ export function universalPath(...parts: PathLike[]): UniversalPath {
|
|||||||
return main.concat(...concats)
|
return main.concat(...concats)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format bytes as human-readable text.
|
||||||
|
*
|
||||||
|
* @param bytes Number of bytes.
|
||||||
|
* @param si True to use metric (SI) units, aka powers of 1000. False to use
|
||||||
|
* binary (IEC), aka powers of 1024.
|
||||||
|
* @param dp Number of decimal places to display.
|
||||||
|
* @see https://stackoverflow.com/a/14919494/4971138
|
||||||
|
*/
|
||||||
|
export function bytesToHumanFileSize(bytes: number, si = false, dp = 1): string {
|
||||||
|
const thresh = si ? 1000 : 1024
|
||||||
|
|
||||||
|
if (Math.abs(bytes) < thresh) {
|
||||||
|
return bytes + ' B'
|
||||||
|
}
|
||||||
|
|
||||||
|
const units = si
|
||||||
|
? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
||||||
|
: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
|
||||||
|
let u = -1
|
||||||
|
const r = 10 ** dp
|
||||||
|
|
||||||
|
do {
|
||||||
|
bytes /= thresh
|
||||||
|
++u
|
||||||
|
} while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1)
|
||||||
|
|
||||||
|
return bytes.toFixed(dp) + ' ' + units[u]
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walk recursively over entries in a directory.
|
* Walk recursively over entries in a directory.
|
||||||
*
|
*
|
||||||
@ -155,6 +186,13 @@ export class UniversalPath {
|
|||||||
return `${this.prefix}${this.resourceLocalPath}`
|
return `${this.prefix}${this.resourceLocalPath}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the basename of the path.
|
||||||
|
*/
|
||||||
|
get toBase(): string {
|
||||||
|
return nodePath.basename(this.resourceLocalPath)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append and resolve the given paths to this resource and return a new UniversalPath.
|
* Append and resolve the given paths to this resource and return a new UniversalPath.
|
||||||
*
|
*
|
||||||
@ -224,6 +262,44 @@ export class UniversalPath {
|
|||||||
return walk(this.resourceLocalPath)
|
return walk(this.resourceLocalPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves true if this resource is a directory.
|
||||||
|
*/
|
||||||
|
async isDirectory(): Promise<boolean> {
|
||||||
|
if ( this.filesystem ) {
|
||||||
|
const stat = await this.filesystem.stat({
|
||||||
|
storePath: this.resourceLocalPath,
|
||||||
|
})
|
||||||
|
|
||||||
|
return stat.isDirectory
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return (await fs.promises.stat(this.resourceLocalPath)).isDirectory()
|
||||||
|
} catch (e) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves true if this resource is a regular file.
|
||||||
|
*/
|
||||||
|
async isFile(): Promise<boolean> {
|
||||||
|
if ( this.filesystem ) {
|
||||||
|
const stat = await this.filesystem.stat({
|
||||||
|
storePath: this.resourceLocalPath,
|
||||||
|
})
|
||||||
|
|
||||||
|
return stat.isFile
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return (await fs.promises.stat(this.resourceLocalPath)).isFile()
|
||||||
|
} catch (e) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given resource exists at the path.
|
* Returns true if the given resource exists at the path.
|
||||||
*/
|
*/
|
||||||
@ -244,6 +320,20 @@ export class UniversalPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List any immediate children of this resource.
|
||||||
|
*/
|
||||||
|
async list(): Promise<Collection<UniversalPath>> {
|
||||||
|
if ( this.filesystem ) {
|
||||||
|
const files = await this.filesystem.list(this.resourceLocalPath)
|
||||||
|
return files.map(x => this.concat(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
const paths = await fs.promises.readdir(this.resourceLocalPath)
|
||||||
|
return Collection.collect<string>(paths)
|
||||||
|
.map(x => this.concat(x))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively create this path as a directory. Equivalent to `mkdir -p` on Linux.
|
* Recursively create this path as a directory. Equivalent to `mkdir -p` on Linux.
|
||||||
*/
|
*/
|
||||||
@ -290,7 +380,7 @@ export class UniversalPath {
|
|||||||
/**
|
/**
|
||||||
* Get a writable stream to this file's contents.
|
* Get a writable stream to this file's contents.
|
||||||
*/
|
*/
|
||||||
async writeStream(): Promise<WritableStream> {
|
async writeStream(): Promise<Writable> {
|
||||||
if ( this.filesystem ) {
|
if ( this.filesystem ) {
|
||||||
return this.filesystem.putStoreFileAsStream({
|
return this.filesystem.putStoreFileAsStream({
|
||||||
storePath: this.resourceLocalPath,
|
storePath: this.resourceLocalPath,
|
||||||
@ -304,7 +394,7 @@ export class UniversalPath {
|
|||||||
* Read the data from this resource's file as a string.
|
* Read the data from this resource's file as a string.
|
||||||
*/
|
*/
|
||||||
async read(): Promise<string> {
|
async read(): Promise<string> {
|
||||||
let stream: ReadableStream
|
let stream: Readable
|
||||||
if ( this.filesystem ) {
|
if ( this.filesystem ) {
|
||||||
stream = await this.filesystem.getStoreFileAsStream({
|
stream = await this.filesystem.getStoreFileAsStream({
|
||||||
storePath: this.resourceLocalPath,
|
storePath: this.resourceLocalPath,
|
||||||
@ -321,10 +411,37 @@ export class UniversalPath {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the size of this resource in bytes.
|
||||||
|
*/
|
||||||
|
async sizeInBytes(): Promise<number> {
|
||||||
|
if ( this.filesystem ) {
|
||||||
|
const stat = await this.filesystem.stat({
|
||||||
|
storePath: this.resourceLocalPath,
|
||||||
|
})
|
||||||
|
|
||||||
|
if ( stat.exists ) {
|
||||||
|
return stat.sizeInBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FileNotFoundError(this.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
const stat = await fs.promises.stat(this.resourceLocalPath)
|
||||||
|
return stat.size
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the size of this resource, formatted in a human-readable string.
|
||||||
|
*/
|
||||||
|
async sizeForHumans(): Promise<string> {
|
||||||
|
return bytesToHumanFileSize(await this.sizeInBytes())
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a readable stream of this file's contents.
|
* Get a readable stream of this file's contents.
|
||||||
*/
|
*/
|
||||||
async readStream(): Promise<ReadableStream> {
|
async readStream(): Promise<Readable> {
|
||||||
if ( this.filesystem ) {
|
if ( this.filesystem ) {
|
||||||
return this.filesystem.getStoreFileAsStream({
|
return this.filesystem.getStoreFileAsStream({
|
||||||
storePath: this.resourceLocalPath,
|
storePath: this.resourceLocalPath,
|
||||||
@ -334,17 +451,70 @@ export class UniversalPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get mime_type() {
|
/**
|
||||||
return Mime.lookup(this.ext)
|
* Returns true if this path exists in the subtree of the given path.
|
||||||
|
* @param otherPath
|
||||||
|
*/
|
||||||
|
isChildOf(otherPath: UniversalPath): boolean {
|
||||||
|
if ( (this.filesystem || otherPath.filesystem) && otherPath.filesystem !== this.filesystem ) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
get content_type() {
|
if ( this.prefix !== otherPath.prefix ) {
|
||||||
return Mime.contentType(this.ext)
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
get charset() {
|
const relative = nodePath.relative(otherPath.toLocal, this.toLocal)
|
||||||
if ( this.mime_type ) {
|
return Boolean(relative && !relative.startsWith('..') && !nodePath.isAbsolute(relative))
|
||||||
return Mime.charset(this.mime_type)
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given path exists in the subtree of this path.
|
||||||
|
* @param otherPath
|
||||||
|
*/
|
||||||
|
isParentOf(otherPath: UniversalPath): boolean {
|
||||||
|
return otherPath.isChildOf(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given path refers to the same resource as this path.
|
||||||
|
* @param otherPath
|
||||||
|
*/
|
||||||
|
is(otherPath: UniversalPath): boolean {
|
||||||
|
if ( (this.filesystem || otherPath.filesystem) && otherPath.filesystem !== this.filesystem ) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( this.prefix !== otherPath.prefix ) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const relative = nodePath.relative(otherPath.toLocal, this.toLocal)
|
||||||
|
return relative === ''
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mime-type of this resource.
|
||||||
|
*/
|
||||||
|
get mimeType(): string | false {
|
||||||
|
return mime.lookup(this.resourceLocalPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the content-type header of this resource.
|
||||||
|
*/
|
||||||
|
get contentType(): string | false {
|
||||||
|
return mime.contentType(this.resourceLocalPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the charset of this resource.
|
||||||
|
*/
|
||||||
|
get charset(): string | false {
|
||||||
|
if ( this.mimeType ) {
|
||||||
|
return mime.charset(this.mimeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,10 @@ import {UniversalPath} from '../path'
|
|||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import * as os from 'os'
|
import * as os from 'os'
|
||||||
import {uuid4} from '../data'
|
import {uuid4} from '../data'
|
||||||
import ReadableStream = NodeJS.ReadableStream;
|
|
||||||
import WritableStream = NodeJS.WritableStream;
|
|
||||||
import {ErrorWithContext} from '../../error/ErrorWithContext'
|
import {ErrorWithContext} from '../../error/ErrorWithContext'
|
||||||
|
import {Readable, Writable} from 'stream'
|
||||||
|
import {Awaitable} from '../types'
|
||||||
|
import {Collection} from '../../collection/Collection'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error thrown when an operation is attempted on a non-existent file.
|
* Error thrown when an operation is attempted on a non-existent file.
|
||||||
@ -65,6 +66,16 @@ export interface Stat {
|
|||||||
*/
|
*/
|
||||||
tags: string[],
|
tags: string[],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if the resource exists as a directory.
|
||||||
|
*/
|
||||||
|
isDirectory: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if the resource exists as a regular file.
|
||||||
|
*/
|
||||||
|
isFile: boolean,
|
||||||
|
|
||||||
accessed?: Date,
|
accessed?: Date,
|
||||||
modified?: Date,
|
modified?: Date,
|
||||||
created?: Date,
|
created?: Date,
|
||||||
@ -77,12 +88,12 @@ export abstract class Filesystem {
|
|||||||
/**
|
/**
|
||||||
* Called when the Filesystem driver is initialized. Do any standup here.
|
* Called when the Filesystem driver is initialized. Do any standup here.
|
||||||
*/
|
*/
|
||||||
public open(): void | Promise<void> {} // eslint-disable-line @typescript-eslint/no-empty-function
|
public open(): Awaitable<void> {} // eslint-disable-line @typescript-eslint/no-empty-function
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the Filesystem driver is destroyed. Do any cleanup here.
|
* Called when the Filesystem driver is destroyed. Do any cleanup here.
|
||||||
*/
|
*/
|
||||||
public close(): void | Promise<void> {} // eslint-disable-line @typescript-eslint/no-empty-function
|
public close(): Awaitable<void> {} // eslint-disable-line @typescript-eslint/no-empty-function
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the URI prefix for this filesystem.
|
* Get the URI prefix for this filesystem.
|
||||||
@ -114,62 +125,67 @@ export abstract class Filesystem {
|
|||||||
*
|
*
|
||||||
* @param args
|
* @param args
|
||||||
*/
|
*/
|
||||||
public abstract putLocalFile(args: {localPath: string, storePath: string, mimeType?: string, tags?: string[], tag?: string}): void | Promise<void>
|
public abstract putLocalFile(args: {localPath: string, storePath: string, mimeType?: string, tags?: string[], tag?: string}): Awaitable<void>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download a file in the remote filesystem to the local filesystem and return it as a UniversalPath.
|
* Download a file in the remote filesystem to the local filesystem and return it as a UniversalPath.
|
||||||
* @param args
|
* @param args
|
||||||
*/
|
*/
|
||||||
public abstract getStoreFileAsTemp(args: {storePath: string}): UniversalPath | Promise<UniversalPath>
|
public abstract getStoreFileAsTemp(args: {storePath: string}): Awaitable<UniversalPath>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a readable stream for a file in the remote filesystem.
|
* Open a readable stream for a file in the remote filesystem.
|
||||||
* @param args
|
* @param args
|
||||||
*/
|
*/
|
||||||
public abstract getStoreFileAsStream(args: {storePath: string}): ReadableStream | Promise<ReadableStream>
|
public abstract getStoreFileAsStream(args: {storePath: string}): Awaitable<Readable>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a writable stream for a file in the remote filesystem.
|
* Open a writable stream for a file in the remote filesystem.
|
||||||
* @param args
|
* @param args
|
||||||
*/
|
*/
|
||||||
public abstract putStoreFileAsStream(args: {storePath: string}): WritableStream | Promise<WritableStream>
|
public abstract putStoreFileAsStream(args: {storePath: string}): Awaitable<Writable>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch some information about a file that may or may not be in the remote filesystem without fetching the entire file.
|
* Fetch some information about a file that may or may not be in the remote filesystem without fetching the entire file.
|
||||||
* @param args
|
* @param args
|
||||||
*/
|
*/
|
||||||
public abstract stat(args: {storePath: string}): Stat | Promise<Stat>
|
public abstract stat(args: {storePath: string}): Awaitable<Stat>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the file does not exist in the remote filesystem, create it. If it does exist, update the modify timestamps.
|
* If the file does not exist in the remote filesystem, create it. If it does exist, update the modify timestamps.
|
||||||
* @param args
|
* @param args
|
||||||
*/
|
*/
|
||||||
public abstract touch(args: {storePath: string}): void | Promise<void>
|
public abstract touch(args: {storePath: string}): Awaitable<void>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the given resource(s) from the remote filesystem.
|
* Remove the given resource(s) from the remote filesystem.
|
||||||
* @param args
|
* @param args
|
||||||
*/
|
*/
|
||||||
public abstract remove(args: {storePath: string, recursive?: boolean }): void | Promise<void>
|
public abstract remove(args: {storePath: string, recursive?: boolean }): Awaitable<void>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the given path on the store as a directory, recursively.
|
* Create the given path on the store as a directory, recursively.
|
||||||
* @param args
|
* @param args
|
||||||
*/
|
*/
|
||||||
public abstract mkdir(args: {storePath: string}): void | Promise<void>
|
public abstract mkdir(args: {storePath: string}): Awaitable<void>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the metadata object for the given file, if it exists.
|
* Get the metadata object for the given file, if it exists.
|
||||||
* @param storePath
|
* @param storePath
|
||||||
*/
|
*/
|
||||||
public abstract getMetadata(storePath: string): FileMetadata | Promise<FileMetadata>
|
public abstract getMetadata(storePath: string): Awaitable<FileMetadata>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the metadata object for the given file, if the file exists.
|
* Set the metadata object for the given file, if the file exists.
|
||||||
* @param storePath
|
* @param storePath
|
||||||
* @param meta
|
* @param meta
|
||||||
*/
|
*/
|
||||||
public abstract setMetadata(storePath: string, meta: FileMetadata): void | Promise<void>
|
public abstract setMetadata(storePath: string, meta: FileMetadata): Awaitable<void>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List direct children of this resource.
|
||||||
|
*/
|
||||||
|
public abstract list(storePath: string): Awaitable<Collection<string>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize the input tags into a single array of strings. This is useful for implementing the fluent
|
* Normalize the input tags into a single array of strings. This is useful for implementing the fluent
|
||||||
|
@ -4,6 +4,7 @@ import * as path from 'path'
|
|||||||
import {UniversalPath} from '../path'
|
import {UniversalPath} from '../path'
|
||||||
import * as rimraf from 'rimraf'
|
import * as rimraf from 'rimraf'
|
||||||
import * as mkdirp from 'mkdirp'
|
import * as mkdirp from 'mkdirp'
|
||||||
|
import { Collection } from '../../collection/Collection'
|
||||||
|
|
||||||
export interface LocalFilesystemConfig {
|
export interface LocalFilesystemConfig {
|
||||||
baseDir: string
|
baseDir: string
|
||||||
@ -87,6 +88,8 @@ export class LocalFilesystem extends Filesystem {
|
|||||||
accessed: stat.atime,
|
accessed: stat.atime,
|
||||||
modified: stat.mtime,
|
modified: stat.mtime,
|
||||||
created: stat.ctime,
|
created: stat.ctime,
|
||||||
|
isDirectory: stat.isDirectory(),
|
||||||
|
isFile: stat.isFile(),
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if ( e?.code === 'ENOENT' ) {
|
if ( e?.code === 'ENOENT' ) {
|
||||||
@ -95,6 +98,8 @@ export class LocalFilesystem extends Filesystem {
|
|||||||
exists: false,
|
exists: false,
|
||||||
sizeInBytes: 0,
|
sizeInBytes: 0,
|
||||||
tags: [],
|
tags: [],
|
||||||
|
isFile: false,
|
||||||
|
isDirectory: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,4 +171,13 @@ export class LocalFilesystem extends Filesystem {
|
|||||||
protected metadataPath(storePath: string): string {
|
protected metadataPath(storePath: string): string {
|
||||||
return path.resolve(this.baseConfig.baseDir, 'meta', storePath + '.json')
|
return path.resolve(this.baseConfig.baseDir, 'meta', storePath + '.json')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all immediate children of the given path.
|
||||||
|
* @param storePath
|
||||||
|
*/
|
||||||
|
public async list(storePath: string): Promise<Collection<string>> {
|
||||||
|
const paths = await fs.promises.readdir(this.storePath(storePath))
|
||||||
|
return Collection.collect<string>(paths)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ import {FileMetadata, Filesystem, Stat} from './Filesystem'
|
|||||||
import * as ssh2 from 'ssh2'
|
import * as ssh2 from 'ssh2'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import ReadableStream = NodeJS.ReadableStream
|
import {Readable, Writable} from 'stream'
|
||||||
|
import {Collection} from '../../collection/Collection'
|
||||||
import {UniversalPath} from '../path'
|
import {UniversalPath} from '../path'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,7 +38,7 @@ export class SSHFilesystem extends Filesystem {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async getStoreFileAsStream(args: { storePath: string }): Promise<ReadableStream> {
|
async getStoreFileAsStream(args: { storePath: string }): Promise<Readable> {
|
||||||
const sftp = await this.getSFTP()
|
const sftp = await this.getSFTP()
|
||||||
return sftp.createReadStream(this.storePath(args.storePath))
|
return sftp.createReadStream(this.storePath(args.storePath))
|
||||||
}
|
}
|
||||||
@ -62,7 +63,7 @@ export class SSHFilesystem extends Filesystem {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async putStoreFileAsStream(args: { storePath: string }): Promise<NodeJS.WritableStream> {
|
async putStoreFileAsStream(args: { storePath: string }): Promise<Writable> {
|
||||||
const sftp = await this.getSFTP()
|
const sftp = await this.getSFTP()
|
||||||
return sftp.createWriteStream(this.storePath(args.storePath))
|
return sftp.createWriteStream(this.storePath(args.storePath))
|
||||||
}
|
}
|
||||||
@ -126,6 +127,8 @@ export class SSHFilesystem extends Filesystem {
|
|||||||
accessed: stat.atime,
|
accessed: stat.atime,
|
||||||
modified: stat.mtime,
|
modified: stat.mtime,
|
||||||
created: stat.ctime,
|
created: stat.ctime,
|
||||||
|
isFile: stat.isFile(),
|
||||||
|
isDirectory: stat.isDirectory(),
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return {
|
return {
|
||||||
@ -133,6 +136,8 @@ export class SSHFilesystem extends Filesystem {
|
|||||||
exists: false,
|
exists: false,
|
||||||
sizeInBytes: 0,
|
sizeInBytes: 0,
|
||||||
tags: [],
|
tags: [],
|
||||||
|
isFile: false,
|
||||||
|
isDirectory: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -243,7 +248,7 @@ export class SSHFilesystem extends Filesystem {
|
|||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
protected storePath(storePath: string): string {
|
protected storePath(storePath: string): string {
|
||||||
return path.resolve(this.baseConfig.baseDir, 'data', storePath)
|
return path.join(this.baseConfig.baseDir, 'data', storePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -252,7 +257,7 @@ export class SSHFilesystem extends Filesystem {
|
|||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
protected metadataPath(storePath: string): string {
|
protected metadataPath(storePath: string): string {
|
||||||
return path.resolve(this.baseConfig.baseDir, 'meta', storePath + '.json')
|
return path.join(this.baseConfig.baseDir, 'meta', storePath + '.json')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -268,4 +273,18 @@ export class SSHFilesystem extends Filesystem {
|
|||||||
stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')))
|
stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async list(storePath: string): Promise<Collection<string>> {
|
||||||
|
const sftp = await this.getSFTP()
|
||||||
|
|
||||||
|
return new Promise<Collection<string>>((res, rej) => {
|
||||||
|
sftp.readdir(this.storePath(storePath), (error, files) => {
|
||||||
|
if ( error ) {
|
||||||
|
rej(error)
|
||||||
|
} else {
|
||||||
|
res(Collection.collect(files).map(x => x.filename))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user