From 52e214e782c85a56d2f3d846fd0daa07c9cdd971 Mon Sep 17 00:00:00 2001 From: Trim21 Date: Fri, 12 May 2023 08:22:46 +0800 Subject: [PATCH] refactor: migrate helpers.js/s3-endpoints.js/signing.js to TypeScript (#1137) --- .eslintrc.js | 6 + .github/workflows/nodejs-windows.yml | 5 +- .github/workflows/nodejs.yml | 5 +- .gitignore | 1 + build.mjs | 39 +- package-lock.json | 786 ++++++++--------- package.json | 69 +- src/AssumeRoleProvider.js | 14 +- src/base-error.ts | 30 - src/errors.ts | 12 +- src/extensions.js | 10 +- src/helpers.js | 822 ------------------ src/helpers.ts | 328 +++++++ src/internal/helper.ts | 580 ++++++++++++ .../s3-endpoints.ts} | 9 +- src/internal/type.ts | 59 ++ {types => src}/minio.d.ts | 148 ++-- src/minio.js | 28 +- src/notification.js | 3 +- src/object-uploader.js | 2 +- src/promisify.js | 31 + src/{signing.js => signing.ts} | 119 ++- src/transformers.js | 2 +- src/xml-parsers.js | 13 +- tests/functional/functional-tests.js | 18 +- tests/unit/test.js | 8 +- 26 files changed, 1627 insertions(+), 1520 deletions(-) delete mode 100644 src/base-error.ts delete mode 100644 src/helpers.js create mode 100644 src/helpers.ts create mode 100644 src/internal/helper.ts rename src/{s3-endpoints.js => internal/s3-endpoints.ts} (88%) create mode 100644 src/internal/type.ts rename {types => src}/minio.d.ts (88%) create mode 100644 src/promisify.js rename src/{signing.js => signing.ts} (76%) diff --git a/.eslintrc.js b/.eslintrc.js index 97a72d1c..ea112c91 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -110,6 +110,12 @@ module.exports = { 'import/no-commonjs': 'error', }, }, + { + files: ['./src/**/*.ts'], + rules: { + 'prefer-const': 'error', + }, + }, { files: ['./tests/**/*'], rules: { diff --git a/.github/workflows/nodejs-windows.yml b/.github/workflows/nodejs-windows.yml index 51abb81c..ecb3b7a3 100644 --- a/.github/workflows/nodejs-windows.yml +++ b/.github/workflows/nodejs-windows.yml @@ -13,9 +13,9 @@ jobs: name: Test on node ${{ matrix.node_version }} and ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: - max-parallel: 3 + max-parallel: 2 matrix: - node_version: [12.x, 14.x, 16.x, 17.x, 18.x, 20.x] + node_version: [12.x, 14.x, 16.x, 18.x, 20.x] os: [windows-latest] steps: - uses: actions/checkout@v3 @@ -28,6 +28,7 @@ jobs: - run: npm i - name: Start MinIO Server -> Run Unit and Functional Tests + timeout-minutes: 10 env: CI: true MINIO_CI_CD: true diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 7c1c8db4..0893cb91 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -13,9 +13,9 @@ jobs: name: Test on node ${{ matrix.node_version }} and ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: - max-parallel: 3 + max-parallel: 2 matrix: - node_version: [12.x, 14.x, 16.x, 17.x, 18.x, 20.x] + node_version: [12.x, 14.x, 16.x, 18.x, 20.x] os: [ubuntu-latest] steps: - uses: actions/checkout@v3 @@ -28,6 +28,7 @@ jobs: - run: npm i - name: Start Server -> Run Unit and Functional Tests + timeout-minutes: 10 env: CI: true MINIO_CI_CD: true diff --git a/.gitignore b/.gitignore index 5e2c97e7..abd45344 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ node_modules yarn.lock .yarn/ .yarnrc.yml +pnpm-lock.yaml diff --git a/build.mjs b/build.mjs index bc5c662a..0ab77f34 100644 --- a/build.mjs +++ b/build.mjs @@ -1,8 +1,9 @@ /* eslint-disable no-console */ -import { execSync } from 'node:child_process' +import { exec } from 'node:child_process' import * as fs from 'node:fs' import * as fsp from 'node:fs/promises' import * as path from 'node:path' +import { promisify } from 'node:util' import * as babel from '@babel/core' import * as fsWalk from '@nodelib/fs.walk' @@ -48,7 +49,7 @@ function options(module) { constantReexports: true, }, plugins: module === 'esm' ? plugins.splice(1) : plugins, - presets: [['@babel/env', { targets: { node: '8' }, modules: false }], ['@babel/preset-typescript']], + presets: [['@babel/env', { targets: { node: '14' }, modules: false }], ['@babel/preset-typescript']], } } @@ -56,7 +57,7 @@ const extMap = { cjs: '.js', esm: '.mjs' } async function buildFiles({ files, module, outDir }) { console.log(`building for ${module}`) - execSync(`npx tsc --outDir ${outDir}`, { stdio: 'inherit' }) + await promisify(exec)(`npx tsc --outDir ${outDir}`, { stdio: 'inherit' }) const opt = options(module) for (const file of files) { @@ -64,24 +65,24 @@ async function buildFiles({ files, module, outDir }) { continue } - if (file.path.endsWith('.d.ts')) { - continue - } - const outFilePath = path.join(outDir, path.relative('src/', file.path)) const outDirPath = path.dirname(outFilePath) await fsp.mkdir(outDirPath, { recursive: true }) + const distCodePath = outFilePath.replace(/\.[tj]s$/g, extMap[module]) + + if (file.path.endsWith('.d.ts')) { + await fsp.copyFile(file.path, outFilePath) + continue + } try { - const result = await babel.transformAsync(fs.readFileSync(file.path).toString(), { + const result = await babel.transformAsync(await fsp.readFile(file.path, 'utf-8'), { filename: file.path, ...opt, }) - const distCodePath = outFilePath.replace(/\.[tj]s$/g, extMap[module]) - - fs.writeFileSync(distCodePath, result.code) + await fsp.writeFile(distCodePath, result.code) } catch (e) { console.error(`failed to transpile ${file.path}`) throw e @@ -93,17 +94,11 @@ async function main() { await fsp.rm('dist', { recursive: true, force: true }) const entries = fsWalk.walkSync('src/') - await buildFiles({ - files: entries, - module: 'cjs', - outDir: './dist/main/', - }) - - await buildFiles({ - files: entries, - module: 'esm', - outDir: './dist/esm/', - }) + + await Promise.all([ + buildFiles({ files: entries, module: 'cjs', outDir: './dist/main/' }), + buildFiles({ files: entries, module: 'esm', outDir: './dist/esm/' }), + ]) for (const file of fsWalk.walkSync('dist/esm/')) { if (file.dirent.isDirectory()) { diff --git a/package-lock.json b/package-lock.json index 33593aef..67d6a52b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,64 +9,63 @@ "version": "7.1.1", "license": "Apache-2.0", "dependencies": { - "async": "^3.1.0", - "block-stream2": "^2.0.0", - "browser-or-node": "^1.3.0", + "async": "^3.2.4", + "block-stream2": "^2.1.0", + "browser-or-node": "^2.1.1", "buffer-crc32": "^0.2.13", - "fast-xml-parser": "^4.1.3", + "fast-xml-parser": "^4.2.2", "ipaddr.js": "^2.0.1", "json-stream": "^1.0.0", "lodash": "^4.17.21", - "mime-types": "^2.1.14", - "mkdirp": "^0.5.1", - "query-string": "^7.1.1", - "through2": "^3.0.1", + "mime-types": "^2.1.35", + "mkdirp": "^0.5.6", + "query-string": "^7.1.3", + "through2": "^4.0.2", "web-encoding": "^1.1.5", - "xml": "^1.0.0", + "xml": "^1.0.1", "xml2js": "^0.5.0" }, "devDependencies": { - "@babel/core": "^7.12.10", + "@babel/core": "^7.21.8", "@babel/plugin-transform-modules-commonjs": "^7.21.5", - "@babel/preset-env": "^7.12.10", - "@babel/preset-typescript": "^7.21.4", + "@babel/preset-env": "^7.21.5", + "@babel/preset-typescript": "^7.21.5", "@babel/register": "^7.21.0", "@nodelib/fs.walk": "^1.2.8", - "@types/async": "^3.2.18", - "@types/browser-or-node": "^1.3.0", - "@types/lodash": "^4.14.192", + "@types/async": "^3.2.20", + "@types/lodash": "^4.14.194", "@types/mime-types": "^2.1.1", - "@types/node": "^18.15.11", + "@types/node": "^20.1.0", "@types/xml": "^1.0.8", "@types/xml2js": "^0.4.11", - "@typescript-eslint/eslint-plugin": "^5.57.1", - "@typescript-eslint/parser": "^5.57.1", - "@upleveled/babel-plugin-remove-node-prefix": "^1.0.4", + "@typescript-eslint/eslint-plugin": "^5.59.2", + "@typescript-eslint/parser": "^5.59.2", + "@upleveled/babel-plugin-remove-node-prefix": "^1.0.5", "babel-plugin-replace-import-extension": "^1.1.3", "babel-plugin-transform-replace-expressions": "^0.2.0", - "chai": "^4.2.0", + "chai": "^4.3.7", "dotenv": "^16.0.3", - "eslint": "^8.37.0", + "eslint": "^8.40.0", "eslint-config-prettier": "^8.8.0", "eslint-import-resolver-typescript": "^3.5.5", "eslint-plugin-import": "^2.27.5", "eslint-plugin-simple-import-sort": "^10.0.0", - "eslint-plugin-unicorn": "^46.0.0", + "eslint-plugin-unicorn": "^47.0.0", "eslint-plugin-unused-imports": "^2.0.0", "husky": "^8.0.3", - "lint-staged": "^13.2.1", - "mocha": "^9.2.0", - "mocha-steps": "^1.1.0", - "nock": "^13.2.2", - "prettier": "^2.8.7", - "source-map-support": "^0.5.13", - "split-file": "^2.2.2", - "superagent": "^5.1.0", + "lint-staged": "^13.2.2", + "mocha": "^10.2.0", + "mocha-steps": "^1.3.0", + "nock": "^13.3.1", + "prettier": "^2.8.8", + "source-map-support": "^0.5.21", + "split-file": "^2.3.0", + "superagent": "^8.0.1", "typescript": "^5.0.4", "uuid": "^9.0.0" }, "engines": { - "node": ">8 <=19" + "node": "^16 || ^18 || >=20" } }, "node_modules/@ampproject/remapping": { @@ -97,31 +96,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", - "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==", + "version": "7.21.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.7.tgz", + "integrity": "sha512-KYMqFYTaenzMK4yUtf4EW9wc4N9ef80FsbMtkwool5zpwl4YrT1SdWYSTRcT94KO4hannogdS+LxY7L+arP3gA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz", - "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==", + "version": "7.21.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.8.tgz", + "integrity": "sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-compilation-targets": "^7.21.4", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.4", + "@babel/generator": "^7.21.5", + "@babel/helper-compilation-targets": "^7.21.5", + "@babel/helper-module-transforms": "^7.21.5", + "@babel/helpers": "^7.21.5", + "@babel/parser": "^7.21.8", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.4", - "@babel/types": "^7.21.4", + "@babel/traverse": "^7.21.5", + "@babel/types": "^7.21.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -185,13 +183,12 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", - "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.5.tgz", + "integrity": "sha512-1RkbFGUKex4lvsB9yhIfWltJM5cZKUftB2eNajaDv3dCMEp49iBG0K14uH8NnX9IPux2+mK7JGEOB0jn48/J6w==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.21.4", + "@babel/compat-data": "^7.21.5", "@babel/helper-validator-option": "^7.21.0", "browserslist": "^4.21.3", "lru-cache": "^5.1.1", @@ -499,15 +496,14 @@ } }, "node_modules/@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.5.tgz", + "integrity": "sha512-BSY+JSlHxOmGsPTydUkPf1MdMQ3M81x5xGCOVgWM3G8XH77sJ292Y2oqcp0CbbgxhqBuI46iUz1tT7hqP7EfgA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" + "@babel/traverse": "^7.21.5", + "@babel/types": "^7.21.5" }, "engines": { "node": ">=6.9.0" @@ -1000,6 +996,18 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", @@ -1154,13 +1162,12 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", - "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.21.5.tgz", + "integrity": "sha512-wb1mhwGOCaXHDTcsRYMKF9e5bbMgqwxtqa2Y1ifH96dXJPwbuLX9qHy3clhrxVqgMz7nyNXs8VkxdH8UBcjKqA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.21.5" }, "engines": { "node": ">=6.9.0" @@ -1254,13 +1261,12 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", - "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.21.5.tgz", + "integrity": "sha512-TR653Ki3pAwxBxUe8srfF3e4Pe3FTA46uaNHYyQwIoM4oWKSoOZiDNyHJ0oIoDIUPSRQbQG7jzgVBX3FPVne1Q==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-plugin-utils": "^7.21.5", "@babel/template": "^7.20.7" }, "engines": { @@ -1337,13 +1343,12 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.21.0.tgz", - "integrity": "sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.21.5.tgz", + "integrity": "sha512-nYWpjKW/7j/I/mZkGVgHJXh4bA1sfdFnJoOXwJuj4m3Q2EraO/8ZyrkCau9P5tbHQk01RMSt6KYLCsW7730SXQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.21.5" }, "engines": { "node": ">=6.9.0" @@ -1555,13 +1560,12 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", - "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.21.5.tgz", + "integrity": "sha512-ZoYBKDb6LyMi5yCsByQ5jmXsHAQDDYeexT1Szvlmui+lADvfSecr5Dxd/PkrTC3pAD182Fcju1VQkB4oCp9M+w==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-plugin-utils": "^7.21.5", "regenerator-transform": "^0.15.1" }, "engines": { @@ -1687,13 +1691,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", - "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.21.5.tgz", + "integrity": "sha512-LYm/gTOwZqsYohlvFUe/8Tujz75LqqVC2w+2qPHLR+WyWHGCZPN1KBpJCJn+4Bk4gOkQy/IXKIge6az5MqwlOg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.21.5" }, "engines": { "node": ">=6.9.0" @@ -1720,15 +1723,14 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.21.4.tgz", - "integrity": "sha512-2W57zHs2yDLm6GD5ZpvNn71lZ0B/iypSdIeq25OurDKji6AdzV07qp4s3n1/x5BqtiGaTrPN3nerlSCaC5qNTw==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.21.5.tgz", + "integrity": "sha512-wH00QnTTldTbf/IefEVyChtRdw5RJvODT/Vb4Vcxq1AZvtXj6T0YeX0cAcXhI6/BdGuiP3GcNIL4OQbI2DVNxg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-compilation-targets": "^7.21.4", - "@babel/helper-plugin-utils": "^7.20.2", + "@babel/compat-data": "^7.21.5", + "@babel/helper-compilation-targets": "^7.21.5", + "@babel/helper-plugin-utils": "^7.21.5", "@babel/helper-validator-option": "^7.21.0", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.20.7", @@ -1753,6 +1755,7 @@ "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -1762,22 +1765,22 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.20.7", + "@babel/plugin-transform-arrow-functions": "^7.21.5", "@babel/plugin-transform-async-to-generator": "^7.20.7", "@babel/plugin-transform-block-scoped-functions": "^7.18.6", "@babel/plugin-transform-block-scoping": "^7.21.0", "@babel/plugin-transform-classes": "^7.21.0", - "@babel/plugin-transform-computed-properties": "^7.20.7", + "@babel/plugin-transform-computed-properties": "^7.21.5", "@babel/plugin-transform-destructuring": "^7.21.3", "@babel/plugin-transform-dotall-regex": "^7.18.6", "@babel/plugin-transform-duplicate-keys": "^7.18.9", "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.21.0", + "@babel/plugin-transform-for-of": "^7.21.5", "@babel/plugin-transform-function-name": "^7.18.9", "@babel/plugin-transform-literals": "^7.18.9", "@babel/plugin-transform-member-expression-literals": "^7.18.6", "@babel/plugin-transform-modules-amd": "^7.20.11", - "@babel/plugin-transform-modules-commonjs": "^7.21.2", + "@babel/plugin-transform-modules-commonjs": "^7.21.5", "@babel/plugin-transform-modules-systemjs": "^7.20.11", "@babel/plugin-transform-modules-umd": "^7.18.6", "@babel/plugin-transform-named-capturing-groups-regex": "^7.20.5", @@ -1785,17 +1788,17 @@ "@babel/plugin-transform-object-super": "^7.18.6", "@babel/plugin-transform-parameters": "^7.21.3", "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.20.5", + "@babel/plugin-transform-regenerator": "^7.21.5", "@babel/plugin-transform-reserved-words": "^7.18.6", "@babel/plugin-transform-shorthand-properties": "^7.18.6", "@babel/plugin-transform-spread": "^7.20.7", "@babel/plugin-transform-sticky-regex": "^7.18.6", "@babel/plugin-transform-template-literals": "^7.18.9", "@babel/plugin-transform-typeof-symbol": "^7.18.9", - "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-escapes": "^7.21.5", "@babel/plugin-transform-unicode-regex": "^7.18.6", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.21.4", + "@babel/types": "^7.21.5", "babel-plugin-polyfill-corejs2": "^0.3.3", "babel-plugin-polyfill-corejs3": "^0.6.0", "babel-plugin-polyfill-regenerator": "^0.4.1", @@ -1827,15 +1830,15 @@ } }, "node_modules/@babel/preset-typescript": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.21.4.tgz", - "integrity": "sha512-sMLNWY37TCdRH/bJ6ZeeOH1nPuanED7Ai9Y/vH31IPqalioJ6ZNFUWONsakhv4r4n+I6gm5lmoE0olkgib/j/A==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.21.5.tgz", + "integrity": "sha512-iqe3sETat5EOrORXiQ6rWfoOg2y68Cs75B9wNxdPW4kixJxh7aXQE1KPdWLDniC24T/6dSnguF33W9j/ZZQcmA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-plugin-utils": "^7.21.5", "@babel/helper-validator-option": "^7.21.0", "@babel/plugin-syntax-jsx": "^7.21.4", - "@babel/plugin-transform-modules-commonjs": "^7.21.2", + "@babel/plugin-transform-modules-commonjs": "^7.21.5", "@babel/plugin-transform-typescript": "^7.21.3" }, "engines": { @@ -1872,11 +1875,10 @@ "license": "MIT" }, "node_modules/@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.5.tgz", + "integrity": "sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==", "dev": true, - "license": "MIT", "dependencies": { "regenerator-runtime": "^0.13.11" }, @@ -1971,15 +1973,14 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.1", + "espree": "^9.5.2", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -1995,11 +1996,10 @@ } }, "node_modules/@eslint/js": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.38.0.tgz", - "integrity": "sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==", + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz", + "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==", "dev": true, - "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -2164,23 +2164,16 @@ "dev": true }, "node_modules/@types/async": { - "version": "3.2.18", - "resolved": "https://registry.npmjs.org/@types/async/-/async-3.2.18.tgz", - "integrity": "sha512-/IsuXp3B9R//uRLi40VlIYoMp7OzhkunPe2fDu7jGfQXI9y3CDCx6FC4juRLSqrpmLst3vgsiK536AAGJFl4Ww==", - "dev": true - }, - "node_modules/@types/browser-or-node": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@types/browser-or-node/-/browser-or-node-1.3.0.tgz", - "integrity": "sha512-MVetr65IR7RdJbUxVHsaPFaXAO8fi89zv1g8L/mHygh1Q7xnnK02XZLwfMh57FOpTO6gtnagoPMQ/UOFfctXRQ==", + "version": "3.2.20", + "resolved": "https://registry.npmjs.org/@types/async/-/async-3.2.20.tgz", + "integrity": "sha512-6jSBQQugzyX1aWto0CbvOnmxrU9tMoXfA9gc4IrLEtvr3dTwSg5GLGoWiZnGLI6UG/kqpB3JOQKQrqnhUWGKQA==", "dev": true }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/json5": { "version": "0.0.29", @@ -2189,11 +2182,10 @@ "dev": true }, "node_modules/@types/lodash": { - "version": "4.14.192", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.192.tgz", - "integrity": "sha512-km+Vyn3BYm5ytMO13k9KTp27O75rbQ0NFw+U//g+PX7VZyjCioXaRFisqSIJRECljcTv73G3i6BpglNGHgUQ5A==", - "dev": true, - "license": "MIT" + "version": "4.14.194", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.194.tgz", + "integrity": "sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==", + "dev": true }, "node_modules/@types/mime-types": { "version": "2.1.1", @@ -2202,11 +2194,10 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.15.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", - "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==", - "dev": true, - "license": "MIT" + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.0.tgz", + "integrity": "sha512-O+z53uwx64xY7D6roOi4+jApDGFg0qn6WHcxe5QeqjMaTezBO/mxdfFXIVAVVyNWKx84OmPB3L8kbVYOTeN34A==", + "dev": true }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -2218,8 +2209,7 @@ "version": "7.3.13", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/xml": { "version": "1.0.8", @@ -2240,16 +2230,15 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.57.1.tgz", - "integrity": "sha512-1MeobQkQ9tztuleT3v72XmY0XuKXVXusAhryoLuU5YZ+mXoYKZP9SQ7Flulh1NX4DTjpGTc2b/eMu4u7M7dhnQ==", + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.2.tgz", + "integrity": "sha512-yVrXupeHjRxLDcPKL10sGQ/QlVrA8J5IYOEWVqk0lJaSZP7X5DfnP7Ns3cc74/blmbipQ1htFNVGsHX6wsYm0A==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.57.1", - "@typescript-eslint/type-utils": "5.57.1", - "@typescript-eslint/utils": "5.57.1", + "@typescript-eslint/scope-manager": "5.59.2", + "@typescript-eslint/type-utils": "5.59.2", + "@typescript-eslint/utils": "5.59.2", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", @@ -2311,15 +2300,14 @@ "license": "ISC" }, "node_modules/@typescript-eslint/parser": { - "version": "5.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.57.1.tgz", - "integrity": "sha512-hlA0BLeVSA/wBPKdPGxoVr9Pp6GutGoY380FEhbVi0Ph4WNe8kLvqIRx76RSQt1lynZKfrXKs0/XeEk4zZycuA==", + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.2.tgz", + "integrity": "sha512-uq0sKyw6ao1iFOZZGk9F8Nro/8+gfB5ezl1cA06SrqbgJAt0SRoFhb9pXaHvkrxUpZaoLxt8KlovHNk8Gp6/HQ==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "5.57.1", - "@typescript-eslint/types": "5.57.1", - "@typescript-eslint/typescript-estree": "5.57.1", + "@typescript-eslint/scope-manager": "5.59.2", + "@typescript-eslint/types": "5.59.2", + "@typescript-eslint/typescript-estree": "5.59.2", "debug": "^4.3.4" }, "engines": { @@ -2339,14 +2327,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.57.1.tgz", - "integrity": "sha512-N/RrBwEUKMIYxSKl0oDK5sFVHd6VI7p9K5MyUlVYAY6dyNb/wHUqndkTd3XhpGlXgnQsBkRZuu4f9kAHghvgPw==", + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.2.tgz", + "integrity": "sha512-dB1v7ROySwQWKqQ8rEWcdbTsFjh2G0vn8KUyvTXdPoyzSL6lLGkiXEV5CvpJsEe9xIdKV+8Zqb7wif2issoOFA==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.57.1", - "@typescript-eslint/visitor-keys": "5.57.1" + "@typescript-eslint/types": "5.59.2", + "@typescript-eslint/visitor-keys": "5.59.2" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2357,14 +2344,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.57.1.tgz", - "integrity": "sha512-/RIPQyx60Pt6ga86hKXesXkJ2WOS4UemFrmmq/7eOyiYjYv/MUSHPlkhU6k9T9W1ytnTJueqASW+wOmW4KrViw==", + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz", + "integrity": "sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "5.57.1", - "@typescript-eslint/utils": "5.57.1", + "@typescript-eslint/typescript-estree": "5.59.2", + "@typescript-eslint/utils": "5.59.2", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -2385,11 +2371,10 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.57.1.tgz", - "integrity": "sha512-bSs4LOgyV3bJ08F5RDqO2KXqg3WAdwHCu06zOqcQ6vqbTJizyBhuh1o1ImC69X4bV2g1OJxbH71PJqiO7Y1RuA==", + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.2.tgz", + "integrity": "sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w==", "dev": true, - "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -2399,14 +2384,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.1.tgz", - "integrity": "sha512-A2MZqD8gNT0qHKbk2wRspg7cHbCDCk2tcqt6ScCFLr5Ru8cn+TCfM786DjPhqwseiS+PrYwcXht5ztpEQ6TFTw==", + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz", + "integrity": "sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "5.57.1", - "@typescript-eslint/visitor-keys": "5.57.1", + "@typescript-eslint/types": "5.59.2", + "@typescript-eslint/visitor-keys": "5.59.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2431,7 +2415,6 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -2440,11 +2423,10 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -2459,22 +2441,20 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "5.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.57.1.tgz", - "integrity": "sha512-kN6vzzf9NkEtawECqze6v99LtmDiUJCVpvieTFA1uL7/jDghiJGubGZ5csicYHU1Xoqb3oH/R5cN5df6W41Nfg==", + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.2.tgz", + "integrity": "sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.57.1", - "@typescript-eslint/types": "5.57.1", - "@typescript-eslint/typescript-estree": "5.57.1", + "@typescript-eslint/scope-manager": "5.59.2", + "@typescript-eslint/types": "5.59.2", + "@typescript-eslint/typescript-estree": "5.59.2", "eslint-scope": "^5.1.1", "semver": "^7.3.7" }, @@ -2489,36 +2469,11 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -2527,11 +2482,10 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -2546,17 +2500,15 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.1.tgz", - "integrity": "sha512-RjQrAniDU0CEk5r7iphkm731zKlFiUjvcBS2yHAg8WWqFMCaCrD0rKEVOMUyMMcbGPZ0bPp56srkGWrgfZqLRA==", + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz", + "integrity": "sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.57.1", + "@typescript-eslint/types": "5.59.2", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -2567,17 +2519,10 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true, - "license": "ISC" - }, "node_modules/@upleveled/babel-plugin-remove-node-prefix": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@upleveled/babel-plugin-remove-node-prefix/-/babel-plugin-remove-node-prefix-1.0.4.tgz", - "integrity": "sha512-EBiMQNjGgDWhe/BcDRbb1R4q4SqS9bMH+NDFZMVMk1XrEHUr4Q5kMKZYDtj79y5QSASYCMQ29dLk9SvCv6haVQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@upleveled/babel-plugin-remove-node-prefix/-/babel-plugin-remove-node-prefix-1.0.5.tgz", + "integrity": "sha512-fBej/v/GHClDJ3H6vgUQOFeH+4dFUrcFJbu9mfJFratnzEBebrgYxPBXv3ssaArTt9HhvgsTVqemeswTum6b2Q==", "dev": true, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -2595,7 +2540,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -2608,7 +2552,6 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -2631,7 +2574,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2740,7 +2682,6 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -2781,6 +2722,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -2942,10 +2889,9 @@ } }, "node_modules/browser-or-node": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-1.3.0.tgz", - "integrity": "sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg==", - "license": "MIT" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-2.1.1.tgz", + "integrity": "sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==" }, "node_modules/browser-stdout": { "version": "1.3.1", @@ -3029,7 +2975,6 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -3477,6 +3422,16 @@ "node": ">=0.4.0" } }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, "node_modules/diff": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", @@ -3676,16 +3631,15 @@ } }, "node_modules/eslint": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.38.0.tgz", - "integrity": "sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==", + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz", + "integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.38.0", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.40.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -3695,9 +3649,9 @@ "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -3909,36 +3863,36 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "46.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-46.0.0.tgz", - "integrity": "sha512-j07WkC+PFZwk8J33LYp6JMoHa1lXc1u6R45pbSAipjpfpb7KIGr17VE2D685zCxR5VL4cjrl65kTJflziQWMDA==", + "version": "47.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-47.0.0.tgz", + "integrity": "sha512-ivB3bKk7fDIeWOUmmMm9o3Ax9zbMz1Bsza/R2qm46ufw4T6VBFBaJIR1uN3pCKSmSXm8/9Nri8V+iUut1NhQGA==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.19.1", - "@eslint-community/eslint-utils": "^4.1.2", - "ci-info": "^3.6.1", + "@eslint-community/eslint-utils": "^4.4.0", + "ci-info": "^3.8.0", "clean-regexp": "^1.0.0", - "esquery": "^1.4.0", + "esquery": "^1.5.0", "indent-string": "^4.0.0", - "is-builtin-module": "^3.2.0", + "is-builtin-module": "^3.2.1", "jsesc": "^3.0.2", "lodash": "^4.17.21", "pluralize": "^8.0.0", "read-pkg-up": "^7.0.1", "regexp-tree": "^0.1.24", - "regjsparser": "^0.9.1", + "regjsparser": "^0.10.0", "safe-regex": "^2.1.1", "semver": "^7.3.8", "strip-indent": "^3.0.0" }, "engines": { - "node": ">=14.18" + "node": ">=16" }, "funding": { "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" }, "peerDependencies": { - "eslint": ">=8.28.0" + "eslint": ">=8.38.0" } }, "node_modules/eslint-plugin-unicorn/node_modules/jsesc": { @@ -3965,6 +3919,27 @@ "node": ">=10" } }, + "node_modules/eslint-plugin-unicorn/node_modules/regjsparser": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.10.0.tgz", + "integrity": "sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, "node_modules/eslint-plugin-unicorn/node_modules/semver": { "version": "7.4.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz", @@ -4017,25 +3992,48 @@ } }, "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "estraverse": "^4.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", "dev": true, - "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -4057,15 +4055,14 @@ } }, "node_modules/espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -4092,7 +4089,6 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -4147,8 +4143,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fast-glob": { "version": "3.2.12", @@ -4171,8 +4166,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fast-safe-stringify": { "version": "2.1.1", @@ -4182,19 +4176,24 @@ "license": "MIT" }, "node_modules/fast-xml-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.0.tgz", - "integrity": "sha512-+zVQv4aVTO+o8oRUyRL7PjgeVo1J6oP8Cw2+a8UTZQcj5V0yUK5T63gTN0ldgiHDPghUjKc4OpT6SwMTwnOQug==", - "license": "MIT", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.2.tgz", + "integrity": "sha512-DLzIPtQqmvmdq3VUKR7T6omPK/VCRNqgFlGtbESfyhcH2R4I8EzK1/K6E8PkRCK2EabWrUHK32NjYRbEFnnz0Q==", + "funding": [ + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + }, + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], "dependencies": { "strnum": "^1.0.5" }, "bin": { "fxparser": "src/cli/cli.js" - }, - "funding": { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" } }, "node_modules/fastq": { @@ -4329,9 +4328,9 @@ } }, "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, "dependencies": { "asynckit": "^0.4.0", @@ -4343,11 +4342,16 @@ } }, "node_modules/formidable": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", - "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==", - "deprecated": "Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", + "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", "dev": true, + "dependencies": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + }, "funding": { "url": "https://ko-fi.com/tunnckoCore/commissions" } @@ -4525,7 +4529,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, - "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -4562,7 +4565,6 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, - "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -4609,16 +4611,6 @@ "dev": true, "license": "MIT" }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.x" - } - }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -4711,6 +4703,15 @@ "he": "bin/he" } }, + "node_modules/hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -4756,7 +4757,6 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, - "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -5279,8 +5279,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -5354,9 +5353,9 @@ "dev": true }, "node_modules/lint-staged": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.2.1.tgz", - "integrity": "sha512-8gfzinVXoPfga5Dz/ZOn8I2GOhf81Wvs+KwbEXQn/oWZAvCVS2PivrXfVbFJc93zD16uC0neS47RXHIjXKYZQw==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.2.2.tgz", + "integrity": "sha512-71gSwXKy649VrSU09s10uAT0rWCcY3aewhMaHyl2N84oBk4Xs9HgxvUp3AYu+bNsK4NrOYYxvSgg7FyGJ+jGcA==", "dev": true, "dependencies": { "chalk": "5.2.0", @@ -5371,7 +5370,7 @@ "object-inspect": "^1.12.3", "pidtree": "^0.6.0", "string-argv": "^0.3.1", - "yaml": "^2.2.1" + "yaml": "^2.2.2" }, "bin": { "lint-staged": "bin/lint-staged.js" @@ -5771,43 +5770,39 @@ } }, "node_modules/mocha": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", - "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", "dev": true, - "license": "MIT", "dependencies": { - "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", "chokidar": "3.5.3", - "debug": "4.3.3", + "debug": "4.3.4", "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", "glob": "7.2.0", - "growl": "1.10.5", "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", - "minimatch": "4.2.1", + "minimatch": "5.0.1", "ms": "2.1.3", - "nanoid": "3.3.1", + "nanoid": "3.3.3", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.2.0", + "workerpool": "6.2.1", "yargs": "16.2.0", "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" }, "bin": { "_mocha": "bin/_mocha", - "mocha": "bin/mocha" + "mocha": "bin/mocha.js" }, "engines": { - "node": ">= 12.0.0" + "node": ">= 14.0.0" }, "funding": { "type": "opencollective", @@ -5831,31 +5826,6 @@ "node": ">=6" } }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "license": "MIT" - }, "node_modules/mocha/node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -5891,18 +5861,26 @@ } }, "node_modules/mocha/node_modules/minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", "dev": true, - "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { "node": ">=10" } }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/mocha/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -5918,11 +5896,10 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", "dev": true, - "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -5945,11 +5922,10 @@ "license": "MIT" }, "node_modules/nock": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/nock/-/nock-13.3.0.tgz", - "integrity": "sha512-HHqYQ6mBeiMc+N038w8LkMpDCRquCHWeNmN3v6645P3NhN2+qXOBqvPqo7Rt1VyCMzKhJ733wZqw5B7cQVFNPg==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.3.1.tgz", + "integrity": "sha512-vHnopocZuI93p2ccivFyGuUfzjq2fxNyNurp7816mlT5V5HF4SzXu8lvLrVzBbNqzs+ODooZ6OksuSUNM7Njkw==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.1.0", "json-stringify-safe": "^5.0.1", @@ -6207,7 +6183,6 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, - "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -6433,11 +6408,10 @@ } }, "node_modules/prettier": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", - "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, - "license": "MIT", "bin": { "prettier": "bin-prettier.js" }, @@ -6458,6 +6432,15 @@ "node": ">= 8" } }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { "version": "6.11.1", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.1.tgz", @@ -6674,15 +6657,13 @@ "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/regenerator-transform": { "version": "0.15.1", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.4" } @@ -6786,7 +6767,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -7012,7 +6992,6 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -7308,26 +7287,24 @@ "license": "MIT" }, "node_modules/superagent": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-5.3.1.tgz", - "integrity": "sha512-wjJ/MoTid2/RuGCOFtlacyGNxN9QLMgcpYLDQlWFIhhdJ93kNscFonGvrpAHSCVjRVj++DGCglocF7Aej1KHvQ==", - "deprecated": "Please upgrade to v7.0.2+ of superagent. We have fixed numerous issues with streams, form-data, attach(), filesystem errors not bubbling up (ENOENT on attach()), and all tests are now passing. See the releases tab for more information at .", + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.9.tgz", + "integrity": "sha512-4C7Bh5pyHTvU33KpZgwrNKh/VQnvgtCSqPRfJAUdmrtSYePVzVg4E4OzsrbkhJj9O7SO6Bnv75K/F8XVZT8YHA==", "dev": true, "dependencies": { "component-emitter": "^1.3.0", - "cookiejar": "^2.1.2", - "debug": "^4.1.1", - "fast-safe-stringify": "^2.0.7", - "form-data": "^3.0.0", - "formidable": "^1.2.2", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.2", "methods": "^1.1.2", - "mime": "^2.4.6", - "qs": "^6.9.4", - "readable-stream": "^3.6.0", - "semver": "^7.3.2" + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" }, "engines": { - "node": ">= 7.0.0" + "node": ">=6.4.0 <13 || >=14" } }, "node_modules/superagent/node_modules/lru-cache": { @@ -7441,13 +7418,11 @@ "license": "MIT" }, "node_modules/through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "license": "MIT", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" + "readable-stream": "3" } }, "node_modules/tiny-glob": { @@ -7568,7 +7543,6 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -7695,21 +7669,10 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } }, - "node_modules/uri-js/node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/util": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", @@ -7823,11 +7786,10 @@ } }, "node_modules/workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", - "dev": true, - "license": "Apache-2.0" + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true }, "node_modules/wrap-ansi": { "version": "7.0.0", diff --git a/package.json b/package.json index 3025bbf7..b3fd3002 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "S3 Compatible Cloud Storage client", "main": "./dist/main/minio.js", "module": "./dist/esm/minio.mjs", - "types": "./types/minio.d.ts", + "types": "./dist/main/minio.d.ts", "scripts": { "prepare": "husky install", "tsc": "tsc", @@ -13,7 +13,6 @@ "test": "mocha", "lint": "eslint --ext js,mjs,cjs,ts ./", "lint-fix": "eslint --ext js,mjs,cjs,ts ./ --fix", - "prepublish": "", "prepublishOnly": "npm test && npm run build", "functional": "mocha tests/functional/functional-tests.js", "format": "prettier -w .", @@ -22,15 +21,17 @@ }, "exports": { ".": { - "types": "./types/minio.d.ts", + "types": "./dist/main/minio.d.ts", "require": "./dist/main/minio.js", "default": "./dist/esm/minio.mjs" }, + "./dist/main/internal/*": null, "./dist/main/*": { "types": "./dist/main/*", "require": "./dist/main/*", "default": null }, + "./dist/esm/internal/*": null, "./dist/esm/*": { "types": "./dist/esm/*", "import": "./dist/esm/*", @@ -70,11 +71,10 @@ }, "author": { "name": "MinIO, Inc.", - "email": "", "url": "https://min.io" }, "engines": { - "node": ">8 <=19" + "node": "^16 || ^18 || >=20" }, "license": "Apache-2.0", "bugs": { @@ -83,59 +83,58 @@ }, "homepage": "https://github.com/minio/minio-js#readme", "dependencies": { - "async": "^3.1.0", - "block-stream2": "^2.0.0", - "browser-or-node": "^1.3.0", + "async": "^3.2.4", + "block-stream2": "^2.1.0", + "browser-or-node": "^2.1.1", "buffer-crc32": "^0.2.13", - "fast-xml-parser": "^4.1.3", + "fast-xml-parser": "^4.2.2", "ipaddr.js": "^2.0.1", "json-stream": "^1.0.0", "lodash": "^4.17.21", - "mime-types": "^2.1.14", - "mkdirp": "^0.5.1", - "query-string": "^7.1.1", - "through2": "^3.0.1", + "mime-types": "^2.1.35", + "mkdirp": "^0.5.6", + "query-string": "^7.1.3", + "through2": "^4.0.2", "web-encoding": "^1.1.5", - "xml": "^1.0.0", + "xml": "^1.0.1", "xml2js": "^0.5.0" }, "devDependencies": { - "@babel/core": "^7.12.10", + "@babel/core": "^7.21.8", "@babel/plugin-transform-modules-commonjs": "^7.21.5", - "@babel/preset-env": "^7.12.10", - "@babel/preset-typescript": "^7.21.4", + "@babel/preset-env": "^7.21.5", + "@babel/preset-typescript": "^7.21.5", "@babel/register": "^7.21.0", "@nodelib/fs.walk": "^1.2.8", - "@types/async": "^3.2.18", - "@types/browser-or-node": "^1.3.0", - "@types/lodash": "^4.14.192", + "@types/async": "^3.2.20", + "@types/lodash": "^4.14.194", "@types/mime-types": "^2.1.1", - "@types/node": "^18.15.11", + "@types/node": "^20.1.0", "@types/xml": "^1.0.8", "@types/xml2js": "^0.4.11", - "@typescript-eslint/eslint-plugin": "^5.57.1", - "@typescript-eslint/parser": "^5.57.1", - "@upleveled/babel-plugin-remove-node-prefix": "^1.0.4", + "@typescript-eslint/eslint-plugin": "^5.59.2", + "@typescript-eslint/parser": "^5.59.2", + "@upleveled/babel-plugin-remove-node-prefix": "^1.0.5", "babel-plugin-replace-import-extension": "^1.1.3", "babel-plugin-transform-replace-expressions": "^0.2.0", - "chai": "^4.2.0", + "chai": "^4.3.7", "dotenv": "^16.0.3", - "eslint": "^8.37.0", + "eslint": "^8.40.0", "eslint-config-prettier": "^8.8.0", "eslint-import-resolver-typescript": "^3.5.5", "eslint-plugin-import": "^2.27.5", "eslint-plugin-simple-import-sort": "^10.0.0", - "eslint-plugin-unicorn": "^46.0.0", + "eslint-plugin-unicorn": "^47.0.0", "eslint-plugin-unused-imports": "^2.0.0", "husky": "^8.0.3", - "lint-staged": "^13.2.1", - "mocha": "^9.2.0", - "mocha-steps": "^1.1.0", - "nock": "^13.2.2", - "prettier": "^2.8.7", - "source-map-support": "^0.5.13", - "split-file": "^2.2.2", - "superagent": "^5.1.0", + "lint-staged": "^13.2.2", + "mocha": "^10.2.0", + "mocha-steps": "^1.3.0", + "nock": "^13.3.1", + "prettier": "^2.8.8", + "source-map-support": "^0.5.21", + "split-file": "^2.3.0", + "superagent": "^8.0.1", "typescript": "^5.0.4", "uuid": "^9.0.0" }, diff --git a/src/AssumeRoleProvider.js b/src/AssumeRoleProvider.js index 25411f85..cc01e68d 100644 --- a/src/AssumeRoleProvider.js +++ b/src/AssumeRoleProvider.js @@ -4,8 +4,8 @@ import { URL, URLSearchParams } from 'node:url' import { CredentialProvider } from './CredentialProvider.js' import { Credentials } from './Credentials.js' -import { makeDateLong, parseXml, toSha256 } from './helpers.js' -import { signV4ByServiceName } from './signing.js' +import { makeDateLong, parseXml, toSha256 } from './internal/helper.ts' +import { signV4ByServiceName } from './signing.ts' export class AssumeRoleProvider extends CredentialProvider { constructor({ @@ -116,7 +116,15 @@ export class AssumeRoleProvider extends CredentialProvider { agent: this.transportAgent, } - const authorization = signV4ByServiceName(requestOptions, this.accessKey, this.secretKey, this.region, date, 'sts') + const authorization = signV4ByServiceName( + requestOptions, + this.accessKey, + this.secretKey, + this.region, + date, + contentSha256, + 'sts', + ) requestOptions.headers.authorization = authorization return { diff --git a/src/base-error.ts b/src/base-error.ts deleted file mode 100644 index d3947b6d..00000000 --- a/src/base-error.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * MinIO Javascript Library for Amazon S3 Compatible Cloud Storage, (C) 2015 MinIO, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/// - -/** - * @internal - */ -export class ExtendableError extends Error { - constructor(message?: string, opt?: ErrorOptions) { - // error Option {cause?: unknown} is a 'nice to have', - // don't use it internally - super(message, opt) - // set error name, otherwise it's always 'Error' - this.name = this.constructor.name - } -} diff --git a/src/errors.ts b/src/errors.ts index fa6f62fb..3bdab3b7 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -14,7 +14,17 @@ * limitations under the License. */ -import { ExtendableError } from './base-error.ts' +/// + +class ExtendableError extends Error { + constructor(message?: string, opt?: ErrorOptions) { + // error Option {cause?: unknown} is a 'nice to have', + // don't use it internally + super(message, opt) + // set error name, otherwise it's always 'Error' + this.name = this.constructor.name + } +} /** * AnonymousRequestError is generated for anonymous keys on specific diff --git a/src/extensions.js b/src/extensions.js index 5e04a930..70caa471 100644 --- a/src/extensions.js +++ b/src/extensions.js @@ -17,7 +17,15 @@ import * as Stream from 'node:stream' import * as errors from './errors.ts' -import { isBoolean, isNumber, isString, isValidBucketName, isValidPrefix, pipesetup, uriEscape } from './helpers.js' +import { + isBoolean, + isNumber, + isString, + isValidBucketName, + isValidPrefix, + pipesetup, + uriEscape, +} from './internal/helper.ts' import * as transformers from './transformers.js' export class extensions { diff --git a/src/helpers.js b/src/helpers.js deleted file mode 100644 index 18091089..00000000 --- a/src/helpers.js +++ /dev/null @@ -1,822 +0,0 @@ -/* - * MinIO Javascript Library for Amazon S3 Compatible Cloud Storage, (C) 2015 MinIO, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as Crypto from 'node:crypto' -import * as fs from 'node:fs' -import * as path from 'node:path' -import * as stream from 'node:stream' - -import { isBrowser } from 'browser-or-node' -import { XMLParser } from 'fast-xml-parser' -import ipaddr from 'ipaddr.js' -import _ from 'lodash' -import mime from 'mime-types' -import querystring from 'query-string' - -import * as errors from './errors.ts' - -const fxp = new XMLParser() - -// Returns a wrapper function that will promisify a given callback function. -// It will preserve 'this'. -export function promisify(fn) { - return function () { - // If the last argument is a function, assume its the callback. - let callback = arguments[arguments.length - 1] - - // If the callback is given, don't promisify, just pass straight in. - if (typeof callback === 'function') { - return fn.apply(this, arguments) - } - - // Otherwise, create a new set of arguments, and wrap - // it in a promise. - let args = [...arguments] - - return new Promise((resolve, reject) => { - // Add the callback function. - args.push((err, value) => { - if (err) { - return reject(err) - } - - resolve(value) - }) - - // Call the function with our special adaptor callback added. - fn.apply(this, args) - }) - } -} - -// All characters in string which are NOT unreserved should be percent encoded. -// Unreserved characers are : ALPHA / DIGIT / "-" / "." / "_" / "~" -// Reference https://tools.ietf.org/html/rfc3986#section-2.2 -export function uriEscape(string) { - return string.split('').reduce((acc, elem) => { - let buf = Buffer.from(elem) - if (buf.length === 1) { - // length 1 indicates that elem is not a unicode character. - // Check if it is an unreserved characer. - if ( - ('A' <= elem && elem <= 'Z') || - ('a' <= elem && elem <= 'z') || - ('0' <= elem && elem <= '9') || - elem === '_' || - elem === '.' || - elem === '~' || - elem === '-' - ) { - // Unreserved characer should not be encoded. - acc = acc + elem - return acc - } - } - // elem needs encoding - i.e elem should be encoded if it's not unreserved - // character or if it's a unicode character. - for (var i = 0; i < buf.length; i++) { - acc = acc + '%' + buf[i].toString(16).toUpperCase() - } - return acc - }, '') -} - -export function uriResourceEscape(string) { - return uriEscape(string).replace(/%2F/g, '/') -} - -export function getScope(region, date, serviceName = 's3') { - return `${makeDateShort(date)}/${region}/${serviceName}/aws4_request` -} - -// isAmazonEndpoint - true if endpoint is 's3.amazonaws.com' or 's3.cn-north-1.amazonaws.com.cn' -export function isAmazonEndpoint(endpoint) { - return endpoint === 's3.amazonaws.com' || endpoint === 's3.cn-north-1.amazonaws.com.cn' -} - -// isVirtualHostStyle - verify if bucket name is support with virtual -// hosts. bucketNames with periods should be always treated as path -// style if the protocol is 'https:', this is due to SSL wildcard -// limitation. For all other buckets and Amazon S3 endpoint we will -// default to virtual host style. -export function isVirtualHostStyle(endpoint, protocol, bucket, pathStyle) { - if (protocol === 'https:' && bucket.indexOf('.') > -1) { - return false - } - return isAmazonEndpoint(endpoint) || !pathStyle -} - -export function isValidIP(ip) { - return ipaddr.isValid(ip) -} - -// isValidEndpoint - true if endpoint is valid domain. -export function isValidEndpoint(endpoint) { - return isValidDomain(endpoint) || isValidIP(endpoint) -} - -// isValidDomain - true if input host is a valid domain. -export function isValidDomain(host) { - if (!isString(host)) { - return false - } - // See RFC 1035, RFC 3696. - if (host.length === 0 || host.length > 255) { - return false - } - // Host cannot start or end with a '-' - if (host[0] === '-' || host.slice(-1) === '-') { - return false - } - // Host cannot start or end with a '_' - if (host[0] === '_' || host.slice(-1) === '_') { - return false - } - // Host cannot start with a '.' - if (host[0] === '.') { - return false - } - var alphaNumerics = '`~!@#$%^&*()+={}[]|\\"\';:> -1) { - return false - } - } - // No need to regexp match, since the list is non-exhaustive. - // We let it be valid and fail later. - return true -} - -// Probes contentType using file extensions. -// For example: probeContentType('file.png') returns 'image/png'. -export function probeContentType(path) { - let contentType = mime.lookup(path) - if (!contentType) { - contentType = 'application/octet-stream' - } - return contentType -} - -// isValidPort - is input port valid. -export function isValidPort(port) { - // verify if port is a number. - if (!isNumber(port)) { - return false - } - // port cannot be negative. - if (port < 0) { - return false - } - // port '0' is valid and special case return true. - if (port === 0) { - return true - } - var min_port = 1 - var max_port = 65535 - // Verify if port is in range. - return port >= min_port && port <= max_port -} - -export function isValidBucketName(bucket) { - if (!isString(bucket)) { - return false - } - - // bucket length should be less than and no more than 63 - // characters long. - if (bucket.length < 3 || bucket.length > 63) { - return false - } - // bucket with successive periods is invalid. - if (bucket.indexOf('..') > -1) { - return false - } - // bucket cannot have ip address style. - if (bucket.match(/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)) { - return false - } - // bucket should begin with alphabet/number and end with alphabet/number, - // with alphabet/number/.- in the middle. - if (bucket.match(/^[a-z0-9][a-z0-9.-]+[a-z0-9]$/)) { - return true - } - return false -} - -// check if objectName is a valid object name -export function isValidObjectName(objectName) { - if (!isValidPrefix(objectName)) { - return false - } - if (objectName.length === 0) { - return false - } - return true -} - -// check if prefix is valid -export function isValidPrefix(prefix) { - if (!isString(prefix)) { - return false - } - if (prefix.length > 1024) { - return false - } - return true -} - -// check if typeof arg number -export function isNumber(arg) { - return typeof arg === 'number' -} - -// check if typeof arg function -export function isFunction(arg) { - return typeof arg === 'function' -} - -// check if typeof arg string -export function isString(arg) { - return typeof arg === 'string' -} - -// check if typeof arg object -export function isObject(arg) { - return typeof arg === 'object' && arg !== null -} - -// check if object is readable stream -export function isReadableStream(arg) { - return isObject(arg) && isFunction(arg._read) -} - -// check if arg is boolean -export function isBoolean(arg) { - return typeof arg === 'boolean' -} - -// check if arg is array -export function isArray(arg) { - return Array.isArray(arg) -} - -// check if arg is a valid date -export function isValidDate(arg) { - return arg instanceof Date && !isNaN(arg) -} - -// Create a Date string with format: -// 'YYYYMMDDTHHmmss' + Z -export function makeDateLong(date) { - date = date || new Date() - - // Gives format like: '2017-08-07T16:28:59.889Z' - date = date.toISOString() - - return date.slice(0, 4) + date.slice(5, 7) + date.slice(8, 13) + date.slice(14, 16) + date.slice(17, 19) + 'Z' -} - -// Create a Date string with format: -// 'YYYYMMDD' -export function makeDateShort(date) { - date = date || new Date() - - // Gives format like: '2017-08-07T16:28:59.889Z' - date = date.toISOString() - - return date.slice(0, 4) + date.slice(5, 7) + date.slice(8, 10) -} - -// pipesetup sets up pipe() from left to right os streams array -// pipesetup will also make sure that error emitted at any of the upstream Stream -// will be emitted at the last stream. This makes error handling simple -export function pipesetup(...streams) { - return streams.reduce((src, dst) => { - src.on('error', (err) => dst.emit('error', err)) - return src.pipe(dst) - }) -} - -// return a Readable stream that emits data -export function readableStream(data) { - var s = new stream.Readable() - s._read = () => {} - s.push(data) - s.push(null) - return s -} - -// Process metadata to insert appropriate value to `content-type` attribute -export function insertContentType(metaData, filePath) { - // check if content-type attribute present in metaData - for (var key in metaData) { - if (key.toLowerCase() === 'content-type') { - return metaData - } - } - // if `content-type` attribute is not present in metadata, - // then infer it from the extension in filePath - var newMetadata = Object.assign({}, metaData) - newMetadata['content-type'] = probeContentType(filePath) - return newMetadata -} - -// Function prepends metadata with the appropriate prefix if it is not already on -export function prependXAMZMeta(metaData) { - var newMetadata = Object.assign({}, metaData) - for (var key in metaData) { - if (!isAmzHeader(key) && !isSupportedHeader(key) && !isStorageclassHeader(key)) { - newMetadata['X-Amz-Meta-' + key] = newMetadata[key] - delete newMetadata[key] - } - } - return newMetadata -} - -// Checks if it is a valid header according to the AmazonS3 API -export function isAmzHeader(key) { - var temp = key.toLowerCase() - return ( - temp.startsWith('x-amz-meta-') || - temp === 'x-amz-acl' || - temp.startsWith('x-amz-server-side-encryption-') || - temp === 'x-amz-server-side-encryption' - ) -} -// Checks if it is a supported Header -export function isSupportedHeader(key) { - var supported_headers = [ - 'content-type', - 'cache-control', - 'content-encoding', - 'content-disposition', - 'content-language', - 'x-amz-website-redirect-location', - ] - return supported_headers.indexOf(key.toLowerCase()) > -1 -} -// Checks if it is a storage header -export function isStorageclassHeader(key) { - return key.toLowerCase() === 'x-amz-storage-class' -} - -export function extractMetadata(metaData) { - var newMetadata = {} - for (var key in metaData) { - if (isSupportedHeader(key) || isStorageclassHeader(key) || isAmzHeader(key)) { - if (key.toLowerCase().startsWith('x-amz-meta-')) { - newMetadata[key.slice(11, key.length)] = metaData[key] - } else { - newMetadata[key] = metaData[key] - } - } - } - return newMetadata -} - -export function getVersionId(headers = {}) { - const versionIdValue = headers['x-amz-version-id'] - return versionIdValue || null -} - -export function getSourceVersionId(headers = {}) { - const sourceVersionId = headers['x-amz-copy-source-version-id'] - return sourceVersionId || null -} - -export function sanitizeETag(etag = '') { - var replaceChars = { '"': '', '"': '', '"': '', '"': '', '"': '' } - return etag.replace(/^("|"|")|("|"|")$/g, (m) => replaceChars[m]) -} - -export const RETENTION_MODES = { - GOVERNANCE: 'GOVERNANCE', - COMPLIANCE: 'COMPLIANCE', -} - -export const RETENTION_VALIDITY_UNITS = { - DAYS: 'Days', - YEARS: 'Years', -} - -export const LEGAL_HOLD_STATUS = { - ENABLED: 'ON', - DISABLED: 'OFF', -} - -const objectToBuffer = (payload) => { - const payloadBuf = Buffer.from(Buffer.from(payload)) - return payloadBuf -} - -export const toMd5 = (payload) => { - let payLoadBuf = objectToBuffer(payload) - // use string from browser and buffer from nodejs - // browser support is tested only against minio server - payLoadBuf = isBrowser ? payLoadBuf.toString() : payLoadBuf - return Crypto.createHash('md5').update(payLoadBuf).digest().toString('base64') -} - -export const toSha256 = (payload) => { - return Crypto.createHash('sha256').update(payload).digest('hex') -} - -// toArray returns a single element array with param being the element, -// if param is just a string, and returns 'param' back if it is an array -// So, it makes sure param is always an array -export const toArray = (param) => { - if (!Array.isArray(param)) { - return [param] - } - return param -} - -export const sanitizeObjectKey = (objectName) => { - // + symbol characters are not decoded as spaces in JS. so replace them first and decode to get the correct result. - let asStrName = (objectName ? objectName.toString() : '').replace(/\+/g, ' ') - const sanitizedName = decodeURIComponent(asStrName) - return sanitizedName -} - -export const PART_CONSTRAINTS = { - // absMinPartSize - absolute minimum part size (5 MiB) - ABS_MIN_PART_SIZE: 1024 * 1024 * 5, - // MIN_PART_SIZE - minimum part size 16MiB per object after which - MIN_PART_SIZE: 1024 * 1024 * 16, - // MAX_PARTS_COUNT - maximum number of parts for a single multipart session. - MAX_PARTS_COUNT: 10000, - // MAX_PART_SIZE - maximum part size 5GiB for a single multipart upload - // operation. - MAX_PART_SIZE: 1024 * 1024 * 1024 * 5, - // MAX_SINGLE_PUT_OBJECT_SIZE - maximum size 5GiB of object per PUT - // operation. - MAX_SINGLE_PUT_OBJECT_SIZE: 1024 * 1024 * 1024 * 5, - // MAX_MULTIPART_PUT_OBJECT_SIZE - maximum size 5TiB of object for - // Multipart operation. - MAX_MULTIPART_PUT_OBJECT_SIZE: 1024 * 1024 * 1024 * 1024 * 5, -} - -export const ENCRYPTION_TYPES = { - // SSEC represents server-side-encryption with customer provided keys - SSEC: 'SSE-C', - // KMS represents server-side-encryption with managed keys - KMS: 'KMS', -} -const GENERIC_SSE_HEADER = 'X-Amz-Server-Side-Encryption' - -const ENCRYPTION_HEADERS = { - // sseGenericHeader is the AWS SSE header used for SSE-S3 and SSE-KMS. - sseGenericHeader: GENERIC_SSE_HEADER, - // sseKmsKeyID is the AWS SSE-KMS key id. - sseKmsKeyID: GENERIC_SSE_HEADER + '-Aws-Kms-Key-Id', -} - -/** - * Return Encryption headers - * @param encConfig - * @returns an object with key value pairs that can be used in headers. - */ -function getEncryptionHeaders(encConfig) { - const encType = encConfig.type - const encHeaders = {} - if (!_.isEmpty(encType)) { - if (encType === ENCRYPTION_TYPES.SSEC) { - return { - [encHeaders[ENCRYPTION_HEADERS.sseGenericHeader]]: 'AES256', - } - } else if (encType === ENCRYPTION_TYPES.KMS) { - return { - [ENCRYPTION_HEADERS.sseGenericHeader]: encConfig.SSEAlgorithm, - [ENCRYPTION_HEADERS.sseKmsKeyID]: encConfig.KMSMasterKeyID, - } - } - } - - return encHeaders -} - -export class CopySourceOptions { - /** - * - * @param Bucket __string__ Bucket Name - * @param Object __string__ Object Name - * @param VersionID __string__ Valid versionId - * @param MatchETag __string__ Etag to match - * @param NoMatchETag __string__ Etag to exclude - * @param MatchModifiedSince __string__ Modified Date of the object/part. UTC Date in string format - * @param MatchUnmodifiedSince __string__ Modified Date of the object/part to exclude UTC Date in string format - * @param MatchRange __boolean__ true or false Object range to match - * @param Start - * @param End - * @param Encryption - */ - constructor({ - Bucket = '', - Object = '', - VersionID = '', - MatchETag = '', - NoMatchETag = '', - MatchModifiedSince = null, - MatchUnmodifiedSince = null, - MatchRange = false, - Start = 0, - End = 0, - Encryption = {}, - } = {}) { - this.Bucket = Bucket - this.Object = Object - this.VersionID = VersionID - this.MatchETag = MatchETag - this.NoMatchETag = NoMatchETag - this.MatchModifiedSince = MatchModifiedSince - this.MatchUnmodifiedSince = MatchUnmodifiedSince - this.MatchRange = MatchRange - this.Start = Start - this.End = End - this.Encryption = Encryption - } - - validate() { - if (!isValidBucketName(this.Bucket)) { - throw new errors.InvalidBucketNameError('Invalid Source bucket name: ' + this.Bucket) - } - if (!isValidObjectName(this.Object)) { - throw new errors.InvalidObjectNameError(`Invalid Source object name: ${this.Object}`) - } - if ((this.MatchRange && this.Start !== -1 && this.End !== -1 && this.Start > this.End) || this.Start < 0) { - throw new errors.InvalidObjectNameError('Source start must be non-negative, and start must be at most end.') - } else if ((this.MatchRange && !isNumber(this.Start)) || !isNumber(this.End)) { - throw new errors.InvalidObjectNameError( - 'MatchRange is specified. But Invalid Start and End values are specified. ', - ) - } - - return true - } - - getHeaders() { - let headerOptions = {} - headerOptions['x-amz-copy-source'] = encodeURI(this.Bucket + '/' + this.Object) - - if (!_.isEmpty(this.VersionID)) { - headerOptions['x-amz-copy-source'] = encodeURI(this.Bucket + '/' + this.Object) + '?versionId=' + this.VersionID - } - - if (!_.isEmpty(this.MatchETag)) { - headerOptions['x-amz-copy-source-if-match'] = this.MatchETag - } - if (!_.isEmpty(this.NoMatchETag)) { - headerOptions['x-amz-copy-source-if-none-match'] = this.NoMatchETag - } - - if (!_.isEmpty(this.MatchModifiedSince)) { - headerOptions['x-amz-copy-source-if-modified-since'] = this.MatchModifiedSince - } - if (!_.isEmpty(this.MatchUnmodifiedSince)) { - headerOptions['x-amz-copy-source-if-unmodified-since'] = this.MatchUnmodifiedSince - } - - return headerOptions - } -} - -export class CopyDestinationOptions { - /* - * @param Bucket __string__ - * @param Object __string__ Object Name for the destination (composed/copied) object defaults - * @param Encryption __object__ Encryption configuration defaults to {} - * @param UserMetadata __object__ - * @param UserTags __object__ | __string__ - * @param LegalHold __string__ ON | OFF - * @param RetainUntilDate __string__ UTC Date String - * @param Mode - */ - constructor({ - Bucket = '', - Object = '', - Encryption = null, - UserMetadata = null, - UserTags = null, - LegalHold = null, - RetainUntilDate = null, - Mode = null, // - }) { - this.Bucket = Bucket - this.Object = Object - this.Encryption = Encryption - this.UserMetadata = UserMetadata - this.UserTags = UserTags - this.LegalHold = LegalHold - this.Mode = Mode // retention mode - this.RetainUntilDate = RetainUntilDate - } - - getHeaders() { - const replaceDirective = 'REPLACE' - const headerOptions = {} - - const userTags = this.UserTags - if (!_.isEmpty(userTags)) { - headerOptions['X-Amz-Tagging-Directive'] = replaceDirective - headerOptions['X-Amz-Tagging'] = isObject(userTags) - ? querystring.stringify(userTags) - : isString(userTags) - ? userTags - : '' - } - - if (!_.isEmpty(this.Mode)) { - headerOptions['X-Amz-Object-Lock-Mode'] = this.Mode // GOVERNANCE or COMPLIANCE - } - - if (!_.isEmpty(this.RetainUntilDate)) { - headerOptions['X-Amz-Object-Lock-Retain-Until-Date'] = this.RetainUntilDate // needs to be UTC. - } - - if (!_.isEmpty(this.LegalHold)) { - headerOptions['X-Amz-Object-Lock-Legal-Hold'] = this.LegalHold // ON or OFF - } - - if (!_.isEmpty(this.UserMetadata)) { - const headerKeys = Object.keys(this.UserMetadata) - headerKeys.forEach((key) => { - headerOptions[`X-Amz-Meta-${key}`] = this.UserMetadata[key] - }) - } - - if (!_.isEmpty(this.Encryption)) { - const encryptionHeaders = getEncryptionHeaders(this.Encryption) - Object.keys(encryptionHeaders).forEach((key) => { - headerOptions[key] = encryptionHeaders[key] - }) - } - return headerOptions - } - validate() { - if (!isValidBucketName(this.Bucket)) { - throw new errors.InvalidBucketNameError('Invalid Destination bucket name: ' + this.Bucket) - } - if (!isValidObjectName(this.Object)) { - throw new errors.InvalidObjectNameError(`Invalid Destination object name: ${this.Object}`) - } - if (!_.isEmpty(this.UserMetadata) && !isObject(this.UserMetadata)) { - throw new errors.InvalidObjectNameError(`Destination UserMetadata should be an object with key value pairs`) - } - - if (!_.isEmpty(this.Mode) && ![RETENTION_MODES.GOVERNANCE, RETENTION_MODES.COMPLIANCE].includes(this.Mode)) { - throw new errors.InvalidObjectNameError( - `Invalid Mode specified for destination object it should be one of [GOVERNANCE,COMPLIANCE]`, - ) - } - - if (!_.isEmpty(this.Encryption) && _.isEmpty(this.Encryption)) { - throw new errors.InvalidObjectNameError(`Invalid Encryption configuration for destination object `) - } - return true - } -} - -export const partsRequired = (size) => { - let maxPartSize = PART_CONSTRAINTS.MAX_MULTIPART_PUT_OBJECT_SIZE / (PART_CONSTRAINTS.MAX_PARTS_COUNT - 1) - let requiredPartSize = size / maxPartSize - if (size % maxPartSize > 0) { - requiredPartSize++ - } - requiredPartSize = Math.trunc(requiredPartSize) - return requiredPartSize -} - -// calculateEvenSplits - computes splits for a source and returns -// start and end index slices. Splits happen evenly to be sure that no -// part is less than 5MiB, as that could fail the multipart request if -// it is not the last part. - -let startIndexParts = [] -let endIndexParts = [] -export function calculateEvenSplits(size, objInfo) { - if (size === 0) { - return null - } - const reqParts = partsRequired(size) - startIndexParts = new Array(reqParts) - endIndexParts = new Array(reqParts) - - let start = objInfo.Start - if (_.isEmpty(objInfo.Start) || start === -1) { - start = 0 - } - const divisorValue = Math.trunc(size / reqParts) - - const reminderValue = size % reqParts - - let nextStart = start - - for (let i = 0; i < reqParts; i++) { - let curPartSize = divisorValue - if (i < reminderValue) { - curPartSize++ - } - - const currentStart = nextStart - let currentEnd = currentStart + curPartSize - 1 - nextStart = currentEnd + 1 - - startIndexParts[i] = currentStart - endIndexParts[i] = currentEnd - } - - return { startIndex: startIndexParts, endIndex: endIndexParts, objInfo: objInfo } -} - -export function removeDirAndFiles(dirPath, removeSelf) { - if (removeSelf === undefined) { - removeSelf = true - } - try { - var files = fs.readdirSync(dirPath) - } catch (e) { - return - } - if (files.length > 0) { - for (var i = 0; i < files.length; i++) { - var filePath = path.join(dirPath, files[i]) - if (fs.statSync(filePath).isFile()) { - fs.unlinkSync(filePath) - } else { - removeDirAndFiles(filePath) - } - } - } - if (removeSelf) { - fs.rmdirSync(dirPath) - } -} - -export const parseXml = (xml) => { - let result = null - result = fxp.parse(xml) - if (result.Error) { - throw result.Error - } - - return result -} - -export class SelectResults { - constructor({ - records, // parsed data as stream - response, // original response stream - stats, // stats as xml - progress, // stats as xml - }) { - this.records = records - this.response = response - this.stats = stats - this.progress = progress - } - - setStats(stats) { - this.stats = stats - } - getStats() { - return this.stats - } - - setProgress(progress) { - this.progress = progress - } - getProgress() { - return this.progress - } - - setResponse(response) { - this.response = response - } - getResponse() { - return this.response - } - - setRecords(records) { - this.records = records - } - - getRecords() { - return this.records - } -} - -export const DEFAULT_REGION = 'us-east-1' diff --git a/src/helpers.ts b/src/helpers.ts new file mode 100644 index 00000000..cfbd4f5d --- /dev/null +++ b/src/helpers.ts @@ -0,0 +1,328 @@ +import * as fs from 'node:fs' +import * as path from 'node:path' + +import * as querystring from 'query-string' + +import * as errors from './errors.ts' +import { + getEncryptionHeaders, + isEmpty, + isEmptyObject, + isNumber, + isObject, + isString, + isValidBucketName, + isValidObjectName, +} from './internal/helper.ts' +import type { Encryption, ObjectMetaData, RequestHeaders } from './internal/type.ts' +import { RETENTION_MODES } from './internal/type.ts' + +export { ENCRYPTION_TYPES, LEGAL_HOLD_STATUS, RETENTION_MODES, RETENTION_VALIDITY_UNITS } from './internal/type.ts' + +export const DEFAULT_REGION = 'us-east-1' + +export interface ICopySourceOptions { + Bucket: string + Object: string + /** + * Valid versionId + */ + VersionID?: string + /** + * Etag to match + */ + MatchETag?: string + /** + * Etag to exclude + */ + NoMatchETag?: string + /** + * Modified Date of the object/part. UTC Date in string format + */ + MatchModifiedSince?: string | null + /** + * Modified Date of the object/part to exclude UTC Date in string format + */ + MatchUnmodifiedSince?: string | null + /** + * true or false Object range to match + */ + MatchRange?: boolean + Start?: number + End?: number + Encryption?: Encryption +} + +export class CopySourceOptions { + public readonly Bucket: string + public readonly Object: string + public readonly VersionID: string + public MatchETag: string + private readonly NoMatchETag: string + private readonly MatchModifiedSince: string | null + private readonly MatchUnmodifiedSince: string | null + public readonly MatchRange: boolean + public readonly Start: number + public readonly End: number + private readonly Encryption?: Encryption + + constructor({ + Bucket, + Object, + VersionID = '', + MatchETag = '', + NoMatchETag = '', + MatchModifiedSince = null, + MatchUnmodifiedSince = null, + MatchRange = false, + Start = 0, + End = 0, + Encryption = undefined, + }: ICopySourceOptions) { + this.Bucket = Bucket + this.Object = Object + this.VersionID = VersionID + this.MatchETag = MatchETag + this.NoMatchETag = NoMatchETag + this.MatchModifiedSince = MatchModifiedSince + this.MatchUnmodifiedSince = MatchUnmodifiedSince + this.MatchRange = MatchRange + this.Start = Start + this.End = End + this.Encryption = Encryption + } + + validate() { + if (!isValidBucketName(this.Bucket)) { + throw new errors.InvalidBucketNameError('Invalid Source bucket name: ' + this.Bucket) + } + if (!isValidObjectName(this.Object)) { + throw new errors.InvalidObjectNameError(`Invalid Source object name: ${this.Object}`) + } + if ((this.MatchRange && this.Start !== -1 && this.End !== -1 && this.Start > this.End) || this.Start < 0) { + throw new errors.InvalidObjectNameError('Source start must be non-negative, and start must be at most end.') + } else if ((this.MatchRange && !isNumber(this.Start)) || !isNumber(this.End)) { + throw new errors.InvalidObjectNameError( + 'MatchRange is specified. But Invalid Start and End values are specified.', + ) + } + + return true + } + + getHeaders(): RequestHeaders { + const headerOptions: RequestHeaders = {} + headerOptions['x-amz-copy-source'] = encodeURI(this.Bucket + '/' + this.Object) + + if (!isEmpty(this.VersionID)) { + headerOptions['x-amz-copy-source'] = `${encodeURI(this.Bucket + '/' + this.Object)}?versionId=${this.VersionID}` + } + + if (!isEmpty(this.MatchETag)) { + headerOptions['x-amz-copy-source-if-match'] = this.MatchETag + } + if (!isEmpty(this.NoMatchETag)) { + headerOptions['x-amz-copy-source-if-none-match'] = this.NoMatchETag + } + + if (!isEmpty(this.MatchModifiedSince)) { + headerOptions['x-amz-copy-source-if-modified-since'] = this.MatchModifiedSince + } + if (!isEmpty(this.MatchUnmodifiedSince)) { + headerOptions['x-amz-copy-source-if-unmodified-since'] = this.MatchUnmodifiedSince + } + + return headerOptions + } +} + +export function removeDirAndFiles(dirPath: string, removeSelf = true) { + if (removeSelf) { + return fs.rmSync(dirPath, { recursive: true, force: true }) + } + + fs.readdirSync(dirPath).forEach((item) => { + fs.rmSync(path.join(dirPath, item), { recursive: true, force: true }) + }) +} + +export interface ICopyDestinationOptions { + /** + * Bucket name + */ + Bucket: string + /** + * Object Name for the destination (composed/copied) object defaults + */ + Object: string + /** + * Encryption configuration defaults to {} + * @default {} + */ + Encryption?: Encryption + UserMetadata?: ObjectMetaData + /** + * query-string encoded string or Record Object + */ + UserTags?: Record | string + LegalHold?: 'on' | 'off' + /** + * UTC Date String + */ + RetainUntilDate?: string + Mode?: RETENTION_MODES +} + +export class CopyDestinationOptions { + public readonly Bucket: string + public readonly Object: string + private readonly Encryption?: Encryption + private readonly UserMetadata?: ObjectMetaData + private readonly UserTags?: Record | string + private readonly LegalHold?: 'on' | 'off' + private readonly RetainUntilDate?: string + private readonly Mode?: RETENTION_MODES + + constructor({ + Bucket, + Object, + Encryption, + UserMetadata, + UserTags, + LegalHold, + RetainUntilDate, + Mode, + }: ICopyDestinationOptions) { + this.Bucket = Bucket + this.Object = Object + this.Encryption = Encryption ?? undefined // null input will become undefined, easy for runtime assert + this.UserMetadata = UserMetadata + this.UserTags = UserTags + this.LegalHold = LegalHold + this.Mode = Mode // retention mode + this.RetainUntilDate = RetainUntilDate + } + + getHeaders(): RequestHeaders { + const replaceDirective = 'REPLACE' + const headerOptions: RequestHeaders = {} + + const userTags = this.UserTags + if (!isEmpty(userTags)) { + headerOptions['X-Amz-Tagging-Directive'] = replaceDirective + headerOptions['X-Amz-Tagging'] = isObject(userTags) + ? querystring.stringify(userTags) + : isString(userTags) + ? userTags + : '' + } + + if (this.Mode) { + headerOptions['X-Amz-Object-Lock-Mode'] = this.Mode // GOVERNANCE or COMPLIANCE + } + + if (this.RetainUntilDate) { + headerOptions['X-Amz-Object-Lock-Retain-Until-Date'] = this.RetainUntilDate // needs to be UTC. + } + + if (this.LegalHold) { + headerOptions['X-Amz-Object-Lock-Legal-Hold'] = this.LegalHold // ON or OFF + } + + if (this.UserMetadata) { + for (const [key, value] of Object.entries(this.UserMetadata)) { + headerOptions[`X-Amz-Meta-${key}`] = value.toString() + } + } + + if (this.Encryption) { + const encryptionHeaders = getEncryptionHeaders(this.Encryption) + for (const [key, value] of Object.entries(encryptionHeaders)) { + headerOptions[key] = value + } + } + return headerOptions + } + + validate() { + if (!isValidBucketName(this.Bucket)) { + throw new errors.InvalidBucketNameError('Invalid Destination bucket name: ' + this.Bucket) + } + if (!isValidObjectName(this.Object)) { + throw new errors.InvalidObjectNameError(`Invalid Destination object name: ${this.Object}`) + } + if (!isEmpty(this.UserMetadata) && !isObject(this.UserMetadata)) { + throw new errors.InvalidObjectNameError(`Destination UserMetadata should be an object with key value pairs`) + } + + if (!isEmpty(this.Mode) && ![RETENTION_MODES.GOVERNANCE, RETENTION_MODES.COMPLIANCE].includes(this.Mode)) { + throw new errors.InvalidObjectNameError( + `Invalid Mode specified for destination object it should be one of [GOVERNANCE,COMPLIANCE]`, + ) + } + + if (this.Encryption !== undefined && isEmptyObject(this.Encryption)) { + throw new errors.InvalidObjectNameError(`Invalid Encryption configuration for destination object `) + } + return true + } +} + +/** + * maybe this should be a generic type for Records, leave it for later refactor + */ +export class SelectResults { + private records?: unknown + private response?: unknown + private stats?: string + private progress?: unknown + + constructor({ + records, // parsed data as stream + response, // original response stream + stats, // stats as xml + progress, // stats as xml + }: { + records?: unknown + response?: unknown + stats?: string + progress?: unknown + }) { + this.records = records + this.response = response + this.stats = stats + this.progress = progress + } + + setStats(stats: string) { + this.stats = stats + } + + getStats() { + return this.stats + } + + setProgress(progress: unknown) { + this.progress = progress + } + + getProgress() { + return this.progress + } + + setResponse(response: unknown) { + this.response = response + } + + getResponse() { + return this.response + } + + setRecords(records: unknown) { + this.records = records + } + + getRecords(): unknown { + return this.records + } +} diff --git a/src/internal/helper.ts b/src/internal/helper.ts new file mode 100644 index 00000000..98c15888 --- /dev/null +++ b/src/internal/helper.ts @@ -0,0 +1,580 @@ +/* + * MinIO Javascript Library for Amazon S3 Compatible Cloud Storage, (C) 2015 MinIO, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as crypto from 'node:crypto' +import * as stream from 'node:stream' + +import { XMLParser } from 'fast-xml-parser' +import ipaddr from 'ipaddr.js' +import _ from 'lodash' +import * as mime from 'mime-types' + +import type { Binary, Encryption, ObjectMetaData, RequestHeaders, ResponseHeader } from './type.ts' +import { ENCRYPTION_TYPES } from './type.ts' + +const MetaDataHeaderPrefix = 'x-amz-meta-' + +/** + * All characters in string which are NOT unreserved should be percent encoded. + * Unreserved characters are : ALPHA / DIGIT / "-" / "." / "_" / "~" + * Reference https://tools.ietf.org/html/rfc3986#section-2.2 + */ +export function uriEscape(string: string) { + return string.split('').reduce((acc: string, elem: string) => { + const buf = Buffer.from(elem) + if (buf.length === 1) { + // length 1 indicates that elem is not a unicode character. + // Check if it is an unreserved characer. + if ( + ('A' <= elem && elem <= 'Z') || + ('a' <= elem && elem <= 'z') || + ('0' <= elem && elem <= '9') || + elem === '_' || + elem === '.' || + elem === '~' || + elem === '-' + ) { + // Unreserved characer should not be encoded. + acc = acc + elem + return acc + } + } + // elem needs encoding - i.e elem should be encoded if it's not unreserved + // character or if it's a unicode character. + for (const char of buf) { + acc = acc + '%' + char.toString(16).toUpperCase() + } + return acc + }, '') +} + +export function uriResourceEscape(string: string) { + return uriEscape(string).replace(/%2F/g, '/') +} + +export function getScope(region: string, date: Date, serviceName = 's3') { + return `${makeDateShort(date)}/${region}/${serviceName}/aws4_request` +} + +/** + * isAmazonEndpoint - true if endpoint is 's3.amazonaws.com' or 's3.cn-north-1.amazonaws.com.cn' + */ +export function isAmazonEndpoint(endpoint: string) { + return endpoint === 's3.amazonaws.com' || endpoint === 's3.cn-north-1.amazonaws.com.cn' +} + +/** + * isVirtualHostStyle - verify if bucket name is support with virtual + * hosts. bucketNames with periods should be always treated as path + * style if the protocol is 'https:', this is due to SSL wildcard + * limitation. For all other buckets and Amazon S3 endpoint we will + * default to virtual host style. + */ +export function isVirtualHostStyle(endpoint: string, protocol: string, bucket: string, pathStyle: boolean) { + if (protocol === 'https:' && bucket.includes('.')) { + return false + } + return isAmazonEndpoint(endpoint) || !pathStyle +} + +export function isValidIP(ip: string) { + return ipaddr.isValid(ip) +} + +/** + * @returns if endpoint is valid domain. + */ +export function isValidEndpoint(endpoint: string) { + return isValidDomain(endpoint) || isValidIP(endpoint) +} + +/** + * @returns if input host is a valid domain. + */ +export function isValidDomain(host: string) { + if (!isString(host)) { + return false + } + // See RFC 1035, RFC 3696. + if (host.length === 0 || host.length > 255) { + return false + } + // Host cannot start or end with a '-' + if (host[0] === '-' || host.slice(-1) === '-') { + return false + } + // Host cannot start or end with a '_' + if (host[0] === '_' || host.slice(-1) === '_') { + return false + } + // Host cannot start with a '.' + if (host[0] === '.') { + return false + } + + const alphaNumerics = '`~!@#$%^&*()+={}[]|\\"\';:> 63) { + return false + } + // bucket with successive periods is invalid. + if (bucket.includes('..')) { + return false + } + // bucket cannot have ip address style. + if (/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/.test(bucket)) { + return false + } + // bucket should begin with alphabet/number and end with alphabet/number, + // with alphabet/number/.- in the middle. + if (/^[a-z0-9][a-z0-9.-]+[a-z0-9]$/.test(bucket)) { + return true + } + return false +} + +/** + * check if objectName is a valid object name + */ +export function isValidObjectName(objectName: unknown) { + if (!isValidPrefix(objectName)) { + return false + } + + return objectName.length !== 0 +} + +/** + * check if prefix is valid + */ +export function isValidPrefix(prefix: unknown): prefix is string { + if (!isString(prefix)) { + return false + } + if (prefix.length > 1024) { + return false + } + return true +} + +/** + * check if typeof arg number + */ +export function isNumber(arg: unknown): arg is number { + return typeof arg === 'number' +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type AnyFunction = (...args: any[]) => any + +/** + * check if typeof arg function + */ +export function isFunction(arg: unknown): arg is AnyFunction { + return typeof arg === 'function' +} + +/** + * check if typeof arg string + */ +export function isString(arg: unknown): arg is string { + return typeof arg === 'string' +} + +/** + * check if typeof arg object + */ +export function isObject(arg: unknown): arg is object { + return typeof arg === 'object' && arg !== null +} + +/** + * check if object is readable stream + */ +export function isReadableStream(arg: unknown): arg is stream.Readable { + // eslint-disable-next-line @typescript-eslint/unbound-method + return isObject(arg) && isFunction((arg as stream.Readable)._read) +} + +/** + * check if arg is boolean + */ +export function isBoolean(arg: unknown): arg is boolean { + return typeof arg === 'boolean' +} + +export function isEmpty(o: unknown): o is null | undefined { + return _.isEmpty(o) +} + +export function isEmptyObject(o: Record): boolean { + return Object.values(o).filter((x) => x !== undefined).length !== 0 +} + +/** + * check if arg is a valid date + */ +export function isValidDate(arg: unknown): arg is Date { + // @ts-expect-error checknew Date(Math.NaN) + return arg instanceof Date && !isNaN(arg) +} + +/** + * Create a Date string with format: 'YYYYMMDDTHHmmss' + Z + */ +export function makeDateLong(date?: Date): string { + date = date || new Date() + + // Gives format like: '2017-08-07T16:28:59.889Z' + const s = date.toISOString() + + return s.slice(0, 4) + s.slice(5, 7) + s.slice(8, 13) + s.slice(14, 16) + s.slice(17, 19) + 'Z' +} + +/** + * Create a Date string with format: 'YYYYMMDD' + */ +export function makeDateShort(date?: Date) { + date = date || new Date() + + // Gives format like: '2017-08-07T16:28:59.889Z' + const s = date.toISOString() + + return s.slice(0, 4) + s.slice(5, 7) + s.slice(8, 10) +} + +/** + * pipesetup sets up pipe() from left to right os streams array + * pipesetup will also make sure that error emitted at any of the upstream Stream + * will be emitted at the last stream. This makes error handling simple + */ +export function pipesetup(...streams: [stream.Readable, ...stream.Duplex[], stream.Writable]) { + // @ts-expect-error ts can't narrow this + return streams.reduce((src: stream.Readable, dst: stream.Writable) => { + src.on('error', (err) => dst.emit('error', err)) + return src.pipe(dst) + }) +} + +/** + * return a Readable stream that emits data + */ +export function readableStream(data: unknown): stream.Readable { + const s = new stream.Readable() + s._read = () => {} + s.push(data) + s.push(null) + return s +} + +/** + * Process metadata to insert appropriate value to `content-type` attribute + */ +export function insertContentType(metaData: ObjectMetaData, filePath: string): ObjectMetaData { + // check if content-type attribute present in metaData + for (const key in metaData) { + if (key.toLowerCase() === 'content-type') { + return metaData + } + } + + // if `content-type` attribute is not present in metadata, then infer it from the extension in filePath + return { + ...metaData, + 'content-type': probeContentType(filePath), + } +} + +/** + * Function prepends metadata with the appropriate prefix if it is not already on + */ +export function prependXAMZMeta(metaData?: ObjectMetaData): RequestHeaders { + if (!metaData) { + return {} + } + + return _.mapKeys(metaData, (value, key) => { + if (isAmzHeader(key) || isSupportedHeader(key) || isStorageClassHeader(key)) { + return key + } + + return MetaDataHeaderPrefix + key + }) +} + +/** + * Checks if it is a valid header according to the AmazonS3 API + */ +export function isAmzHeader(key: string) { + const temp = key.toLowerCase() + return ( + temp.startsWith(MetaDataHeaderPrefix) || + temp === 'x-amz-acl' || + temp.startsWith('x-amz-server-side-encryption-') || + temp === 'x-amz-server-side-encryption' + ) +} + +/** + * Checks if it is a supported Header + */ +export function isSupportedHeader(key: string) { + const supported_headers = [ + 'content-type', + 'cache-control', + 'content-encoding', + 'content-disposition', + 'content-language', + 'x-amz-website-redirect-location', + ] + return supported_headers.includes(key.toLowerCase()) +} + +/** + * Checks if it is a storage header + */ +export function isStorageClassHeader(key: string) { + return key.toLowerCase() === 'x-amz-storage-class' +} + +export function extractMetadata(headers: ResponseHeader) { + return _.mapKeys( + _.pickBy(headers, (value, key) => isSupportedHeader(key) || isStorageClassHeader(key) || isAmzHeader(key)), + (value, key) => { + const lower = key.toLowerCase() + if (lower.startsWith(MetaDataHeaderPrefix)) { + return lower.slice(MetaDataHeaderPrefix.length) + } + + return key + }, + ) +} + +export function getVersionId(headers: ResponseHeader = {}) { + return headers['x-amz-version-id'] || null +} + +export function getSourceVersionId(headers: ResponseHeader = {}) { + return headers['x-amz-copy-source-version-id'] || null +} + +export function sanitizeETag(etag = ''): string { + const replaceChars: Record = { + '"': '', + '"': '', + '"': '', + '"': '', + '"': '', + } + return etag.replace(/^("|"|")|("|"|")$/g, (m) => replaceChars[m] as string) +} + +export function toMd5(payload: Binary): string { + // use string from browser and buffer from nodejs + // browser support is tested only against minio server + return crypto.createHash('md5').update(Buffer.from(payload)).digest().toString('base64') +} + +export function toSha256(payload: Binary): string { + return crypto.createHash('sha256').update(payload).digest('hex') +} + +/** + * toArray returns a single element array with param being the element, + * if param is just a string, and returns 'param' back if it is an array + * So, it makes sure param is always an array + */ +export function toArray(param: T | T[]): Array { + if (!Array.isArray(param)) { + return [param] as T[] + } + return param +} + +export function sanitizeObjectKey(objectName: string): string { + // + symbol characters are not decoded as spaces in JS. so replace them first and decode to get the correct result. + const asStrName = (objectName ? objectName.toString() : '').replace(/\+/g, ' ') + return decodeURIComponent(asStrName) +} + +export const PART_CONSTRAINTS = { + // absMinPartSize - absolute minimum part size (5 MiB) + ABS_MIN_PART_SIZE: 1024 * 1024 * 5, + // MIN_PART_SIZE - minimum part size 16MiB per object after which + MIN_PART_SIZE: 1024 * 1024 * 16, + // MAX_PARTS_COUNT - maximum number of parts for a single multipart session. + MAX_PARTS_COUNT: 10000, + // MAX_PART_SIZE - maximum part size 5GiB for a single multipart upload + // operation. + MAX_PART_SIZE: 1024 * 1024 * 1024 * 5, + // MAX_SINGLE_PUT_OBJECT_SIZE - maximum size 5GiB of object per PUT + // operation. + MAX_SINGLE_PUT_OBJECT_SIZE: 1024 * 1024 * 1024 * 5, + // MAX_MULTIPART_PUT_OBJECT_SIZE - maximum size 5TiB of object for + // Multipart operation. + MAX_MULTIPART_PUT_OBJECT_SIZE: 1024 * 1024 * 1024 * 1024 * 5, +} + +const GENERIC_SSE_HEADER = 'X-Amz-Server-Side-Encryption' + +const ENCRYPTION_HEADERS = { + // sseGenericHeader is the AWS SSE header used for SSE-S3 and SSE-KMS. + sseGenericHeader: GENERIC_SSE_HEADER, + // sseKmsKeyID is the AWS SSE-KMS key id. + sseKmsKeyID: GENERIC_SSE_HEADER + '-Aws-Kms-Key-Id', +} as const + +/** + * Return Encryption headers + * @param encConfig + * @returns an object with key value pairs that can be used in headers. + */ +export function getEncryptionHeaders(encConfig: Encryption): RequestHeaders { + const encType = encConfig.type + + if (!isEmpty(encType)) { + if (encType === ENCRYPTION_TYPES.SSEC) { + return { + [ENCRYPTION_HEADERS.sseGenericHeader]: 'AES256', + } + } else if (encType === ENCRYPTION_TYPES.KMS) { + return { + [ENCRYPTION_HEADERS.sseGenericHeader]: encConfig.SSEAlgorithm, + [ENCRYPTION_HEADERS.sseKmsKeyID]: encConfig.KMSMasterKeyID, + } + } + } + + return {} +} + +export function partsRequired(size: number): number { + const maxPartSize = PART_CONSTRAINTS.MAX_MULTIPART_PUT_OBJECT_SIZE / (PART_CONSTRAINTS.MAX_PARTS_COUNT - 1) + let requiredPartSize = size / maxPartSize + if (size % maxPartSize > 0) { + requiredPartSize++ + } + requiredPartSize = Math.trunc(requiredPartSize) + return requiredPartSize +} + +/** + * calculateEvenSplits - computes splits for a source and returns + * start and end index slices. Splits happen evenly to be sure that no + * part is less than 5MiB, as that could fail the multipart request if + * it is not the last part. + */ +export function calculateEvenSplits( + size: number, + objInfo: T, +): { + startIndex: number[] + objInfo: T + endIndex: number[] +} | null { + if (size === 0) { + return null + } + const reqParts = partsRequired(size) + const startIndexParts: number[] = [] + const endIndexParts: number[] = [] + + let start = objInfo.Start + if (isEmpty(start) || start === -1) { + start = 0 + } + const divisorValue = Math.trunc(size / reqParts) + + const reminderValue = size % reqParts + + let nextStart = start + + for (let i = 0; i < reqParts; i++) { + let curPartSize = divisorValue + if (i < reminderValue) { + curPartSize++ + } + + const currentStart = nextStart + const currentEnd = currentStart + curPartSize - 1 + nextStart = currentEnd + 1 + + startIndexParts.push(currentStart) + endIndexParts.push(currentEnd) + } + + return { startIndex: startIndexParts, endIndex: endIndexParts, objInfo: objInfo } +} + +const fxp = new XMLParser() + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function parseXml(xml: string): any { + const result = fxp.parse(xml) + if (result.Error) { + throw result.Error + } + + return result +} diff --git a/src/s3-endpoints.js b/src/internal/s3-endpoints.ts similarity index 88% rename from src/s3-endpoints.js rename to src/internal/s3-endpoints.ts index aa6a7921..141f08ff 100644 --- a/src/s3-endpoints.js +++ b/src/internal/s3-endpoints.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { isString } from './helpers.js' +import { isString } from './helper.ts' // List of currently supported endpoints. const awsS3Endpoint = { @@ -37,12 +37,15 @@ const awsS3Endpoint = { // Add new endpoints here. } +export type Region = keyof typeof awsS3Endpoint | string + // getS3Endpoint get relevant endpoint for the region. -export function getS3Endpoint(region) { +export function getS3Endpoint(region: Region): string { if (!isString(region)) { throw new TypeError(`Invalid region: ${region}`) } - var endpoint = awsS3Endpoint[region] + + const endpoint = (awsS3Endpoint as Record)[region] if (endpoint) { return endpoint } diff --git a/src/internal/type.ts b/src/internal/type.ts new file mode 100644 index 00000000..a0352d3a --- /dev/null +++ b/src/internal/type.ts @@ -0,0 +1,59 @@ +import type * as http from 'node:http' +import type * as https from 'node:https' + +export type Binary = string | Buffer + +// nodejs IncomingHttpHeaders is Record, but it's actually this: +export type ResponseHeader = Record + +export type ObjectMetaData = Record + +export type RequestHeaders = Record + +export type Encryption = + | { + type: ENCRYPTION_TYPES.SSEC + } + | { + type: ENCRYPTION_TYPES.KMS + SSEAlgorithm?: string + KMSMasterKeyID?: string + } + +export enum ENCRYPTION_TYPES { + /** + * SSEC represents server-side-encryption with customer provided keys + */ + SSEC = 'SSE-C', + /** + * KMS represents server-side-encryption with managed keys + */ + KMS = 'KMS', +} + +export enum RETENTION_MODES { + GOVERNANCE = 'GOVERNANCE', + COMPLIANCE = 'COMPLIANCE', +} + +export enum RETENTION_VALIDITY_UNITS { + DAYS = 'Days', + YEARS = 'Years', +} + +export enum LEGAL_HOLD_STATUS { + ENABLED = 'ON', + DISABLED = 'OFF', +} + +export type Transport = typeof http | typeof https + +export interface IRequest { + protocol: string + port?: number | string + method: string + path: string + headers: RequestHeaders +} + +export type ICanonicalRequest = string diff --git a/types/minio.d.ts b/src/minio.d.ts similarity index 88% rename from types/minio.d.ts rename to src/minio.d.ts index dbd85e74..7c1fac2f 100644 --- a/types/minio.d.ts +++ b/src/minio.d.ts @@ -4,19 +4,20 @@ import { EventEmitter } from 'node:events' import type { RequestOptions } from 'node:https' import type { Readable as ReadableStream } from 'node:stream' +import type { + CopyDestinationOptions, + CopySourceOptions, + LEGAL_HOLD_STATUS, + RETENTION_MODES, + RETENTION_VALIDITY_UNITS, +} from './helpers.ts' +import type { Region } from './internal/s3-endpoints.ts' +import type { Transport } from './internal/type.ts' + +export * from './helpers.ts' +export type { Region } from './internal/s3-endpoints.ts' + // Exports only from typings -export type Region = - | 'us-east-1' - | 'us-west-1' - | 'us-west-2' - | 'eu-west-1' - | 'eu-central-1' - | 'ap-southeast-1' - | 'ap-northeast-1' - | 'ap-southeast-2' - | 'sa-east-1' - | 'cn-north-1' - | string export type NotificationEvent = | 's3:ObjectCreated:*' | 's3:ObjectCreated:Put' @@ -35,9 +36,22 @@ export type NotificationEvent = | 's3:Replication:OperationReplicatedAfterThreshold' | 's3:Replication:OperationNotTracked' | string -export type Mode = 'COMPLIANCE' | 'GOVERNANCE' -export type LockUnit = 'Days' | 'Years' -export type LegalHoldStatus = 'ON' | 'OFF' + +/** + * @deprecated keep for backward compatible, use `RETENTION_MODES` instead + */ +export type Mode = RETENTION_MODES + +/** + * @deprecated keep for backward compatible + */ +export type LockUnit = RETENTION_VALIDITY_UNITS + +/** + * @deprecated keep for backward compatible + */ +export type LegalHoldStatus = LEGAL_HOLD_STATUS + export type NoResultCallback = (error: Error | null) => void export type ResultCallback = (error: Error | null, result: T) => void export type VersioningConfig = Record @@ -57,7 +71,7 @@ export interface ClientOptions { useSSL?: boolean | undefined port?: number | undefined region?: Region | undefined - transport?: any + transport?: Transport sessionToken?: string | undefined partSize?: number | undefined pathStyle?: boolean | undefined @@ -147,8 +161,8 @@ export interface LifecycleRule { } export interface LockConfig { - mode: Mode - unit: LockUnit + mode: RETENTION_MODES + unit: RETENTION_VALIDITY_UNITS validity: number } @@ -171,14 +185,14 @@ export interface ReplicationConfig { export interface RetentionOptions { versionId: string - mode?: Mode + mode?: RETENTION_MODES retainUntilDate?: IsoDate governanceBypass?: boolean } export interface LegalHoldOptions { versionId: string - status: LegalHoldStatus + status: LEGAL_HOLD_STATUS } export interface InputSerialization { @@ -230,13 +244,13 @@ export interface SourceObjectStats { // No need to export this. But without it - linter error. export class TargetConfig { - setId(id: any): void + setId(id: unknown): void - addEvent(newEvent: any): void + addEvent(newEvent: unknown): void - addFilterSuffix(suffix: any): void + addFilterSuffix(suffix: string): void - addFilterPrefix(prefix: any): void + addFilterPrefix(prefix: string): void } export interface MakeBucketOpt { @@ -649,14 +663,7 @@ export class Client { } } -export namespace Policy { - const NONE: 'none' - const READONLY: 'readonly' - const WRITEONLY: 'writeonly' - const READWRITE: 'readwrite' -} - -export class CopyConditions { +export declare class CopyConditions { setModified(date: Date): void setUnmodified(date: Date): void @@ -666,7 +673,7 @@ export class CopyConditions { setMatchETagExcept(etag: string): void } -export class PostPolicy { +export declare class PostPolicy { setExpires(date: Date): void setKey(objectName: string): void @@ -686,7 +693,7 @@ export class PostPolicy { setUserMetaData(metadata: Record): void } -export class NotificationPoller extends EventEmitter { +export declare class NotificationPoller extends EventEmitter { stop(): void start(): void @@ -695,68 +702,23 @@ export class NotificationPoller extends EventEmitter { checkForChanges(): void } -export class NotificationConfig { +export declare class NotificationConfig { add(target: TopicConfig | QueueConfig | CloudFunctionConfig): void } -export class TopicConfig extends TargetConfig { +export declare class TopicConfig extends TargetConfig { constructor(arn: string) } -export class QueueConfig extends TargetConfig { +export declare class QueueConfig extends TargetConfig { constructor(arn: string) } -export class CloudFunctionConfig extends TargetConfig { +export declare class CloudFunctionConfig extends TargetConfig { constructor(arn: string) } -export class CopySourceOptions { - constructor(options: { - Bucket: string - Object: string - VersionID?: string - MatchETag?: string - NoMatchETag?: string - MatchModifiedSince?: string - MatchUnmodifiedSince?: string - MatchRange?: boolean - Start?: number - End?: number - Encryption?: { - type: string - SSEAlgorithm?: string - KMSMasterKeyID?: string - } - }) - - getHeaders(): Record - - validate(): boolean -} - -export class CopyDestinationOptions { - constructor(options: { - Bucket: string - Object: string - Encryption?: { - type: string - SSEAlgorithm?: string - KMSMasterKeyID?: string - } - UserMetadata?: Record - UserTags?: Record | string - LegalHold?: LegalHoldStatus - RetainUntilDate?: string - Mode?: Mode - }) - - getHeaders(): Record - - validate(): boolean -} - -export function buildARN( +export declare function buildARN( partition: string, service: string, region: string, @@ -764,12 +726,12 @@ export function buildARN( resource: string, ): string -export const ObjectCreatedAll: NotificationEvent // s3:ObjectCreated:*' -export const ObjectCreatedPut: NotificationEvent // s3:ObjectCreated:Put -export const ObjectCreatedPost: NotificationEvent // s3:ObjectCreated:Post -export const ObjectCreatedCopy: NotificationEvent // s3:ObjectCreated:Copy -export const ObjectCreatedCompleteMultipartUpload: NotificationEvent // s3:ObjectCreated:CompleteMultipartUpload -export const ObjectRemovedAll: NotificationEvent // s3:ObjectRemoved:* -export const ObjectRemovedDelete: NotificationEvent // s3:ObjectRemoved:Delete -export const ObjectRemovedDeleteMarkerCreated: NotificationEvent // s3:ObjectRemoved:DeleteMarkerCreated -export const ObjectReducedRedundancyLostObject: NotificationEvent // s3:ReducedRedundancyLostObject +export declare const ObjectCreatedAll: NotificationEvent // s3:ObjectCreated:*' +export declare const ObjectCreatedPut: NotificationEvent // s3:ObjectCreated:Put +export declare const ObjectCreatedPost: NotificationEvent // s3:ObjectCreated:Post +export declare const ObjectCreatedCopy: NotificationEvent // s3:ObjectCreated:Copy +export declare const ObjectCreatedCompleteMultipartUpload: NotificationEvent // s3:ObjectCreated:CompleteMultipartUpload +export declare const ObjectRemovedAll: NotificationEvent // s3:ObjectRemoved:* +export declare const ObjectRemovedDelete: NotificationEvent // s3:ObjectRemoved:Delete +export declare const ObjectRemovedDeleteMarkerCreated: NotificationEvent // s3:ObjectRemoved:DeleteMarkerCreated +export declare const ObjectReducedRedundancyLostObject: NotificationEvent // s3:ReducedRedundancyLostObject diff --git a/src/minio.js b/src/minio.js index 2567e254..6901daf8 100644 --- a/src/minio.js +++ b/src/minio.js @@ -32,18 +32,15 @@ import xml2js from 'xml2js' import { CredentialProvider } from './CredentialProvider.js' import * as errors from './errors.ts' import { extensions } from './extensions.js' +import { CopyDestinationOptions, CopySourceOptions, DEFAULT_REGION } from './helpers.ts' import { calculateEvenSplits, - CopyDestinationOptions, - CopySourceOptions, - DEFAULT_REGION, extractMetadata, getScope, getSourceVersionId, getVersionId, insertContentType, isAmazonEndpoint, - isArray, isBoolean, isFunction, isNumber, @@ -57,33 +54,30 @@ import { isValidPort, isValidPrefix, isVirtualHostStyle, - LEGAL_HOLD_STATUS, makeDateLong, PART_CONSTRAINTS, partsRequired, pipesetup, prependXAMZMeta, - promisify, readableStream, - RETENTION_MODES, - RETENTION_VALIDITY_UNITS, sanitizeETag, toMd5, toSha256, uriEscape, uriResourceEscape, -} from './helpers.js' +} from './internal/helper.ts' +import { getS3Endpoint } from './internal/s3-endpoints.ts' +import { LEGAL_HOLD_STATUS, RETENTION_MODES, RETENTION_VALIDITY_UNITS } from './internal/type.ts' import { NotificationConfig, NotificationPoller } from './notification.js' import { ObjectUploader } from './object-uploader.js' -import { getS3Endpoint } from './s3-endpoints.js' -import { postPresignSignatureV4, presignSignatureV4, signV4 } from './signing.js' +import { promisify } from './promisify.js' +import { postPresignSignatureV4, presignSignatureV4, signV4 } from './signing.ts' import * as transformers from './transformers.js' import { parseSelectObjectContentResponse } from './xml-parsers.js' - // will be replaced by bundler const Package = { version: process.env.MINIO_JS_PACKAGE_VERSION || 'development' } -export * from './helpers.js' +export * from './helpers.ts' export * from './notification.js' export class Client { @@ -569,7 +563,7 @@ export class Client { } this.checkAndRefreshCreds() - var authorization = signV4(reqOptions, this.accessKey, this.secretKey, region, date) + var authorization = signV4(reqOptions, this.accessKey, this.secretKey, region, date, sha256sum) reqOptions.headers.authorization = authorization } var req = this.transport.request(reqOptions, (response) => { @@ -1913,7 +1907,7 @@ export class Client { if (!isValidBucketName(bucketName)) { throw new errors.InvalidBucketNameError('Invalid bucket name: ' + bucketName) } - if (!isArray(objectsList)) { + if (!Array.isArray(objectsList)) { throw new errors.InvalidArgumentError('objectsList should be a list') } if (!isFunction(cb)) { @@ -2637,7 +2631,7 @@ export class Client { if (!isString(suffix)) { throw new TypeError('suffix must be of type string') } - if (!isArray(events)) { + if (!Array.isArray(events)) { throw new TypeError('events must be of type Array') } let listener = new NotificationPoller(this, bucketName, prefix, suffix, events) @@ -3543,7 +3537,7 @@ export class Client { const me = this // many async flows. so store the ref. const sourceFilesLength = sourceObjList.length - if (!isArray(sourceObjList)) { + if (!Array.isArray(sourceObjList)) { throw new errors.InvalidArgumentError('sourceConfig should an array of CopySourceOptions ') } if (!(destObjConfig instanceof CopyDestinationOptions)) { diff --git a/src/notification.js b/src/notification.js index 5fe14541..2c3b45c3 100644 --- a/src/notification.js +++ b/src/notification.js @@ -16,7 +16,8 @@ import { EventEmitter } from 'node:events' -import { DEFAULT_REGION, pipesetup, uriEscape } from './helpers.js' +import { DEFAULT_REGION } from './helpers.ts' +import { pipesetup, uriEscape } from './internal/helper.ts' import * as transformers from './transformers.js' // Notification config - array of target configs. diff --git a/src/object-uploader.js b/src/object-uploader.js index 2fdf6606..b14f75c1 100644 --- a/src/object-uploader.js +++ b/src/object-uploader.js @@ -19,7 +19,7 @@ import { Transform } from 'node:stream' import * as querystring from 'query-string' -import { getVersionId, sanitizeETag } from './helpers.js' +import { getVersionId, sanitizeETag } from './internal/helper.ts' // We extend Transform because Writable does not implement ._flush(). export class ObjectUploader extends Transform { diff --git a/src/promisify.js b/src/promisify.js new file mode 100644 index 00000000..1f68464a --- /dev/null +++ b/src/promisify.js @@ -0,0 +1,31 @@ +// Returns a wrapper function that will promisify a given callback function. +// It will preserve 'this'. +export function promisify(fn) { + return function () { + // If the last argument is a function, assume its the callback. + let callback = arguments[arguments.length - 1] + + // If the callback is given, don't promisify, just pass straight in. + if (typeof callback === 'function') { + return fn.apply(this, arguments) + } + + // Otherwise, create a new set of arguments, and wrap + // it in a promise. + let args = [...arguments] + + return new Promise((resolve, reject) => { + // Add the callback function. + args.push((err, value) => { + if (err) { + return reject(err) + } + + resolve(value) + }) + + // Call the function with our special adaptor callback added. + fn.apply(this, args) + }) + } +} diff --git a/src/signing.js b/src/signing.ts similarity index 76% rename from src/signing.js rename to src/signing.ts index 247206f6..bacd0158 100644 --- a/src/signing.js +++ b/src/signing.ts @@ -14,12 +14,11 @@ * limitations under the License. */ -import * as Crypto from 'node:crypto' - -import _ from 'lodash' +import * as crypto from 'node:crypto' import * as errors from './errors.ts' -import { getScope, isArray, isNumber, isObject, isString, makeDateLong, makeDateShort, uriEscape } from './helpers.js' +import { getScope, isNumber, isObject, isString, makeDateLong, makeDateShort, uriEscape } from './internal/helper.ts' +import type { ICanonicalRequest, IRequest, RequestHeaders } from './internal/type.ts' const signV4Algorithm = 'AWS4-HMAC-SHA256' @@ -33,7 +32,13 @@ const signV4Algorithm = 'AWS4-HMAC-SHA256' // \n // // -function getCanonicalRequest(method, path, headers, signedHeaders, hashedPayload) { +function getCanonicalRequest( + method: string, + path: string, + headers: RequestHeaders, + signedHeaders: string[], + hashedPayload: string, +): ICanonicalRequest { if (!isString(method)) { throw new TypeError('method should be of type "string"') } @@ -43,18 +48,19 @@ function getCanonicalRequest(method, path, headers, signedHeaders, hashedPayload if (!isObject(headers)) { throw new TypeError('headers should be of type "object"') } - if (!isArray(signedHeaders)) { + if (!Array.isArray(signedHeaders)) { throw new TypeError('signedHeaders should be of type "array"') } if (!isString(hashedPayload)) { throw new TypeError('hashedPayload should be of type "string"') } + const headersArray = signedHeaders.reduce((acc, i) => { // Trim spaces from the value (required by V4 spec) const val = `${headers[i]}`.replace(/ +/g, ' ') acc.push(`${i.toLowerCase()}:${val}`) return acc - }, []) + }, [] as string[]) const requestResource = path.split('?')[0] let requestQuery = path.split('?')[1] @@ -66,22 +72,22 @@ function getCanonicalRequest(method, path, headers, signedHeaders, hashedPayload requestQuery = requestQuery .split('&') .sort() - .map((element) => (element.indexOf('=') === -1 ? element + '=' : element)) + .map((element) => (!element.includes('=') ? element + '=' : element)) .join('&') } - const canonical = [] - canonical.push(method.toUpperCase()) - canonical.push(requestResource) - canonical.push(requestQuery) - canonical.push(headersArray.join('\n') + '\n') - canonical.push(signedHeaders.join(';').toLowerCase()) - canonical.push(hashedPayload) - return canonical.join('\n') + return [ + method.toUpperCase(), + requestResource, + requestQuery, + headersArray.join('\n') + '\n', + signedHeaders.join(';').toLowerCase(), + hashedPayload, + ].join('\n') } // generate a credential string -function getCredential(accessKey, region, requestDate, serviceName = 's3') { +function getCredential(accessKey: string, region: string, requestDate?: Date, serviceName = 's3') { if (!isString(accessKey)) { throw new TypeError('accessKey should be of type "string"') } @@ -95,7 +101,7 @@ function getCredential(accessKey, region, requestDate, serviceName = 's3') { } // Returns signed headers array - alphabetically sorted -function getSignedHeaders(headers) { +function getSignedHeaders(headers: RequestHeaders): string[] { if (!isObject(headers)) { throw new TypeError('request should be of type "object"') } @@ -127,13 +133,13 @@ function getSignedHeaders(headers) { // Is skipped for obvious reasons const ignoredHeaders = ['authorization', 'content-length', 'content-type', 'user-agent'] - return _.map(headers, (v, header) => header) - .filter((header) => ignoredHeaders.indexOf(header) === -1) + return Object.keys(headers) + .filter((header) => !ignoredHeaders.includes(header)) .sort() } // returns the key used for calculating signature -function getSigningKey(date, region, secretKey, serviceName = 's3') { +function getSigningKey(date: Date, region: string, secretKey: string, serviceName = 's3') { if (!isObject(date)) { throw new TypeError('date should be of type "object"') } @@ -144,16 +150,17 @@ function getSigningKey(date, region, secretKey, serviceName = 's3') { throw new TypeError('secretKey should be of type "string"') } const dateLine = makeDateShort(date) - let hmac1 = Crypto.createHmac('sha256', 'AWS4' + secretKey) + const hmac1 = crypto + .createHmac('sha256', 'AWS4' + secretKey) .update(dateLine) .digest(), - hmac2 = Crypto.createHmac('sha256', hmac1).update(region).digest(), - hmac3 = Crypto.createHmac('sha256', hmac2).update(serviceName).digest() - return Crypto.createHmac('sha256', hmac3).update('aws4_request').digest() + hmac2 = crypto.createHmac('sha256', hmac1).update(region).digest(), + hmac3 = crypto.createHmac('sha256', hmac2).update(serviceName).digest() + return crypto.createHmac('sha256', hmac3).update('aws4_request').digest() } // returns the string that needs to be signed -function getStringToSign(canonicalRequest, requestDate, region, serviceName = 's3') { +function getStringToSign(canonicalRequest: ICanonicalRequest, requestDate: Date, region: string, serviceName = 's3') { if (!isString(canonicalRequest)) { throw new TypeError('canonicalRequest should be of type "string"') } @@ -163,19 +170,15 @@ function getStringToSign(canonicalRequest, requestDate, region, serviceName = 's if (!isString(region)) { throw new TypeError('region should be of type "string"') } - const hash = Crypto.createHash('sha256').update(canonicalRequest).digest('hex') + const hash = crypto.createHash('sha256').update(canonicalRequest).digest('hex') const scope = getScope(region, requestDate, serviceName) - const stringToSign = [] - stringToSign.push(signV4Algorithm) - stringToSign.push(makeDateLong(requestDate)) - stringToSign.push(scope) - stringToSign.push(hash) - const signString = stringToSign.join('\n') - return signString + const stringToSign = [signV4Algorithm, makeDateLong(requestDate), scope, hash] + + return stringToSign.join('\n') } // calculate the signature of the POST policy -export function postPresignSignatureV4(region, date, secretKey, policyBase64) { +export function postPresignSignatureV4(region: string, date: Date, secretKey: string, policyBase64: string): string { if (!isString(region)) { throw new TypeError('region should be of type "string"') } @@ -189,11 +192,19 @@ export function postPresignSignatureV4(region, date, secretKey, policyBase64) { throw new TypeError('policyBase64 should be of type "string"') } const signingKey = getSigningKey(date, region, secretKey) - return Crypto.createHmac('sha256', signingKey).update(policyBase64).digest('hex').toLowerCase() + return crypto.createHmac('sha256', signingKey).update(policyBase64).digest('hex').toLowerCase() } // Returns the authorization header -export function signV4(request, accessKey, secretKey, region, requestDate, serviceName = 's3') { +export function signV4( + request: IRequest, + accessKey: string, + secretKey: string, + region: string, + requestDate: Date, + sha256sum: string, + serviceName = 's3', +) { if (!isObject(request)) { throw new TypeError('request should be of type "object"') } @@ -214,26 +225,41 @@ export function signV4(request, accessKey, secretKey, region, requestDate, servi throw new errors.SecretKeyRequiredError('secretKey is required for signing') } - const sha256sum = request.headers['x-amz-content-sha256'] - const signedHeaders = getSignedHeaders(request.headers) const canonicalRequest = getCanonicalRequest(request.method, request.path, request.headers, signedHeaders, sha256sum) const serviceIdentifier = serviceName || 's3' const stringToSign = getStringToSign(canonicalRequest, requestDate, region, serviceIdentifier) const signingKey = getSigningKey(requestDate, region, secretKey, serviceIdentifier) const credential = getCredential(accessKey, region, requestDate, serviceIdentifier) - const signature = Crypto.createHmac('sha256', signingKey).update(stringToSign).digest('hex').toLowerCase() + const signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest('hex').toLowerCase() return `${signV4Algorithm} Credential=${credential}, SignedHeaders=${signedHeaders .join(';') .toLowerCase()}, Signature=${signature}` } -export function signV4ByServiceName(request, accessKey, secretKey, region, requestDate, serviceName = 's3') { - return signV4(request, accessKey, secretKey, region, requestDate, serviceName) +export function signV4ByServiceName( + request: IRequest, + accessKey: string, + secretKey: string, + region: string, + requestDate: Date, + contentSha256: string, + serviceName = 's3', +): string { + return signV4(request, accessKey, secretKey, region, requestDate, contentSha256, serviceName) } + // returns a presigned URL string -export function presignSignatureV4(request, accessKey, secretKey, sessionToken, region, requestDate, expires) { +export function presignSignatureV4( + request: IRequest, + accessKey: string, + secretKey: string, + sessionToken: string, + region: string, + requestDate: Date, + expires: number, +) { if (!isObject(request)) { throw new TypeError('request should be of type "object"') } @@ -269,7 +295,7 @@ export function presignSignatureV4(request, accessKey, secretKey, sessionToken, const credential = getCredential(accessKey, region, requestDate) const hashedPayload = 'UNSIGNED-PAYLOAD' - const requestQuery = [] + const requestQuery: string[] = [] requestQuery.push(`X-Amz-Algorithm=${signV4Algorithm}`) requestQuery.push(`X-Amz-Credential=${uriEscape(credential)}`) requestQuery.push(`X-Amz-Date=${iso8601Date}`) @@ -293,7 +319,6 @@ export function presignSignatureV4(request, accessKey, secretKey, sessionToken, const stringToSign = getStringToSign(canonicalRequest, requestDate, region) const signingKey = getSigningKey(requestDate, region, secretKey) - const signature = Crypto.createHmac('sha256', signingKey).update(stringToSign).digest('hex').toLowerCase() - const presignedUrl = request.protocol + '//' + request.headers.host + path + `&X-Amz-Signature=${signature}` - return presignedUrl + const signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest('hex').toLowerCase() + return request.protocol + '//' + request.headers.host + path + `&X-Amz-Signature=${signature}` } diff --git a/src/transformers.js b/src/transformers.js index 4cde9a2a..bf4d0db7 100644 --- a/src/transformers.js +++ b/src/transformers.js @@ -21,7 +21,7 @@ import _ from 'lodash' import Through2 from 'through2' import * as errors from './errors.ts' -import { isFunction } from './helpers.js' +import { isFunction } from './internal/helper.ts' import * as xmlParsers from './xml-parsers.js' // getConcater returns a stream that concatenates the input and emits diff --git a/src/xml-parsers.js b/src/xml-parsers.js index 447ec898..994af5a7 100644 --- a/src/xml-parsers.js +++ b/src/xml-parsers.js @@ -19,16 +19,9 @@ import { XMLParser } from 'fast-xml-parser' import _ from 'lodash' import * as errors from './errors.ts' -import { - isObject, - parseXml, - readableStream, - RETENTION_VALIDITY_UNITS, - sanitizeETag, - sanitizeObjectKey, - SelectResults, - toArray, -} from './helpers.js' +import { SelectResults } from './helpers.ts' +import { isObject, parseXml, readableStream, sanitizeETag, sanitizeObjectKey, toArray } from './internal/helper.ts' +import { RETENTION_VALIDITY_UNITS } from './internal/type.ts' // Parse XML and return information as Javascript types const fxp = new XMLParser() diff --git a/tests/functional/functional-tests.js b/tests/functional/functional-tests.js index f24f7ab6..21221a04 100644 --- a/tests/functional/functional-tests.js +++ b/tests/functional/functional-tests.js @@ -31,14 +31,8 @@ import superagent from 'superagent' import * as uuid from 'uuid' import { AssumeRoleProvider } from '../../src/AssumeRoleProvider.js' -import { - CopyDestinationOptions, - CopySourceOptions, - DEFAULT_REGION, - getVersionId, - isArray, - removeDirAndFiles, -} from '../../src/helpers.js' +import { CopyDestinationOptions, CopySourceOptions, DEFAULT_REGION, removeDirAndFiles } from '../../src/helpers.ts' +import { getVersionId } from '../../src/internal/helper.ts' import * as minio from '../../src/minio.js' const assert = chai.assert @@ -2447,7 +2441,7 @@ describe('functional tests', function () { if (err) { return done(err) } - if (isArray(tagList)) { + if (Array.isArray(tagList)) { done() } }) @@ -2507,7 +2501,7 @@ describe('functional tests', function () { if (err) { return done(err) } - if (isArray(tagList)) { + if (Array.isArray(tagList)) { done() } }) @@ -2604,7 +2598,7 @@ describe('functional tests', function () { if (err) { return done(err) } - if (isArray(tagList)) { + if (Array.isArray(tagList)) { done() } }) @@ -3777,7 +3771,7 @@ describe('functional tests', function () { const objContent = Buffer.alloc(100 * 1024, 0) const canRunAssumeRoleTest = clientConfigParams.endPoint.includes('localhost') - const stsEndPoint = 'http://localhost:9000' + const stsEndPoint = 'http://' + clientConfigParams.endPoint + ':' + clientConfigParams.port try { if (canRunAssumeRoleTest) { diff --git a/tests/unit/test.js b/tests/unit/test.js index ceaf4256..02f1cc35 100644 --- a/tests/unit/test.js +++ b/tests/unit/test.js @@ -19,17 +19,15 @@ import * as Stream from 'node:stream' import { assert } from 'chai' import Nock from 'nock' +import { CopyDestinationOptions, CopySourceOptions } from '../../src/helpers.ts' import { calculateEvenSplits, - CopyDestinationOptions, - CopySourceOptions, - isArray, isValidEndpoint, isValidIP, makeDateLong, makeDateShort, partsRequired, -} from '../../src/helpers.js' +} from '../../src/internal/helper.ts' import * as Minio from '../../src/minio.js' const Package = { version: 'development' } @@ -174,7 +172,7 @@ describe('Helpers', () => { const fnResult = calculateEvenSplits(testCase.size, testCase) const { startIndex, endIndex } = fnResult || {} - if (isArray(startIndex) && isArray(endIndex)) { + if (Array.isArray(startIndex) && Array.isArray(endIndex)) { const isExpectedResult = startIndex.length === testCase.expectedStart.length && endIndex.length === testCase.expectedEnd.length assert.equal(isExpectedResult, true)