diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index c299b37..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,52 +0,0 @@ -module.exports = { - // Specifies the ESLint parser - parser: '@typescript-eslint/parser', - - // Which files to not lint - ignorePatterns: [ - 'test/fixtures', - 'node_modules' - ], - - parserOptions: { - // Allows for the parsing of modern ECMAScript features - ecmaVersion: 2020, - // Allows for the use of imports - sourceType: 'module', - }, - - plugins: ["mocha"], - - // The base rules this project extends from - extends: [ - // Uses the recommended rules from the @typescript-eslint/eslint-plugin - 'plugin:@typescript-eslint/recommended', - 'plugin:prettier/recommended', - ], - // Rules in addition to the base - rules: { - // Eslint overrides - 'curly': ['error', 'all'], - 'quotes': ['error', 'single', { avoidEscape: true }], - 'max-lines-per-function': ['error', 60], - - // Typescript overrides - // '@typescript-eslint/no-empty-function': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'error', - '@typescript-eslint/no-explicit-any': 'off', - "@typescript-eslint/explicit-function-return-type": ["error", { "allowExpressions": true }], - '@typescript-eslint/no-unused-vars': [ - 'error', - { vars: 'all', args: 'none', ignoreRestSiblings: false }, - ], - }, - overrides: [ - { - files: ['**/*.spec.ts'], - rules: { - 'max-lines-per-function': 'off', - "mocha/no-exclusive-tests": "error", - }, - }, - ], -}; diff --git a/.github/workflows/build-node.yml b/.github/workflows/build-node.yml index f2bfe55..dcb47e8 100644 --- a/.github/workflows/build-node.yml +++ b/.github/workflows/build-node.yml @@ -29,7 +29,11 @@ jobs: build: strategy: matrix: - node-version: ['18.x', '20.x', '22.x'] + node-version: + - '18.x' + - '20.x' + - '22.x' + - '24.x' runs-on: - ubuntu-latest @@ -41,12 +45,14 @@ jobs: uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: 'npm' - - run: npm ci - - run: npm run build - - run: npm run test - - run: npm run lint + - name: Install, build, lint, test + run: | + npm ci + npm run build + npm test + npm run lint diff --git a/Dockerfile b/Dockerfile index 8845c0c..0e16326 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:22 AS build +FROM node:24 AS build WORKDIR /opt @@ -12,7 +12,7 @@ COPY ./src ./src RUN npm run build --ignore-scripts -- -p ./tsconfig.defs.json -FROM node:22-alpine AS runtime +FROM node:24-alpine AS runtime WORKDIR /opt diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..cee7603 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,25 @@ +// eslint.config.js or eslint.config.mjs for compat +import { default as acrLint } from '@acrontum/eslint-config'; + +export default [ + { ignores: ['test/fixtures', '**/node_modules', 'dist/'] }, + { + files: ['**/*.spec.ts'], + rules: { + 'max-lines-per-function': 'off', + }, + }, + ...acrLint, + { + files: ['src/cli.ts', 'src/util/logger.ts'], + rules: { + 'no-console': 'off', + }, + }, + { + files: ['**/*.ts'], + rules: { + '@typescript-eslint/restrict-template-expressions': ['error', { allowBoolean: true, allowNumber: true, }], + }, + }, +]; diff --git a/package-lock.json b/package-lock.json index 2bec1f2..8890da4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,35 +12,52 @@ "moxy": "dist/src/cli.js" }, "devDependencies": { + "@acrontum/eslint-config": "^1.2.1", "@tsconfig/node18": "^18.2.4", - "@types/chai": "^4.3.1", - "@types/chai-as-promised": "^7.1.5", - "@types/mocha": "^9.1.1", - "@types/node": "^16.10.3", - "@types/supertest": "^2.0.12", - "@typescript-eslint/eslint-plugin": "^5.20.0", - "@typescript-eslint/parser": "^5.20.0", - "chai": "^4.3.6", - "chai-as-promised": "^7.1.1", - "eslint": "^8.14.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-mocha": "^10.0.3", - "eslint-plugin-prettier": "^4.0.0", - "mocha": "^9.2.2", - "prettier": "^2.6.2", + "@types/node": "^24.10.9", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^8.23.0", + "@typescript-eslint/parser": "^8.23.0", + "eslint": "^9.19.0", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-prettier": "^5.2.3", + "prettier": "^3.4.2", "source-map-support": "^0.5.21", - "supertest": "^6.3.4", - "typedoc": "^0.27.2", - "typescript": "^5.7.2" + "supertest": "^7.0.0", + "typedoc": "^0.27.6", + "typescript": "^5.7.3" }, "engines": { "node": ">=18" } }, + "node_modules/@acrontum/eslint-config": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@acrontum/eslint-config/-/eslint-config-1.2.3.tgz", + "integrity": "sha512-tUcjbM3XqkxlEkH1AJHLc2kE8VSDSE9+2aJZWtlm6ASSQJ2ECysQtqz+hRfFjKGDb77RYIaSfbGbBvsi8Bmudw==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "@eslint/eslintrc": ">= 3.1.0", + "@eslint/js": ">= 9.5.0", + "@typescript-eslint/eslint-plugin": ">= 7", + "@typescript-eslint/parser": ">= 7", + "eslint": ">= 7", + "eslint-config-prettier": ">= 7", + "eslint-plugin-no-only-tests": ">= 3", + "eslint-plugin-prettier": ">= 5", + "prettier": ">= 3" + }, + "peerDependenciesMeta": { + "@eslint/eslintrc": { + "optional": true + } + } + }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -57,47 +74,175 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true, "license": "MIT", + "peer": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@gerrit0/mini-shiki": { @@ -112,20 +257,28 @@ "@shikijs/vscode-textmate": "^10.0.1" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { - "node": ">=10.10.0" + "node": ">=18.18.0" } }, "node_modules/@humanwhocodes/module-importer": { @@ -142,50 +295,54 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, - "license": "BSD-3-Clause" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "dev": true, "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, "engines": { - "node": ">= 8" + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@paralleldrive/cuid2": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", + "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 8" + "dependencies": { + "@noble/hashes": "^1.1.5" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "dev": true, "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, "engines": { - "node": ">= 8" + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" } }, "node_modules/@shikijs/engine-oniguruma": { @@ -211,36 +368,19 @@ } }, "node_modules/@shikijs/vscode-textmate": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.1.tgz", - "integrity": "sha512-fTIQwLF+Qhuws31iw7Ncl1R3HUDtGwIipiJ9iU+UsDUwMhegFcQKQHd51nZjb7CArq0MvON8rbgCGQYWHUKAdg==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node18": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.4.tgz", - "integrity": "sha512-5xxU8vVs9/FNcvm3gE07fPbn9tl6tqGGWA9tSlwsUEkBxtRnTsNmwrV8gasZ9F/EobaSv9+nu8AxUKccw77JpQ==", + "version": "18.2.6", + "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.6.tgz", + "integrity": "sha512-eAWQzAjPj18tKnDzmWstz4OyWewLUNBm9tdoN9LayzoboRktYx3Enk1ZXPmThj55L7c4VWYq/Bzq0A51znZfhw==", "dev": true, "license": "MIT" }, - "node_modules/@types/chai": { - "version": "4.3.20", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", - "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/chai-as-promised": { - "version": "7.1.8", - "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", - "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/chai": "*" - } - }, "node_modules/@types/cookiejar": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", @@ -248,6 +388,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -272,26 +419,15 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/mocha": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", - "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/node": { - "version": "16.18.126", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.126.tgz", - "integrity": "sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==", + "version": "24.10.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.9.tgz", + "integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==", "dev": true, - "license": "MIT" - }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } }, "node_modules/@types/superagent": { "version": "8.1.9", @@ -307,13 +443,14 @@ } }, "node_modules/@types/supertest": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.16.tgz", - "integrity": "sha512-6c2ogktZ06tr2ENoZivgm7YnprnhYE4ZoXGMY+oA7IuAf17M8FWvujXZGmxLv8y0PTyts4x5A+erSwVUFA8XSg==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.3.tgz", + "integrity": "sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==", "dev": true, "license": "MIT", "dependencies": { - "@types/superagent": "*" + "@types/methods": "^1.1.4", + "@types/superagent": "^8.1.0" } }, "node_modules/@types/unist": { @@ -324,122 +461,151 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", - "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.1.tgz", + "integrity": "sha512-cFYYFZ+oQFi6hUnBTbLRXfTJiaQtYE3t4O692agbBl+2Zy+eqSKWtPjhPXJu1G7j4RLjKgeJPDdq3EqOwmX5Ag==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/type-utils": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.53.1", + "@typescript-eslint/type-utils": "8.53.1", + "@typescript-eslint/utils": "8.53.1", + "@typescript-eslint/visitor-keys": "8.53.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@typescript-eslint/parser": "^8.53.1", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", - "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.53.1.tgz", + "integrity": "sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", + "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "debug": "^4.3.4" + "@typescript-eslint/scope-manager": "8.53.1", + "@typescript-eslint/types": "8.53.1", + "@typescript-eslint/typescript-estree": "8.53.1", + "@typescript-eslint/visitor-keys": "8.53.1", + "debug": "^4.4.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.53.1.tgz", + "integrity": "sha512-WYC4FB5Ra0xidsmlPb+1SsnaSKPmS3gsjIARwbEkHkoWloQmuzcfypljaJcR78uyLA1h8sHdWWPHSLDI+MtNog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.53.1", + "@typescript-eslint/types": "^8.53.1", + "debug": "^4.4.3" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.53.1.tgz", + "integrity": "sha512-Lu23yw1uJMFY8cUeq7JlrizAgeQvWugNQzJp8C3x8Eo5Jw5Q2ykMdiiTB9vBVOOUBysMzmRRmUfwFrZuI2C4SQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" + "@typescript-eslint/types": "8.53.1", + "@typescript-eslint/visitor-keys": "8.53.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.53.1.tgz", + "integrity": "sha512-qfvLXS6F6b1y43pnf0pPbXJ+YoXIC7HKg0UGZ27uMIemKMKA6XH2DTxsEDdpdN29D+vHV07x/pnlPNVLhdhWiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", - "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.53.1.tgz", + "integrity": "sha512-MOrdtNvyhy0rHyv0ENzub1d4wQYKb2NmIqG7qEqPWFW7Mpy2jzFC3pQ2yKDvirZB7jypm5uGjF2Qqs6OIqu47w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" + "@typescript-eslint/types": "8.53.1", + "@typescript-eslint/typescript-estree": "8.53.1", + "@typescript-eslint/utils": "8.53.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.53.1.tgz", + "integrity": "sha512-jr/swrr2aRmUAUjW5/zQHbMaui//vQlsZcJKijZf3M26bnmLj8LyZUpj8/Rd6uzaek06OWsqdofN/Thenm5O8A==", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -447,98 +613,95 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.53.1.tgz", + "integrity": "sha512-RGlVipGhQAG4GxV1s34O91cxQ/vWiHJTDHbXRr0li2q/BGg3RR/7NM8QDWgkEgrwQYCvmJV9ichIwyoKCQ+DTg==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "@typescript-eslint/project-service": "8.53.1", + "@typescript-eslint/tsconfig-utils": "8.53.1", + "@typescript-eslint/types": "8.53.1", + "@typescript-eslint/visitor-keys": "8.53.1", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.53.1.tgz", + "integrity": "sha512-c4bMvGVWW4hv6JmDUEG7fSYlWOl3II2I4ylt0NM+seinYQlZMQIaKaXIIVJWt9Ofh6whrpM+EdDQXKXjNovvrg==", "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.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.53.1", + "@typescript-eslint/types": "8.53.1", + "@typescript-eslint/typescript-estree": "8.53.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.53.1.tgz", + "integrity": "sha512-oy+wV7xDKFPRyNggmXuZQSBzvoLnpmJs+GhzRhPjrxl2b/jIlyjVokzm47CZCDUdXKr2zd7ZLodPfOBpOPyPlg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "8.53.1", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "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/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, - "license": "ISC" + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -573,26 +736,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -609,20 +752,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -630,16 +759,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/array-union": { - "version": "2.1.0", - "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" - } - }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -647,16 +766,6 @@ "dev": true, "license": "MIT" }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -668,53 +777,19 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } + "dev": true, + "license": "MIT" }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" + "balanced-match": "^1.0.0" } }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true, - "license": "ISC" - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -723,9 +798,9 @@ "license": "MIT" }, "node_modules/call-bind-apply-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", - "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -737,14 +812,14 @@ } }, "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -763,51 +838,6 @@ "node": ">=6" } }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chai": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", - "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chai-as-promised": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", - "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", - "dev": true, - "license": "WTFPL", - "dependencies": { - "check-error": "^1.0.2" - }, - "peerDependencies": { - "chai": ">= 2.1.2 < 6" - } - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -825,72 +855,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -941,6 +905,16 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, "node_modules/cookiejar": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", @@ -964,9 +938,9 @@ } }, "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { @@ -981,32 +955,6 @@ } } }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -1035,42 +983,6 @@ "wrappy": "1" } }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -1086,13 +998,6 @@ "node": ">= 0.4" } }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -1139,14 +1044,20 @@ "node": ">= 0.4" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, "engines": { - "node": ">=6" + "node": ">= 0.4" } }, "node_modules/escape-string-regexp": { @@ -1163,156 +1074,141 @@ } }, "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-config-prettier": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", - "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, "peerDependencies": { "eslint": ">=7.0.0" } }, - "node_modules/eslint-plugin-mocha": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.5.0.tgz", - "integrity": "sha512-F2ALmQVPT1GoP27O1JTZGrV9Pqg8k79OeIuvw63UxMtQKREZtmkK1NFgkZQ2TW7L2JSSFKHFPTtHu5z8R9QNRw==", + "node_modules/eslint-plugin-no-only-tests": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-3.3.0.tgz", + "integrity": "sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==", "dev": true, "license": "MIT", - "dependencies": { - "eslint-utils": "^3.0.0", - "globals": "^13.24.0", - "rambda": "^7.4.0" - }, + "peer": true, "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "eslint": ">=7.0.0" + "node": ">=5.0.0" } }, "node_modules/eslint-plugin-prettier": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", - "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "version": "5.5.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", + "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "prettier-linter-helpers": "^1.0.0" + "prettier-linter-helpers": "^1.0.1", + "synckit": "^0.11.12" }, "engines": { - "node": ">=12.0.0" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" }, "peerDependencies": { - "eslint": ">=7.28.0", - "prettier": ">=2.0.0" + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" }, "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, "eslint-config-prettier": { "optional": true } } }, "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==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^2.0.0" + "estraverse": "^5.2.0" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10" + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { @@ -1328,55 +1224,88 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "engines": { - "node": ">=4.0" + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -1386,16 +1315,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -1409,7 +1328,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -1419,16 +1338,6 @@ "node": ">=4.0" } }, - "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/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -1449,39 +1358,9 @@ "node_modules/fast-diff": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", @@ -1504,40 +1383,35 @@ "dev": true, "license": "MIT" }, - "node_modules/fastq": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", - "integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "flat-cache": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=16.0.0" } }, "node_modules/find-up": { @@ -1557,47 +1431,38 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", - "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, "license": "ISC" }, "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -1605,43 +1470,23 @@ } }, "node_modules/formidable": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", - "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", + "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", "dev": true, "license": "MIT", "dependencies": { + "@paralleldrive/cuid2": "^2.2.2", "dezalgo": "^1.0.4", - "hexoid": "^1.0.0", - "once": "^1.4.0", - "qs": "^6.11.0" + "once": "^1.4.0" + }, + "engines": { + "node": ">=14.0.0" }, "funding": { "url": "https://ko-fi.com/tunnckoCore/commissions" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -1652,39 +1497,19 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/get-intrinsic": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", - "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", + "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "get-proto": "^1.0.0", + "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", @@ -1711,28 +1536,6 @@ "node": ">= 0.4" } }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -1747,37 +1550,13 @@ } }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1796,23 +1575,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "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-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1836,43 +1598,39 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "license": "MIT", - "bin": { - "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==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, "license": "MIT", "engines": { @@ -1906,38 +1664,6 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1948,16 +1674,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -1971,49 +1687,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2022,9 +1695,9 @@ "license": "ISC" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -2112,33 +1785,6 @@ "dev": true, "license": "MIT" }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.1" - } - }, "node_modules/lunr": { "version": "2.3.9", "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", @@ -2181,16 +1827,6 @@ "dev": true, "license": "MIT" }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -2201,20 +1837,6 @@ "node": ">= 0.6" } }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -2238,128 +1860,33 @@ "node": ">= 0.6" } }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", - "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", - "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", - "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", - "ms": "2.1.3", - "nanoid": "3.3.1", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.2.0", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "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/minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "mime-db": "1.52.0" }, "engines": { - "node": ">=10" + "node": ">= 0.6" } }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "has-flag": "^4.0.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/ms": { @@ -2369,19 +1896,6 @@ "dev": true, "license": "MIT" }, - "node_modules/nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", - "dev": true, - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -2389,27 +1903,10 @@ "dev": true, "license": "MIT" }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true, - "license": "MIT" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-inspect": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", - "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, "license": "MIT", "engines": { @@ -2502,16 +1999,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -2522,34 +2009,15 @@ "node": ">=8" } }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -2566,25 +2034,26 @@ } }, "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", + "peer": true, "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", "dev": true, "license": "MIT", "dependencies": { @@ -2615,9 +2084,9 @@ } }, "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -2630,67 +2099,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/rambda": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/rambda/-/rambda-7.5.0.tgz", - "integrity": "sha512-y/M9weqWAH4iopRd7EHDEQQvpFPHj1AA3oHozE9tfITHUtTR7Z9PSlIRRG2l1GuW7sefC1cXFfIcF+cgnShdBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2701,83 +2109,10 @@ "node": ">=4" } }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, "license": "ISC", "bin": { @@ -2787,16 +2122,6 @@ "node": ">=10" } }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2896,16 +2221,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -2927,34 +2242,6 @@ "source-map": "^0.6.0" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -2969,40 +2256,39 @@ } }, "node_modules/superagent": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", - "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", - "deprecated": "Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.3.0.tgz", + "integrity": "sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==", "dev": true, "license": "MIT", "dependencies": { - "component-emitter": "^1.3.0", + "component-emitter": "^1.3.1", "cookiejar": "^2.1.4", - "debug": "^4.3.4", + "debug": "^4.3.7", "fast-safe-stringify": "^2.1.1", - "form-data": "^4.0.0", - "formidable": "^2.1.2", + "form-data": "^4.0.5", + "formidable": "^3.5.4", "methods": "^1.1.2", "mime": "2.6.0", - "qs": "^6.11.0", - "semver": "^7.3.8" + "qs": "^6.14.1" }, "engines": { - "node": ">=6.4.0 <13 || >=14" + "node": ">=14.18.0" } }, "node_modules/supertest": { - "version": "6.3.4", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.4.tgz", - "integrity": "sha512-erY3HFDG0dPnhw4U+udPfrzXa4xhSG+n4rxfRuZWCUvjFWwKl+OxWf/7zk50s84/fAAs7vf5QAb9uRa0cCykxw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.2.2.tgz", + "integrity": "sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==", "dev": true, "license": "MIT", "dependencies": { + "cookie-signature": "^1.2.2", "methods": "^1.1.2", - "superagent": "^8.1.2" + "superagent": "^10.3.0" }, "engines": { - "node": ">=6.4.0" + "node": ">=14.18.0" } }, "node_modules/supports-color": { @@ -3018,47 +2304,50 @@ "node": ">=8" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/synckit": { + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", "dev": true, "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "@pkgr/core": "^0.2.9" }, "engines": { - "node": ">=8.0" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" } }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "license": "0BSD" - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, "license": "MIT", "dependencies": { - "tslib": "^1.8.1" + "fdir": "^6.5.0", + "picomatch": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/ts-api-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" }, "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + "typescript": ">=4.8.4" } }, "node_modules/type-check": { @@ -3074,33 +2363,10 @@ "node": ">= 0.8.0" } }, - "node_modules/type-detect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", - "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "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" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typedoc": { - "version": "0.27.6", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.27.6.tgz", - "integrity": "sha512-oBFRoh2Px6jFx366db0lLlihcalq/JzyCVp7Vaq1yphL/tbgx2e+bkpkCgJPunaPvPwoTOXSwasfklWHm7GfAw==", + "version": "0.27.9", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.27.9.tgz", + "integrity": "sha512-/z585740YHURLl9DN2jCWe6OW7zKYm6VoQ93H0sxZ1cwHQEQrUn5BJrEnkWhfzUdyO+BLGjnKUZ9iz9hKloFDw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -3117,41 +2383,16 @@ "node": ">= 18" }, "peerDependencies": { - "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x" - } - }, - "node_modules/typedoc/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, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/typedoc/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x" } }, "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3167,6 +2408,13 @@ "dev": true, "license": "MIT" }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -3203,31 +2451,6 @@ "node": ">=0.10.0" } }, - "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" - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -3235,72 +2458,20 @@ "dev": true, "license": "ISC" }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, "node_modules/yaml": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", - "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { - "node": ">= 14" - } - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" + "node": ">= 14.6" }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yocto-queue": { diff --git a/package.json b/package.json index 82c6ca4..1920f09 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "docs-readme": "npx doctoc --github readme.md && sed -i 's/%5C_/_/g' readme.md", "docs-changelog": "npx auto-changelog --output changelog.md --commit-limit false --sort-commits date --hide-empty-releases --ignore-commit-pattern 'acrontum/release' --breaking-pattern 'breaking change: '", "lint": "eslint '{src,test}/**/*.{js,ts,json}'", - "test": "NODE_ENV=test mocha --require source-map-support/register --recursive 'dist/test/**/*.spec.js'", + "test": "NODE_ENV=test node --test --require source-map-support/register dist/test/*.spec.js", "prepublishOnly": "./githooks/pre-push" }, "bin": { @@ -35,26 +35,20 @@ }, "homepage": "https://github.com/acrontum/moxy#readme", "devDependencies": { + "@acrontum/eslint-config": "^1.2.1", "@tsconfig/node18": "^18.2.4", - "@types/chai": "^4.3.1", - "@types/chai-as-promised": "^7.1.5", - "@types/mocha": "^9.1.1", - "@types/node": "^16.10.3", - "@types/supertest": "^2.0.12", - "@typescript-eslint/eslint-plugin": "^5.20.0", - "@typescript-eslint/parser": "^5.20.0", - "chai": "^4.3.6", - "chai-as-promised": "^7.1.1", - "eslint": "^8.14.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-mocha": "^10.0.3", - "eslint-plugin-prettier": "^4.0.0", - "mocha": "^9.2.2", - "prettier": "^2.6.2", + "@types/node": "^24.10.9", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^8.23.0", + "@typescript-eslint/parser": "^8.23.0", + "eslint": "^9.19.0", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-prettier": "^5.2.3", + "prettier": "^3.4.2", "source-map-support": "^0.5.21", - "supertest": "^6.3.4", - "typedoc": "^0.27.2", - "typescript": "^5.7.2" + "supertest": "^7.0.0", + "typedoc": "^0.27.6", + "typescript": "^5.7.3" }, "engines": { "node": ">=18" diff --git a/src/cli.ts b/src/cli.ts index bff0fb1..eec4437 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,9 +1,9 @@ #!/usr/bin/env node -import { realpathSync } from 'fs'; -import { PathConfig } from './router'; -import { MoxyServer, ServerConfig } from './server'; +import { realpathSync } from 'node:fs'; import { version } from '../package.json'; +import { PathConfig } from './router/router'; +import { MoxyServer, ServerConfig } from './server/moxy-server'; export interface CliConfig { options: ServerConfig; @@ -36,7 +36,6 @@ export const assertNextArg = (name: string, argv: string[]): string => { return next; }; -/* eslint-disable-next-line max-lines-per-function */ export const getOption = (config: CliConfig, argv?: string[]): number => { if (!argv?.length) { return 0; @@ -62,7 +61,7 @@ export const getOption = (config: CliConfig, argv?: string[]): number => { config.routerFolders.push( ...assertNextArg(arg, argv) .split(',') - .map((f) => realpathSync(f)) + .map((f) => realpathSync(f)), ); break; @@ -74,7 +73,7 @@ export const getOption = (config: CliConfig, argv?: string[]): number => { const newlineRemoved = next.replace(/([^\\])\\n/g, '$1'); config.configs.push(JSON.parse(newlineRemoved) as { path: string; config: PathConfig }); } catch (e) { - throw new Error(`Error parsing --on argument: '${next}'\n${(e as Error)?.message}`); + throw new Error(`Error parsing --on argument: '${next}'\n${(e as Error | undefined)?.message}`); } break; @@ -90,11 +89,12 @@ export const getOption = (config: CliConfig, argv?: string[]): number => { case '-a': case '--allow-http-config': + config.options.router ||= {}; config.options.router.allowHttpRouteConfig = true; break; default: - throw new Error(`Unknown option -- ${arg}\n${usage}`); + throw new Error(`Unknown option -- ${arg || 'empty'}\n${usage}`); } return argv.length; @@ -131,7 +131,7 @@ export const main = async (argv?: string[]): Promise => { }; if (require.main === module) { - main(process.argv.slice(2)).catch((error: Error) => { + main(process.argv.slice(2)).catch((error: unknown) => { console.error(error); process.exit(1); }); diff --git a/src/index.ts b/src/index.ts index f10195a..41a976f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,9 @@ +export * from './server/moxy-server'; +export * from './server/request'; +export * from './server/response'; +export * from './router/router'; +export * from './util/format'; +export * from './util/http-exception'; +export * from './util/common-extensions'; +export * from './util/logger'; export * from './cli'; -export * from './router'; -export * from './server'; -export * from './util'; diff --git a/src/router/index.ts b/src/router/index.ts deleted file mode 100644 index 668a21f..0000000 --- a/src/router/index.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { OutgoingHttpHeaders } from 'http'; -import { RequestOptions } from 'https'; -import { MoxyRequest, MoxyResponse, MoxyServer } from '..'; - -/** - * Path and query params - */ -export type HandlerVariables = Record; - -/** - * Common http verbs - */ -export type Method = 'connect' | 'delete' | 'get' | 'head' | 'options' | 'patch' | 'post' | 'put' | 'trace'; - -/** - * Manual request handler - */ -export type RequestHandler = ( - req: MoxyRequest, - res: MoxyResponse, - variables: HandlerVariables, - server: MoxyServer -) => void; - -export interface PathSettings { - /** - * If set, will proxy all requests to the target - */ - proxy?: string; - /** - * Options to pass through proxy - */ - proxyOptions?: RequestOptions; - /** - * Method-level delay (in milliseconds) - */ - delay?: number; - /** - * If true, will not parse route as regex - */ - exact?: true; -} - -export interface MethodSettings extends PathSettings { - /** - * status code to return (defaults to 200) - */ - status?: number; - /** - * response payload - */ - body?: any; - /** - * headers to add (Content-Type is added automatically) - */ - headers?: OutgoingHttpHeaders; - /** - * HTTP request handler function - */ - handler?: RequestHandler; -} - -/** - * Configuration for a method. - * Would be configured as { get: MethodConfig, post: MethodConfig, ... } - * - * examples - * - * Standard http response: - * { - * status: 200, - * body: { message: 'hello' }, - * } - * - * Manual request listener method: - * async (req, res, vars) => res.sendJson({ url: req.url, date: Date.now() }, { status: 201 }); - * - * Static file: - * '/static/:file' - * - */ -export type MethodConfig = MethodSettings | string | RequestHandler; - -/** - * Configuration for a path. - */ -export type PathConfig = PathSettings & { all?: MethodConfig } & { [key in Method]?: MethodConfig }; - -/** - * Configuration for a route. - */ -export type RouteConfig = string | RequestHandler | PathConfig; - -/** - * Configuration for multiple routes. - */ -export type Routes = Record; - -export * from './router'; diff --git a/src/router/router.ts b/src/router/router.ts index b245d0c..544d8bf 100644 --- a/src/router/router.ts +++ b/src/router/router.ts @@ -1,19 +1,108 @@ import * as http from 'http'; import * as https from 'https'; -import { posix } from 'path'; -import { URL } from 'url'; -import { MoxyRequest, MoxyResponse, MoxyServer } from '../server'; -import { HttpException, Logger, formatRouteResponse, formatRoutesForPrinting } from '../util'; -import { - HandlerVariables, - Method, - MethodConfig, - MethodSettings, - PathConfig, - PathSettings, - RouteConfig, - Routes, -} from './index'; +import { ClientRequest, OutgoingHttpHeaders } from 'node:http'; +import { posix } from 'node:path'; +import { URL } from 'node:url'; +import { MoxyServer } from '../server/moxy-server'; +import { MoxyRequest } from '../server/request'; +import { MoxyResponse } from '../server/response'; +import { formatRouteResponse, formatRoutesForPrinting } from '../util/format'; +import { HttpException } from '../util/http-exception'; +import { Logger } from '../util/logger'; + +/** + * Path and query params + */ +export type HandlerVariables = Record; + +/** + * Common http verbs + */ +export type Method = 'connect' | 'delete' | 'get' | 'head' | 'options' | 'patch' | 'post' | 'put' | 'trace'; + +/** + * Manual request handler + */ +export type RequestHandler = ( + req: MoxyRequest, + res: MoxyResponse, + variables: HandlerVariables, + server: MoxyServer, +) => unknown; + +export interface PathSettings { + /** + * If set, will proxy all requests to the target + */ + proxy?: string; + /** + * Options to pass through proxy + */ + proxyOptions?: https.RequestOptions; + /** + * Method-level delay (in milliseconds) + */ + delay?: number; + /** + * If true, will not parse route as regex + */ + exact?: true; +} + +export interface MethodSettings extends PathSettings { + /** + * status code to return (defaults to 200) + */ + status?: number; + /** + * response payload + */ + body?: unknown; + /** + * headers to add (Content-Type is added automatically) + */ + headers?: http.OutgoingHttpHeaders; + /** + * HTTP request handler function + */ + handler?: RequestHandler; +} + +/** + * Configuration for a method. + * Would be configured as { get: MethodConfig, post: MethodConfig, ... } + * + * examples + * + * Standard http response: + * { + * status: 200, + * body: { message: 'hello' }, + * } + * + * Manual request listener method: + * async (req, res, vars) => res.sendJson({ url: req.url, date: Date.now() }, { status: 201 }); + * + * Static file: + * '/static/:file' + * + */ +export type MethodConfig = MethodSettings | string | RequestHandler; + +/** + * Configuration for a path. + */ +export type PathConfig = PathSettings & { all?: MethodConfig } & { [key in Method]?: MethodConfig }; + +/** + * Configuration for a route. + */ +export type RouteConfig = string | RequestHandler | PathConfig; + +/** + * Configuration for multiple routes. + */ +export type Routes = Record; export interface RouterConfig { /** @@ -74,7 +163,7 @@ export class Router { * * @return {this} */ - addRoute(path: string, config: RouteConfig, options?: AddRouteOptions): this { + addRoute(path: string | null, config: RouteConfig | null, options?: AddRouteOptions): this { if (!path) { throw new HttpException('router.on must contain "path"', 422); } @@ -97,7 +186,10 @@ export class Router { this.routes[path] = { ...(compiledRoute as PathConfig) }; delete compiledRoute.urlRegex; } else { - this.routes[path] = { ...((this.routes[path] as PathConfig) || {}), ...(compiledRoute as PathConfig) }; + this.routes[path] = { + ...((this.routes[path] as PathConfig | undefined) || {}), + ...(compiledRoute as PathConfig), + }; delete compiledRoute.urlRegex; } @@ -129,6 +221,7 @@ export class Router { * @return {this} */ removeRoute(path: string): this { + /* eslint-disable-next-line @typescript-eslint/no-dynamic-delete */ delete this.routes[path]; this.routerPaths = Object.entries(this.routes); @@ -144,6 +237,10 @@ export class Router { * @return {Promise} */ async handleApi(req: MoxyRequest, res: MoxyResponse): Promise { + if (!req.path) { + return res.sendJson({ message: 'Not found', status: 404, headers: { 'X-Moxy-Error': 'Req path is undefined' } }); + } + const body = await req.getBody('json'); const { path, config } = body; const configPath = req.path.replace(/^\/_moxy\/routes/, ''); @@ -161,12 +258,16 @@ export class Router { } if (!this.options.allowHttpRouteConfig) { - return res.sendJson({ message: 'Not found', status: 404 }); + return res.sendJson({ + message: 'Not found', + status: 404, + headers: { 'X-Moxy-Error': 'Server not configurable over HTTP' }, + }); } switch (apiRoute) { case 'POST /_moxy/routes': - return this.#createApiRoute(req, res, path, config); + return this.#createApiRoute(req, res, path as string | null, config as RouteConfig | null); case `PATCH /_moxy/routes${configPath}`: return this.#updateApiRoute(res, configPath, body); @@ -193,8 +294,8 @@ export class Router { request: http.IncomingMessage, response: MoxyResponse, proxyUrl: string, - options?: https.RequestOptions - ): void { + options?: https.RequestOptions, + ): ClientRequest { const target = new URL(proxyUrl); const reqOptions: https.RequestOptions = { @@ -204,13 +305,13 @@ export class Router { path: `${target.pathname}${target.search}${target.hash}`, method: request.method, ...options, - headers: { ...request?.headers, ...options?.headers, Host: target.hostname }, + headers: { ...request.headers, ...(options?.headers as OutgoingHttpHeaders), Host: target.hostname }, }; const protocol = reqOptions.protocol === 'http:' ? http : https; const proxy = protocol.request(reqOptions, (proxyResponse) => { - response.writeHead(proxyResponse.statusCode, proxyResponse.headers); + response.writeHead(proxyResponse.statusCode || 500, proxyResponse.headers); proxyResponse.pipe(response, { end: true }); }); @@ -227,13 +328,15 @@ export class Router { proxy.on('timeout', () => { response.sendJson( { status: 504, message: 'Proxy timeout', options: reqOptions }, - { headers: { 'X-Moxy-Error': 'proxy timeout' } } + { headers: { 'X-Moxy-Error': 'proxy timeout' } }, ); request.destroy(); proxy.destroy(); }); request.pipe(proxy, { end: true }); + + return proxy; } /** @@ -242,21 +345,36 @@ export class Router { * @param {MoxyRequest} req The request * @param {MoxyResponse} res The resource * - * @return {Promise} + * @return {Promise} */ - async requestListener(req: MoxyRequest, res: MoxyResponse): Promise { - res.on('finish', () => this.#logger.log(`\n${formatRouteResponse(req, res)}`)); + async requestListener(req: MoxyRequest, res: MoxyResponse): Promise { + if (!req.url) { + return res.sendJson( + { message: 'Req parsing error', status: 500 }, + { headers: { 'X-Moxy-Error': 'Req URL is undefined' } }, + ); + } + if (!req.path) { + return res.sendJson( + { message: 'Req parsing error', status: 500 }, + { headers: { 'X-Moxy-Error': 'Req path is undefined' } }, + ); + } + + res.on('finish', () => { + this.#logger.log(`\n${formatRouteResponse(req, res)}`); + }); if (/^\/_moxy/.test(req.url)) { return await this.handleApi(req, res); } - for (const index in this.onceRouterPaths) { + for (let index = 0; index < this.onceRouterPaths.length; ++index) { const [url, routeConfig] = this.onceRouterPaths[index]; const response = await this.tryHandleRequest(req, res, url, routeConfig); if (response !== null) { - this.onceRouterPaths.splice(parseInt(index, 10), 1); + this.onceRouterPaths.splice(index, 1); return response; } @@ -300,56 +418,58 @@ export class Router { req: MoxyRequest, res: MoxyResponse, url: string, - routeConfig: ParsedPathConfig - ): Promise { + routeConfig: ParsedPathConfig, + ): Promise { const { methodConfig, proxySettings } = this.#parseRequestConfig(req, routeConfig); - let variables = req.query; + let variables: HandlerVariables = req.query; - if (typeof methodConfig === 'undefined' && !proxySettings && typeof routeConfig !== 'function') { + if (!methodConfig && !proxySettings && typeof routeConfig !== 'function') { + return null; + } + + if (!req.url) { return null; } if (routeConfig.urlRegex) { - const match: RegExpExecArray = routeConfig.urlRegex.exec(req.url); + const match = routeConfig.urlRegex.exec(req.url); routeConfig.urlRegex.lastIndex = 0; if (!match) { return null; } - variables = { ...match?.groups, ...req.query }; + variables = { ...match.groups, ...req.query }; } else if (url !== req.url && url !== req.path) { return null; } - await this.#delay(routeConfig?.delay); + await this.#delay(routeConfig.delay); if (typeof routeConfig === 'function') { - return routeConfig(req, res, variables, this.#server); + routeConfig(req, res, variables, this.#server); + return res; } if (typeof methodConfig === 'function') { - return methodConfig(req, res, variables, this.#server); + methodConfig(req, res, variables, this.#server); + return res; } if (typeof methodConfig === 'string') { return res.sendFile(this.#applyReplacements(methodConfig, variables)); } - if (proxySettings) { + if (proxySettings?.proxy) { await this.#delay(proxySettings.delay); - return this.createProxy( - req, - res, - this.#applyReplacements(proxySettings.proxy, variables), - proxySettings.proxyOptions - ); + this.createProxy(req, res, this.#applyReplacements(proxySettings.proxy, variables), proxySettings.proxyOptions); + return res; } await this.#delay(methodConfig?.delay); - return await this.#parseConfigRoute(res, methodConfig, variables); + return this.#parseConfigRoute(res, methodConfig, variables); } /** @@ -370,25 +490,25 @@ export class Router { /** * Extract configurations from incoming request * - * @param {MoxyRequest} req The request - * @param {ParsedPathConfig} routeConfig The route configuration + * @param {MoxyRequest} req The request + * @param {ParsedPathConfig | null} routeConfig The route configuration * * @return { methodConfig: MethodConfig; proxySettings: PathSettings } */ #parseRequestConfig( req: MoxyRequest, - routeConfig: ParsedPathConfig - ): { methodConfig: MethodConfig; proxySettings: PathSettings } { - const method = req.method?.toLowerCase?.() as Method; + routeConfig: ParsedPathConfig | null, + ): { methodConfig: MethodConfig | null; proxySettings: PathSettings | null } { + const method = req.method?.toLowerCase() as Method; const methodConfig = - (routeConfig as PathConfigWithOptions)?.[method] || (routeConfig as PathConfigWithOptions)?.all; + (routeConfig as PathConfigWithOptions)[method] || (routeConfig as PathConfigWithOptions).all || null; - let proxySettings: PathSettings = null; + let proxySettings: PathSettings | null = null; - if ((methodConfig as MethodSettings)?.proxy) { + if ((methodConfig as MethodSettings | null)?.proxy) { proxySettings = methodConfig as MethodSettings; - } else if ((routeConfig as MethodSettings)?.proxy) { - proxySettings = routeConfig as MethodSettings; + } else if (routeConfig?.proxy) { + proxySettings = routeConfig; } return { methodConfig, proxySettings }; @@ -403,27 +523,29 @@ export class Router { * * @return {Promise} */ - async #parseConfigRoute( + #parseConfigRoute( res: MoxyResponse, - methodConfig: MethodSettings, - variables: HandlerVariables - ): Promise { - const status = methodConfig.status ?? 200; - const headers: http.OutgoingHttpHeaders = methodConfig?.headers; + methodConfig: MethodSettings | null, + variables: HandlerVariables, + ): null | MoxyResponse { + const status = methodConfig?.status ?? 200; + const headers = methodConfig?.headers; - let body = methodConfig.body; + let body = methodConfig?.body; if (typeof body === 'object' && body !== null) { try { body = JSON.stringify(body); res.setHeader('Content-Type', 'application/json'); - } catch (e) {} + } catch (e) { + this.#logger.debug('failed to parse body', { body, e }); + } } body = this.#applyReplacements(body, variables); return res.writeHead(status, headers).end(body); } - async #delay(delay: number): Promise { + async #delay(delay?: number): Promise { if (!delay) { return; } @@ -442,7 +564,7 @@ export class Router { * * @return {string} */ - #applyReplacements(payload: string, variables: HandlerVariables): string { + #applyReplacements(payload: T, variables: HandlerVariables | null): T { if (!payload || typeof payload !== 'string') { return payload; } @@ -450,7 +572,7 @@ export class Router { const serialize = (value: string | string[]): string => (Array.isArray(value) ? JSON.stringify(value) : value); Object.entries(variables || {}).forEach(([varname, replacement]) => { - payload = payload.replace(new RegExp(`:${varname}`, 'g'), serialize(replacement)); + payload = (payload as string).replace(new RegExp(`:${varname}`, 'g'), serialize(replacement)) as T; }); return payload; @@ -475,7 +597,7 @@ export class Router { parsed = { get: config }; } - if (!options?.exact && !(config as PathConfig)?.exact) { + if (!options?.exact && !(config as PathConfig).exact) { const pathWithGroups = this.parsePlaceholderParams(fullPath); parsed.urlRegex = new RegExp(`^${pathWithGroups}(\\?.*)?$`, 'g'); } @@ -518,7 +640,7 @@ export class Router { */ #sendApiRoutes(req: MoxyRequest, res: MoxyResponse): MoxyResponse { return res.sendJson( - Object.keys(req.query.once === 'true' ? Object.fromEntries(this.onceRouterPaths) : this.routes) + Object.keys(req.query.once === 'true' ? Object.fromEntries(this.onceRouterPaths) : this.routes), ); } @@ -546,10 +668,10 @@ export class Router { * * @return {MoxyResponse} */ - #createApiRoute(req: MoxyRequest, res: MoxyResponse, path: string, config: RouteConfig): MoxyResponse { + #createApiRoute(req: MoxyRequest, res: MoxyResponse, path: string | null, config: RouteConfig | null): MoxyResponse { this.addRoute(path, config, { once: req.query.once === 'true' }); - let payload = { [path]: this.routes[path] }; + let payload = { [path as string]: this.routes[path as string] }; if (req.query.once === 'true') { payload = Object.fromEntries([this.onceRouterPaths[this.onceRouterPaths.length - 1]]); } @@ -566,7 +688,7 @@ export class Router { * * @return {MoxyResponse} */ - #updateApiRoute(res: MoxyResponse, path: string, body: Record): MoxyResponse { + #updateApiRoute(res: MoxyResponse, path: string, body: Record): MoxyResponse { if (!path || !this.routes[path]) { return res.sendJson({ message: 'Not found', status: 404 }); } @@ -580,17 +702,18 @@ export class Router { * * @param {MoxyResponse} res The respoonse * @param {string} path The path - * @param {Record} body The body + * @param {Record} body The body * * @return {MoxyResponse} */ - #createOrReplaceApiRoute(res: MoxyResponse, path: string, body: Record): MoxyResponse { + #createOrReplaceApiRoute(res: MoxyResponse, path: string, body: Record): MoxyResponse { if (!path) { return res.sendJson({ message: 'Not found', status: 404 }); } const status = this.routes[path] ? 200 : 201; + /* eslint-disable-next-line @typescript-eslint/no-dynamic-delete */ delete this.routes[path]; this.addRoute(path, body); @@ -606,6 +729,7 @@ export class Router { * @return {MoxyResponse} */ #deleteApiRoute(res: MoxyResponse, path: string): MoxyResponse { + /* eslint-disable-next-line @typescript-eslint/no-dynamic-delete */ delete this.routes[path]; this.routerPaths = Object.entries(this.routes); @@ -615,14 +739,14 @@ export class Router { /** * Hides parsed regex from response * - * @param {Routes} json The json + * @param {Routes} routes The router config object * * @return {string} */ #removeRouteRegex(routes: Routes): string { return JSON.stringify(routes, (key, value) => { if (key !== 'urlRegex') { - return value; + return value as unknown; } }); } diff --git a/src/server/index.ts b/src/server/index.ts deleted file mode 100644 index 19603ec..0000000 --- a/src/server/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './moxy-server'; -export * from './request'; -export * from './response'; diff --git a/src/server/moxy-server.ts b/src/server/moxy-server.ts index 13b0090..6b4f7f7 100644 --- a/src/server/moxy-server.ts +++ b/src/server/moxy-server.ts @@ -1,9 +1,11 @@ -import * as fs from 'fs'; -import { createServer, IncomingMessage, Server, ServerOptions, ServerResponse } from 'http'; -import { AddressInfo, Socket } from 'net'; -import { basename, join } from 'path'; -import { AddRouteOptions, RouteConfig, Router, RouterConfig, Routes } from '../router'; -import { getId, HttpException, Logger, LogLevels } from '../util'; +import * as fs from 'node:fs'; +import { createServer, IncomingMessage, Server, ServerOptions, ServerResponse } from 'node:http'; +import { AddressInfo, Socket } from 'node:net'; +import { basename, join } from 'node:path'; +import { AddRouteOptions, RouteConfig, Router, RouterConfig, Routes } from '../router/router'; +import { getId } from '../util/format'; +import { HttpException } from '../util/http-exception'; +import { Logger, LogLevel } from '../util/logger'; import { MoxyRequest } from './request'; import { MoxyResponse } from './response'; @@ -11,7 +13,7 @@ export interface ServerConfig { /** * Set log level */ - logging?: LogLevels; + logging?: LogLevel; /** * Configuration passed to router */ @@ -31,17 +33,17 @@ export class MoxyServer { /** * Instance of HTTP server */ - server?: MoxyHttpServer; + server: MoxyHttpServer | null = null; /** * The internal router */ router: Router; - #responses: Record; + #responses: { [key in string]?: MoxyResponse }; #logger: Logger; constructor(config?: ServerConfig) { - this.#logger = new Logger(process.env.MOXY_LOG || config?.logging || 'verbose'); + this.#logger = new Logger((process.env.MOXY_LOG as LogLevel | undefined) || config?.logging || 'verbose'); this.router = new Router(this.#logger, this, config?.router); this.#responses = {}; } @@ -52,20 +54,20 @@ export class MoxyServer { * @type {number} */ get port(): number { - return (this?.server?.address?.() as AddressInfo)?.port; + return (this.server?.address() as AddressInfo).port; } /** * Get current log level */ - get logLevel(): string { + get logLevel(): LogLevel { return this.#logger.level; } /** * Set current log level */ - set logLevel(value: string) { + set logLevel(value: LogLevel) { this.#logger.level = value; } @@ -151,7 +153,7 @@ export class MoxyServer { const files = await this.getFolderContents(path); while (files.length) { - const next = files.shift(); + const next = files.shift() as fs.Dirent; if (next.isDirectory()) { files.push(...(await this.getFolderContents(next.name))); @@ -192,7 +194,8 @@ export class MoxyServer { * @param {string} basePath The base path */ loadConfigFromFile(filePath: string, basePath: string): void { - let pathConfig: Record = require(filePath); // eslint-disable-line @typescript-eslint/no-var-requires + /* eslint-disable-next-line @typescript-eslint/no-require-imports */ + let pathConfig = require(filePath) as Record; const prefix = filePath.replace(`/${basename(filePath)}`, '').replace(basePath, ''); if (filePath.endsWith('.json')) { @@ -223,31 +226,34 @@ export class MoxyServer { ServerResponse: MoxyResponse, }; - this.server = createServer( + const server = createServer( options, - async (req: IncomingMessage, res: ServerResponse): Promise => { + /* eslint-disable-next-line @typescript-eslint/no-misused-promises */ + async (req: IncomingMessage, res: ServerResponse): Promise => { this.#responses[(req as MoxyRequest).id] = res as MoxyResponse; try { const response = await this.router.requestListener(req as MoxyRequest, res as MoxyResponse); + /* eslint-disable-next-line @typescript-eslint/no-dynamic-delete */ delete this.#responses[(req as MoxyRequest).id]; return response; } catch (error) { this.#handleUncaughtErrors(error as HttpException, res as MoxyResponse); } - } + }, ); + this.server = server; this.#createConnectionManager(); return new Promise((resolve, reject) => { - this.server.on('error', reject); + server.on('error', reject); - this.server.listen(port, () => { + server.listen(port, () => { this.#logger.log(`moxy up :${this.port}`); - return resolve(this.server); + resolve(server); }); }); } @@ -263,13 +269,22 @@ export class MoxyServer { return new Promise((resolve, reject) => { if (!this.server) { resolve(); + return; } if (options?.closeConnections) { this.server.emit('closeConnections'); } - this.server.close((error) => (error ? reject(error) : resolve((this.server = null)))); + this.server.close((error) => { + if (error) { + reject(error); + return; + } + this.server = null; + + resolve(); + }); }); } @@ -295,7 +310,7 @@ export class MoxyServer { const currentResponse = this.#responses[res.id]; if (currentResponse && !currentResponse.writableEnded) { - if (error?.status) { + if (error.status) { currentResponse.sendJson({ status: error.status, error: error.message }); } else { currentResponse.sendJson({ @@ -305,6 +320,7 @@ export class MoxyServer { } } + /* eslint-disable-next-line @typescript-eslint/no-dynamic-delete */ delete this.#responses[res.id]; } @@ -312,6 +328,10 @@ export class MoxyServer { * Configures connection management */ #createConnectionManager(): void { + if (!this.server) { + return; + } + const connections: Record = {}; this.server.on('connection', (socket) => { @@ -319,6 +339,7 @@ export class MoxyServer { connections[id] = socket; socket.on('close', () => { + /* eslint-disable-next-line @typescript-eslint/no-dynamic-delete */ delete connections[id]; }); }); diff --git a/src/server/request.ts b/src/server/request.ts index 15dd5f2..59109b5 100644 --- a/src/server/request.ts +++ b/src/server/request.ts @@ -1,8 +1,7 @@ import { IncomingMessage } from 'http'; import { Socket } from 'net'; -import { ParsedUrlQuery } from 'querystring'; -import { parse } from 'url'; -import { getId } from '../util'; +import { HandlerVariables } from '../router/router'; +import { getId } from '../util/format'; export class MoxyRequest extends IncomingMessage { /** @@ -14,9 +13,9 @@ export class MoxyRequest extends IncomingMessage { */ timestamp: number; - #query: ParsedUrlQuery; - #path: string; - #body: Promise; + #query?: HandlerVariables; + #path?: string; + #body?: Promise; constructor(socket: Socket) { super(socket); @@ -31,10 +30,12 @@ export class MoxyRequest extends IncomingMessage { get body(): Promise { if (!this.#body) { this.#body = new Promise((resolve) => { - const data: any[] = []; + const data: Uint8Array[] = []; - this.on('data', (chunk) => data.push(chunk)); - this.on('end', () => resolve(Buffer.concat(data))); + this.on('data', (chunk: Uint8Array) => data.push(chunk)); + this.on('end', () => { + resolve(Buffer.concat(data)); + }); }); } @@ -46,8 +47,14 @@ export class MoxyRequest extends IncomingMessage { * * @type {ParsedUrlQuery} */ - get query(): ParsedUrlQuery { - return this.#query || parse(this.url, true)?.query; + get query(): HandlerVariables { + if (this.#query) { + return this.#query; + } + if (this.url) { + return Object.fromEntries(new URL('http://example.com' + this.url).searchParams.entries()); + } + return {}; } /** @@ -55,7 +62,7 @@ export class MoxyRequest extends IncomingMessage { * * @type {string} */ - get path(): string { + get path(): string | undefined { return this.#path || this.url?.replace(/[?#].*/, ''); } @@ -66,16 +73,16 @@ export class MoxyRequest extends IncomingMessage { */ async getBody(format: 'buffer'): Promise; async getBody(format: 'string'): Promise; - async getBody(format: 'json'): Promise>; - async getBody(format?: 'buffer' | 'string' | 'json'): Promise> { + async getBody(format: 'json'): Promise>; + async getBody(format?: 'buffer' | 'string' | 'json'): Promise> { const payload = await this.body; if (format === 'string') { - return payload?.toString('utf8') ?? ''; + return (payload.toString('utf8') as string | null) ?? ''; } if (format === 'json') { - return JSON.parse((await this.body)?.toString('utf8') || '{}'); + return JSON.parse((await this.body).toString('utf8') || '{}') as Record; } return this.parseBody(await this.body); @@ -86,9 +93,9 @@ export class MoxyRequest extends IncomingMessage { * * @param {Buffer} body The body * - * @return {(Buffer | Record | string)} + * @return {(Buffer | Record | string)} */ - parseBody(body: Buffer): string | Buffer | Record { + parseBody(body: Buffer): string | Buffer | Record { const content = this.headers['Content-Type'] as string; if (!content) { @@ -96,11 +103,11 @@ export class MoxyRequest extends IncomingMessage { } if (/text\//.test(content)) { - return body?.toString('utf8'); + return body.toString('utf8'); } if (/application\/json/.test(content)) { - return JSON.parse(body?.toString('utf8') || '{}'); + return JSON.parse(body.toString('utf8') || '{}') as Record; } return body; diff --git a/src/server/response.ts b/src/server/response.ts index 46977ea..0fd0374 100644 --- a/src/server/response.ts +++ b/src/server/response.ts @@ -1,7 +1,7 @@ -import * as fs from 'fs'; -import { OutgoingHttpHeaders, ServerResponse } from 'http'; -import * as path from 'path'; -import { extToMimeType } from '../util'; +import * as fs from 'node:fs'; +import { OutgoingHttpHeaders, ServerResponse } from 'node:http'; +import * as path from 'node:path'; +import { extToMimeType } from '../util/common-extensions'; import { MoxyRequest } from './request'; export interface SendOptions { @@ -17,9 +17,9 @@ export class MoxyResponse extends ServerResponse { /** * Request duration in ms */ - duration: number; + duration?: number; - #chunks: any[] = []; + #chunks: Uint8Array[] = []; constructor(req: MoxyRequest) { super(req); @@ -34,23 +34,27 @@ export class MoxyResponse extends ServerResponse { /** * The response body * - * @type {(Buffer|Record|string)} + * @type {(Buffer|Record|string)} */ - get body(): string | Buffer | Record { + get body(): string | Buffer | Record { return this.parseBody(Buffer.concat(this.#chunks)); } /** * Sends a json response * - * @param {string|Record} json The json + * @param {string|Record} json The json * @param {SendOptions} options Reponse options * * @return {MoxyResponse} */ - sendJson(json: string | Record, options?: SendOptions): MoxyResponse { + sendJson(json: string | Record | unknown[], options?: SendOptions): this { if (typeof json !== 'string') { - options = { ...options, status: options?.status ?? json?.status }; + let status: number | null = options?.status ?? null; + if (!Array.isArray(json) && typeof json.status === 'number') { + status ??= json.status; + } + options = { ...options, status: status ?? 200 }; json = JSON.stringify(json); } @@ -68,7 +72,7 @@ export class MoxyResponse extends ServerResponse { * * @return {MoxyResponse} */ - sendFile(filename: string, options?: SendOptions): MoxyResponse { + sendFile(filename: string, options?: SendOptions): this { let filePath = path.join(process.cwd(), filename.replace(/\.\.\/?/g, '')); if (!fs.existsSync(filePath)) { @@ -113,10 +117,17 @@ export class MoxyResponse extends ServerResponse { * * @param {Record} headers The headers */ - setHeaders(headers: Record): void { - for (const [name, value] of Object.entries(headers)) { + setHeaders( + headers: + | Headers + | Map + | Record, + ): this { + for (const [name, value] of Object.entries(headers) as [string, number | string | readonly string[]][]) { this.setHeader(name, value); } + + return this; } /** @@ -124,9 +135,9 @@ export class MoxyResponse extends ServerResponse { * * @param {Buffer} body The body * - * @return {(Buffer|Record|string)} + * @return {(Buffer|Record|string)} */ - parseBody(body: Buffer): string | Buffer | Record { + parseBody(body: Buffer): string | Buffer | Record { const content = this.getHeader('Content-Type') as string; if (!content) { @@ -138,20 +149,22 @@ export class MoxyResponse extends ServerResponse { } if (/application\/json/.test(content)) { - return JSON.parse(body.toString('utf8')); + return JSON.parse(body.toString('utf8')) as Record; } + + return body; } /** * Override writablewrite to store body internally * * @param {string} chunk The chunk - * @param {any[]} args The arguments + * @param {unknown[]} args The arguments * * @return {boolean} */ - write(chunk: string, ...args: any[]): boolean { - const written = super.write(chunk, ...args); + write(chunk: string, ...args: unknown[]): boolean { + const written = super.write(chunk, ...(args as [])); this.#chunks.push(Buffer.from(chunk)); return written; @@ -160,13 +173,13 @@ export class MoxyResponse extends ServerResponse { /** * Overwrite writableend to store body internally * - * @param {any[]} args The arguments + * @param {unknown[]} args The arguments */ - end(...args: any[]): this { - super.end(...args); + end(...args: unknown[]): this { + super.end(...(args as [])); if (args[0]) { - this.#chunks.push(Buffer.from(args[0])); + this.#chunks.push(Buffer.from(args[0] as string)); } return this; diff --git a/src/util/format.ts b/src/util/format.ts index 1564a6b..5f12068 100644 --- a/src/util/format.ts +++ b/src/util/format.ts @@ -1,6 +1,7 @@ -import { randomUUID } from 'crypto'; -import { Method, Routes } from '../router'; -import { MoxyRequest, MoxyResponse } from '../server'; +import { randomUUID } from 'node:crypto'; +import { Method, Routes } from '../router/router'; +import { MoxyRequest } from '../server/request'; +import { MoxyResponse } from '../server/response'; export const colours = { red: '\x1b[31m', @@ -26,7 +27,7 @@ export const methodColours: Record = { }; export const formatMethod = (method: Method): string => - `${methodColours[method?.toLowerCase?.() as Method]}${method.toUpperCase()}\x1b[0m`; + `${methodColours[method.toLowerCase() as Method]}${method.toUpperCase()}\x1b[0m`; export const formatStatus = (status: number): string => { if (status >= 500) { @@ -47,9 +48,9 @@ export const formatStatus = (status: number): string => { return status.toString(); }; -export const formatBody = (body: string | Buffer | Record): string | Buffer => { +export const formatBody = (body: string | Buffer | Record): string | Buffer => { if (typeof body === 'string') { - return body?.length > 1500 ? `${body.slice(0, 1000)} ...` : body; + return body.length > 1500 ? `${body.slice(0, 1000)} ...` : body; } if (Buffer.isBuffer(body)) { @@ -58,7 +59,7 @@ export const formatBody = (body: string | Buffer | Record): string const json = JSON.stringify(body, null, 2); - return json?.length > 1500 ? `${json.slice(0, 1000)} ...` : json; + return json.length > 1500 ? `${json.slice(0, 1000)} ...` : json; }; export const formatRouteResponse = (req: MoxyRequest, res: MoxyResponse): string => { @@ -67,6 +68,7 @@ export const formatRouteResponse = (req: MoxyRequest, res: MoxyResponse): string `${colours.teal}${req.url}${colours.none}`, '=>', formatStatus(res.statusCode), + /* eslint-disable-next-line @typescript-eslint/restrict-template-expressions */ `\n${formatBody(res.body)}`, ].join(' '); }; @@ -87,4 +89,4 @@ export const formatRoutesForPrinting = (routes: Routes, expandFunction = true): }; export const getId: () => string = - typeof randomUUID === 'function' ? randomUUID : () => Math.round(Math.random() * 0xffffffffff).toString(36); + typeof randomUUID === 'function' ? randomUUID : (): string => Math.round(Math.random() * 0xffffffffff).toString(36); diff --git a/src/util/index.ts b/src/util/index.ts deleted file mode 100644 index 88d2d0c..0000000 --- a/src/util/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './common-extensions'; -export * from './format'; -export * from './http-exception'; -export * from './logger'; diff --git a/src/util/logger.ts b/src/util/logger.ts index a89fa23..8339ae9 100644 --- a/src/util/logger.ts +++ b/src/util/logger.ts @@ -1,56 +1,56 @@ -export type LogLevels = 'error' | 'off' | string; +export type LogLevel = 'off' | 'trace' | 'error' | 'warn' | 'info' | 'log' | 'verbose' | 'debug'; export class Logger { - level: LogLevels = 'verbose'; + level: LogLevel = 'verbose'; - constructor(level?: LogLevels) { - this.level = level; + constructor(level?: LogLevel) { + this.level = level || 'verbose'; } /** * Same as console.log. Will not log if level is 'error' or 'off' */ - log(...args: any[]): void { - return this.logIfEnabled('log', ...args); + log(...args: unknown[]): void { + this.logIfEnabled('log', ...args); } /** * Same as console.info. Will not log if level is 'error' or 'off' */ - info(...args: any[]): void { - return this.logIfEnabled('info', ...args); + info(...args: unknown[]): void { + this.logIfEnabled('info', ...args); } /** * Same as console.debug. Will not log if level is 'error' or 'off' */ - debug(...args: any[]): void { - return this.logIfEnabled('debug', ...args); + debug(...args: unknown[]): void { + this.logIfEnabled('debug', ...args); } /** * Same as console.warn. Will not log if level is 'error' or 'off' */ - warn(...args: any[]): void { - return this.logIfEnabled('warn', ...args); + warn(...args: unknown[]): void { + this.logIfEnabled('warn', ...args); } /** * Same as console.error. Will always log */ - error(...args: any[]): void { - return console.error(...args); + error(...args: unknown[]): void { + console.error(...args); } /** * Same as console.trace. Will always log */ - trace(...args: any[]): void { - return console.trace(...args); + trace(...args: unknown[]): void { + console.trace(...args); } - logIfEnabled(method: keyof typeof console, ...args: any[]): void { - if ((this.level as LogLevels) === 'off') { + logIfEnabled(method: keyof typeof console, ...args: unknown[]): void { + if (this.level === 'off') { return; } @@ -58,6 +58,6 @@ export class Logger { return; } - return console[method as 'log'](...args); + console[method as 'log'](...args); } } diff --git a/test/cli.spec.ts b/test/cli.spec.ts index 8c02d3b..f155f8f 100644 --- a/test/cli.spec.ts +++ b/test/cli.spec.ts @@ -1,27 +1,24 @@ -import { expect, use } from 'chai'; -import { default as chaiPromise } from 'chai-as-promised'; -import { afterEach } from 'mocha'; -import { join, relative } from 'path'; -import { default as supertest } from 'supertest'; +import assert from 'node:assert'; +import { join, relative } from 'node:path'; +import { afterEach, describe, it } from 'node:test'; import { formatRoutesForPrinting, main, MoxyServer, RouteConfig } from '../src'; +import { getRequest, TestRequest } from './shared/test-util'; -use(chaiPromise); - -describe(relative(process.cwd(), __filename), () => { +describe(relative(process.cwd(), __filename), async () => { let moxy: MoxyServer; - let request: supertest.SuperTest; + let request: TestRequest; - const start = async (argv: string[], assertions: (moxy: MoxyServer) => any): Promise => { + const start = async (argv: string[], assertions: (moxy: MoxyServer) => unknown): Promise => { moxy = await main(argv); await assertions(moxy); await moxy.close({ closeConnections: true }); }; afterEach(async () => { - await moxy?.close?.({ closeConnections: true }); + await moxy.close({ closeConnections: true }); }); - it('can start a server', async () => { + await it('can start a server', async () => { const oldLog = process.env.MOXY_LOG; process.env.MOXY_LOG = 'error'; @@ -32,10 +29,11 @@ describe(relative(process.cwd(), __filename), () => { delete process.env.MOXY_LOG; } - request = supertest(moxy.server); + request = getRequest(moxy); + await request.get('/_moxy').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ + assert.strictEqual(status, 200); + assert.deepStrictEqual(body, { 'GET /routes?once=false': 'show router routes', 'GET /router?once=false&serializeMethods=true': 'show router', }); @@ -44,34 +42,34 @@ describe(relative(process.cwd(), __filename), () => { await moxy.close({ closeConnections: true }); await start(['-q'], (server) => { - expect(server.logLevel).equals('error'); + assert.strictEqual(server.logLevel, 'error'); }); await start(['--quiet'], (server) => { - expect(server.logLevel).equals('error'); + assert.strictEqual(server.logLevel, 'error'); }); await start(['--quiet', '-q'], (server) => { - expect(server.logLevel).equals('error'); + assert.strictEqual(server.logLevel, 'error'); }); await start(['-q', '-p', '8521', '--port', '8521', '-a', '--allow-http-config'], (server) => { - expect(server.port).equals(8521); - expect(server.router.options.allowHttpRouteConfig).equals(true); + assert.strictEqual(server.port, 8521); + assert.strictEqual(server.router.options.allowHttpRouteConfig, true); }); - await expect(main(['-p', 'a1'])).is.rejectedWith('Error: invalid port a1'); + await assert.rejects(main(['-p', 'a1']), /Error: invalid port a1/); }); - it('can load routes on config', async () => { + await it('can load routes on config', async () => { const routes = join(__dirname, 'fixtures', 'load-from-dir'); const serializedDeleteFuntion = "delete(req, res) {\n return res.writeHead(301, 'google.ca');\n }"; await start(['-q', '-r', routes], (server) => { - const routerConfig = JSON.parse(formatRoutesForPrinting(server.router.routes)); + const routerConfig = JSON.parse(formatRoutesForPrinting(server.router.routes)) as unknown; - expect(routerConfig).deep.equals({ + assert.deepStrictEqual(routerConfig, { '/a/test': { get: { status: 200 } }, '/a/users/something': { delete: serializedDeleteFuntion }, '/a/y/test': { get: { status: 200 } }, @@ -110,9 +108,9 @@ describe(relative(process.cwd(), __filename), () => { }); await start(['-q', '--routes', routes], (server) => { - const routerConfig = JSON.parse(formatRoutesForPrinting(server.router.routes)); + const routerConfig = JSON.parse(formatRoutesForPrinting(server.router.routes)) as unknown; - expect(routerConfig).deep.equals({ + assert.deepStrictEqual(routerConfig, { '/a/test': { get: { status: 200 } }, '/a/users/something': { delete: serializedDeleteFuntion }, '/a/y/test': { get: { status: 200 } }, @@ -151,9 +149,9 @@ describe(relative(process.cwd(), __filename), () => { }); await start(['-q', '--routes', routes, '--routes', routes], (server) => { - const routerConfig = JSON.parse(formatRoutesForPrinting(server.router.routes)); + const routerConfig = JSON.parse(formatRoutesForPrinting(server.router.routes)) as unknown; - expect(routerConfig).deep.equals({ + assert.deepStrictEqual(routerConfig, { '/a/test': { get: { status: 200 } }, '/a/users/something': { delete: serializedDeleteFuntion }, '/a/y/test': { get: { status: 200 } }, @@ -199,7 +197,7 @@ describe(relative(process.cwd(), __filename), () => { }); await start(['-q', '-o', onFirstTest], (server) => { - expect(server.router.routes).deep.equals({ + assert.deepStrictEqual(server.router.routes, { '/test/this/path': { get: { status: 503 }, urlRegex: /^\/test\/this\/path(\?.*)?$/g }, }); }); @@ -219,7 +217,7 @@ describe(relative(process.cwd(), __filename), () => { }); await start(['-q', '-o', onFirstTest, '--on', onSecondTest, '-o', onSecondTestPartTwo], (server) => { - expect(server.router.routes).deep.equals({ + assert.deepStrictEqual(server.router.routes, { '/test/this/path': { get: { status: 503 }, urlRegex: /^\/test\/this\/path(\?.*)?$/g }, '/some/other/path': { get: { status: 503 }, @@ -229,4 +227,4 @@ describe(relative(process.cwd(), __filename), () => { }); }); }); -}); +}).catch(console.error); diff --git a/test/router.spec.ts b/test/router.spec.ts index 630ffa5..18ebaab 100644 --- a/test/router.spec.ts +++ b/test/router.spec.ts @@ -1,20 +1,28 @@ -import { expect } from 'chai'; -import { after, afterEach, before } from 'mocha'; -import { join, relative } from 'path'; -import { default as supertest } from 'supertest'; +import assert from 'node:assert'; +import { join, relative } from 'node:path'; +import { after, afterEach, before, describe, it } from 'node:test'; import { routeConfig } from '../examples/example-routing/example.routes'; import { MoxyServer, PathConfig, RequestHandler } from '../src'; +import { getRequest, TestRequest } from './shared/test-util'; -describe(relative(process.cwd(), __filename), () => { +type NetError = { + address: string; + code: string; + errno: number; + port: number; + syscall: string; +}; + +describe(relative(process.cwd(), __filename), async () => { const moxy: MoxyServer = new MoxyServer({ logging: 'error' }); - let request: supertest.SuperTest; + let request: TestRequest; before(async () => { await moxy.listen(); - request = supertest(moxy.server); + request = getRequest(moxy); }); - afterEach(async () => { + afterEach(() => { moxy.resetRoutes(); }); @@ -22,7 +30,7 @@ describe(relative(process.cwd(), __filename), () => { await moxy.close({ closeConnections: true }); }); - it('can configure routes', async () => { + await it('can configure routes', async (context) => { await request.get('/example-routing/12345/measurements/76543').expect(404); await request.get('/example-routing/static/image.png').expect(404); await request.post('/example-routing/auth/login').expect(404); @@ -36,16 +44,16 @@ describe(relative(process.cwd(), __filename), () => { await request.get('/example-routing/exact/match/handler?ignore=(.*)').expect(404); // change static file path in exampe from /public/ to /test/ - expect((routeConfig['/static/(?.*)'] as PathConfig).get).equals('/public/:file'); + assert.strictEqual((routeConfig['/static/(?.*)'] as PathConfig).get, '/public/:file'); (routeConfig['/static/(?.*)'] as PathConfig).get = '/test/:file'; // google proxy is slow-ish const proxy = new MoxyServer({ logging: 'error' }); proxy.on('/test\\?q=asdf', { get: { status: 418 } }); await proxy.listen(); - after(() => proxy.close({ closeConnections: true })); + context.after(() => proxy.close({ closeConnections: true })); - expect(routeConfig['proxied-server(?.*)'] as PathConfig).deep.equals({ + assert.deepStrictEqual(routeConfig['proxied-server(?.*)'] as PathConfig, { proxy: 'https://www.google.com:path', proxyOptions: { headers: { @@ -58,8 +66,8 @@ describe(relative(process.cwd(), __filename), () => { moxy.onAll('/example-routing', routeConfig); await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals([ + assert.strictEqual(status, 200); + assert.deepStrictEqual(body, [ '/example-routing/:machineId/measurements/:measurementId', '/example-routing/static/(?.*)', '/example-routing/assets/(?.*)', @@ -76,8 +84,8 @@ describe(relative(process.cwd(), __filename), () => { }); await request.get('/_moxy/router').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ + assert.strictEqual(status, 200); + assert.deepStrictEqual(body, { '/example-routing/:machineId/measurements/:measurementId': { get: { status: 200, @@ -178,15 +186,15 @@ describe(relative(process.cwd(), __filename), () => { await request.get('/example-routing/exact/match/handler?ignore=(.*)').expect(200); }); - it('can read filesystem for routing', async () => { + await it('can read filesystem for routing', async () => { await moxy.addRoutesFromFolder(join(__dirname, 'fixtures', 'load-from-dir')); const serializedDeleteFuntion = "delete(req, res) {\n return res.writeHead(301, 'google.ca');\n }"; await request.get('/_moxy/router').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ + assert.strictEqual(status, 200); + assert.deepStrictEqual(body, { '/a/test': { get: { status: 200 } }, '/a/users/something': { delete: serializedDeleteFuntion }, '/a/y/test': { get: { status: 200 } }, @@ -225,7 +233,7 @@ describe(relative(process.cwd(), __filename), () => { }); }); - it('can temporarily override a route', async () => { + await it('can temporarily override a route', async () => { await request.get('/hello/world').expect(404); moxy.on('/hello/world', { @@ -236,13 +244,13 @@ describe(relative(process.cwd(), __filename), () => { }); await request.get('/hello/world').expect(({ status, text }) => { - expect(status).equals(200); - expect(text).equals('hi!'); + assert.strictEqual(status, 200); + assert.strictEqual(text, 'hi!'); }); await request.get('/hello/world').expect(({ status, text }) => { - expect(status).equals(200); - expect(text).equals('hi!'); + assert.strictEqual(status, 200); + assert.strictEqual(text, 'hi!'); }); await request.post('/hello/world').expect(404); @@ -255,13 +263,13 @@ describe(relative(process.cwd(), __filename), () => { }); await request.get('/hello/world').expect(({ status, text }) => { - expect(status).equals(200); - expect(text).equals('hi!'); + assert.strictEqual(status, 200); + assert.strictEqual(text, 'hi!'); }); await request.post('/hello/world').expect(({ status, body }) => { - expect(status).equals(201); - expect(body).deep.equals({ message: 'welcome' }); + assert.strictEqual(status, 201); + assert.deepStrictEqual(body, { message: 'welcome' }); }); await request.post('/hello/world').expect(404); @@ -275,13 +283,13 @@ describe(relative(process.cwd(), __filename), () => { }); await request.get('/hello/world').expect(({ status, text }) => { - expect(status).equals(418); - expect(text).equals('easteregg'); + assert.strictEqual(status, 418); + assert.strictEqual(text, 'easteregg'); }); await request.get('/hello/world').expect(({ status, text }) => { - expect(status).equals(200); - expect(text).equals('hi!'); + assert.strictEqual(status, 200); + assert.strictEqual(text, 'hi!'); }); moxy.once('/hello/world', { get: { status: 400 } }); @@ -294,7 +302,7 @@ describe(relative(process.cwd(), __filename), () => { await request.get('/hello/world').expect(200); }); - it('can slow down requests', async () => { + await it('can slow down requests', async () => { moxy.on('/test', { get: { status: 200 }, post: { @@ -305,11 +313,11 @@ describe(relative(process.cwd(), __filename), () => { let start = Date.now(); await request.get('/test').expect(200); - expect(Date.now() - start < 50).equals(true); + assert.strictEqual(Date.now() - start < 50, true); start = Date.now(); await request.post('/test').expect(201); - expect(Date.now() - start >= 50).equals(true); + assert.strictEqual(Date.now() - start >= 50, true); moxy.on('/top-level-delay', { delay: 50, @@ -318,7 +326,7 @@ describe(relative(process.cwd(), __filename), () => { start = Date.now(); await request.get('/top-level-delay').expect(200); - expect(Date.now() - start >= 50).equals(true); + assert.strictEqual(Date.now() - start >= 50, true); moxy.on('/route-and-method-level-delay', { delay: 50, @@ -331,13 +339,13 @@ describe(relative(process.cwd(), __filename), () => { start = Date.now(); await request.post('/route-and-method-level-delay').expect(201); - expect(Date.now() - start >= 100).equals(true); + assert.strictEqual(Date.now() - start >= 100, true); }); - it('can proxy requests to another server', async () => { + await it('can proxy requests to another server', async (context) => { const proxyTarget = new MoxyServer({ logging: 'error' }); await proxyTarget.listen(0); - after(async () => await proxyTarget.close({ closeConnections: true })); + context.after(() => proxyTarget.close({ closeConnections: true })); proxyTarget.on('/this/request/was/proxied', { get: { @@ -354,9 +362,9 @@ describe(relative(process.cwd(), __filename), () => { }); await request.get('/proxy/this/request/was/proxied').expect(({ status, body, headers }) => { - expect(status).equals(418); - expect(body).deep.equals({ message: 'Hello!' }); - expect(headers['x-proxy-responder']).equals('moxy'); + assert.strictEqual(status, 418); + assert.deepStrictEqual(body, { message: 'Hello!' }); + assert.strictEqual(headers['x-proxy-responder'], 'moxy'); }); proxyTarget.on('/proxier', { @@ -379,9 +387,9 @@ describe(relative(process.cwd(), __filename), () => { }); await request.get('/proxy/proxier').expect(({ status, body, headers }) => { - expect(status).equals(418); - expect(body).deep.equals({ message: 'Hello!' }); - expect(headers['x-proxy-responder']).equals('moxy'); + assert.strictEqual(status, 418); + assert.deepStrictEqual(body, { message: 'Hello!' }); + assert.strictEqual(headers['x-proxy-responder'], 'moxy'); }); moxy.on('/bad-proxy/(?.*)', { @@ -390,14 +398,26 @@ describe(relative(process.cwd(), __filename), () => { }, }); - await request.get('/bad-proxy/proxier').expect(({ status, body, headers }) => { - expect(status).equals(502); - expect(body.status).equals(502); - expect(body.message.code).equals('ECONNREFUSED'); - expect(headers['x-moxy-error']).equals('proxy error'); - }); + await request + .get('/bad-proxy/proxier') + .expect<{ status: number; message: NetError }>(({ status, body, headers }) => { + assert.deepStrictEqual( + { status, body }, + { + status: 502, + body: { + status: 502, + message: { + ...body.message, + code: 'ECONNREFUSED', + }, + }, + }, + ); + assert.strictEqual(headers['x-moxy-error'], 'proxy error'); + }); - let timer: NodeJS.Timeout; + let timer: NodeJS.Timeout | undefined; proxyTarget.on('/slow', { get: (_, res) => (timer = setTimeout(() => res.sendJson({ message: 'zzzzzz' }), 1000)), }); @@ -411,16 +431,25 @@ describe(relative(process.cwd(), __filename), () => { }, }); - await request.get('/slow-proxy/proxier').expect(({ status, body, headers }) => { - expect(status).equals(504); - expect(body.message).equals('Proxy timeout'); - expect(headers['x-moxy-error']).equals('proxy timeout'); + await request.get('/slow-proxy/proxier').expect<{ options: unknown }>(({ status, body, headers }) => { + assert.deepStrictEqual( + { status, body }, + { + status: 504, + body: { + status: 504, + message: 'Proxy timeout', + options: body.options, + }, + }, + ); + assert.strictEqual(headers['x-moxy-error'], 'proxy timeout'); }); clearTimeout(timer); }); - it('can use query and path params', async () => { + await it('can use query and path params', async () => { // explicit handlers for with and without query string moxy.on('/test-params/:tpId\\?search=:search', { get: { @@ -446,16 +475,20 @@ describe(relative(process.cwd(), __filename), () => { .get('/test-params/0118') .query({ search: 'ambul' }) .expect(({ status, body }) => { - expect(status).equals(401); - expect(body).deep.equals([ - ['tpId', '0118'], - ['search', 'ambul'], - ]); + assert.deepStrictEqual( + { status, body }, + { + status: 401, + body: [ + ['tpId', '0118'], + ['search', 'ambul'], + ], + }, + ); }); await request.get('/test-params/0118').expect(({ status, body }) => { - expect(status).equals(402); - expect(body).deep.equals([['tpId', '0118']]); + assert.deepStrictEqual({ status, body }, { status: 402, body: [['tpId', '0118']] }); }); // explicit required query @@ -478,8 +511,8 @@ describe(relative(process.cwd(), __filename), () => { .get('/test-params/0118') .query({ search: 'ambul' }) .expect(({ status, body }) => { - expect(status).equals(401); - expect(body).deep.equals([ + assert.strictEqual(status, 401); + assert.deepStrictEqual(body, [ ['tpId', '0118'], ['search', 'ambul'], ]); @@ -507,16 +540,21 @@ describe(relative(process.cwd(), __filename), () => { .get('/test-params/0118') .query({ search: 'ambul' }) .expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals([ - ['tpId', '0118'], - ['search', 'ambul'], - ]); + assert.deepStrictEqual( + { status, body }, + { + status: 200, + body: [ + ['tpId', '0118'], + ['search', 'ambul'], + ], + }, + ); }); await request.get('/test-params/0118').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals([ + assert.strictEqual(status, 200); + assert.deepStrictEqual(body, [ ['tpId', '0118'], ['search', ':search'], ]); @@ -527,15 +565,13 @@ describe(relative(process.cwd(), __filename), () => { moxy.resetRoutes(); moxy.on('/moxy.git/info/:refs', handler); await request.get('/moxy.git/info/refs?service=git-upload-pack').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ refs: 'refs', service: 'git-upload-pack' }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { refs: 'refs', service: 'git-upload-pack' } }); }); moxy.resetRoutes(); moxy.on('/moxy.git/info/:refs', handler); await request.get('/moxy.git/info/refs?service=git-upload-pack').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ refs: 'refs', service: 'git-upload-pack' }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { refs: 'refs', service: 'git-upload-pack' } }); }); moxy.resetRoutes(); @@ -553,8 +589,7 @@ describe(relative(process.cwd(), __filename), () => { moxy.resetRoutes(); moxy.on('/moxy.git/info/:refs\\?asdf=fdsa', handler); await request.get('/moxy.git/info/refs?asdf=fdsa').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ refs: 'refs', asdf: 'fdsa' }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { refs: 'refs', asdf: 'fdsa' } }); }); moxy.resetRoutes(); @@ -584,8 +619,7 @@ describe(relative(process.cwd(), __filename), () => { moxy.resetRoutes(); moxy.on('/test-params/:tpId\\?search=:search', handler); await request.get('/test-params/tpid?search=asdf').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ tpId: 'tpid', search: 'asdf' }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { tpId: 'tpid', search: 'asdf' } }); }); moxy.resetRoutes(); @@ -607,26 +641,23 @@ describe(relative(process.cwd(), __filename), () => { moxy.resetRoutes(); moxy.on('/test-params/:tpId', handler); await request.get('/test-params/tpid').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ tpId: 'tpid' }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { tpId: 'tpid' } }); }); moxy.resetRoutes(); moxy.on('/test-params/:tpId', handler); await request.get('/test-params/tpid?search').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ tpId: 'tpid', search: '' }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { tpId: 'tpid', search: '' } }); }); moxy.resetRoutes(); moxy.on('/test-params/:tpId', handler); await request.get('/test-params/tpid?search=asdf').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ tpId: 'tpid', search: 'asdf' }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { tpId: 'tpid', search: 'asdf' } }); }); }); - it('can disable regex route matching', async () => { + await it('can disable regex route matching', async () => { await request.get('/route/:ignored/.*').expect(404); await request.post('/route/:ignored/.*').expect(404); await request.delete('/route/:ignored/.*').expect(404); @@ -639,7 +670,7 @@ describe(relative(process.cwd(), __filename), () => { moxy.on('/route/:ignored/.*', { exact: true, - all: (req, res, vars) => res.sendJson(vars), + all: (_req, res, vars) => res.sendJson(vars), }); await request.get('/route/:ignored/.*').expect(200); @@ -663,7 +694,7 @@ describe(relative(process.cwd(), __filename), () => { await request.delete('/route/ignored/path').expect(404); moxy.on('/route/:ignored/.*', { - all: (req, res, vars) => res.sendJson(vars), + all: (_req, res, vars) => res.sendJson(vars), }); await request.get('/route/:ignored/.*').expect(200); @@ -677,9 +708,9 @@ describe(relative(process.cwd(), __filename), () => { await request.delete('/route/ignored/path').expect(200); }); - it('can modify server params from handler method', async () => { + await it('can modify server params from handler method', async () => { moxy.on('/modify-me', { - get: (req, res, vars, server) => { + get: (_req, res, _vars, server) => { server.once('/modify-me', { get: { status: 418, @@ -693,16 +724,13 @@ describe(relative(process.cwd(), __filename), () => { }); await request.get('/modify-me').expect(({ status, body }) => { - expect(status).equals(200); - expect(body.message).equals('configured'); + assert.deepStrictEqual({ status, body }, { status: 200, body: { message: 'configured' } }); }); await request.get('/modify-me').expect(({ status, body }) => { - expect(status).equals(418); - expect(body.message).equals('ok'); + assert.deepStrictEqual({ status, body }, { status: 418, body: { message: 'ok' } }); }); await request.get('/modify-me').expect(({ status, body }) => { - expect(status).equals(200); - expect(body.message).equals('configured'); + assert.deepStrictEqual({ status, body }, { status: 200, body: { message: 'configured' } }); }); }); -}); +}).catch(console.error); diff --git a/test/server.spec.ts b/test/server.spec.ts index d52e40e..dd4290b 100644 --- a/test/server.spec.ts +++ b/test/server.spec.ts @@ -1,8 +1,8 @@ -import { expect } from 'chai'; -import { after, afterEach, before } from 'mocha'; -import { relative } from 'path'; -import { default as supertest } from 'supertest'; +import assert from 'node:assert'; +import { relative } from 'node:path'; +import { after, afterEach, before, describe, it } from 'node:test'; import { MoxyServer, RouteConfig } from '../src'; +import { getRequest, TestRequest } from './shared/test-util'; const basicRouteConfig: RouteConfig = { post: { status: 418, body: { message: '0xC0FFEE' } } }; const updatedRouteConfig: RouteConfig = { delete: { status: 418, body: { message: '0xC0FFEE' } } }; @@ -19,26 +19,25 @@ const privateRouteResponse = { 'GET /router?once=false&serializeMethods=true': 'show router', }; -describe(relative(process.cwd(), __filename), () => { +describe(relative(process.cwd(), __filename), async () => { const moxy: MoxyServer = new MoxyServer({ router: { allowHttpRouteConfig: true }, logging: 'error' }); - let request: supertest.SuperTest; + let request: TestRequest; const clearRoutes = async (): Promise => { moxy.resetRoutes(); moxy.on('/brew', basicRouteConfig); await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/brew']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/brew'] }); }); }; before(async () => { await moxy.listen(); - request = supertest(moxy.server); + request = getRequest(moxy); }); - afterEach(async () => { + afterEach(() => { moxy.resetRoutes(); }); @@ -46,46 +45,40 @@ describe(relative(process.cwd(), __filename), () => { await moxy.close({ closeConnections: true }); }); - it('GET /_moxy - reports api routes', async () => { + await it('GET /_moxy - reports api routes', async () => { await request.get('/_moxy').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(publicRouteResponse); + assert.deepStrictEqual({ status, body }, { status: 200, body: publicRouteResponse }); }); moxy.on('/a/b/c', { get: { status: 200 } }); await request.get('/_moxy').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(publicRouteResponse); + assert.deepStrictEqual({ status, body }, { status: 200, body: publicRouteResponse }); }); }); - it('GET /_moxy/routes - can list available routes', async () => { + await it('GET /_moxy/routes - can list available routes', async () => { await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals([]); + assert.deepStrictEqual({ status, body }, { status: 200, body: [] }); }); await request .get('/_moxy/routes') .query({ once: true }) .expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals([]); + assert.deepStrictEqual({ status, body }, { status: 200, body: [] }); }); moxy.on('/a/b/c', { get: { status: 200 } }); await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/a/b/c']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/a/b/c'] }); }); moxy.on('test-two', { get: { status: 200 } }); await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/a/b/c', 'test-two']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/a/b/c', 'test-two'] }); }); moxy.once('/x/y/z', { get: { status: 200 } }); @@ -94,8 +87,7 @@ describe(relative(process.cwd(), __filename), () => { .get('/_moxy/routes') .query({ once: true }) .expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/x/y/z']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/x/y/z'] }); }); moxy.once('test-three', { get: { status: 200 } }); @@ -104,32 +96,34 @@ describe(relative(process.cwd(), __filename), () => { .get('/_moxy/routes') .query({ once: true }) .expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/x/y/z', 'test-three']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/x/y/z', 'test-three'] }); }); }); - it('GET /_moxy/router - can return router config', async () => { + await it('GET /_moxy/router - can return router config', async () => { await request.get('/_moxy/router').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({}); + assert.deepStrictEqual({ status, body }, { status: 200, body: {} }); }); moxy.on('/a/b/c', { get: { status: 200 } }); await request.get('/_moxy/router').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ '/a/b/c': { get: { status: 200 } } }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { '/a/b/c': { get: { status: 200 } } } }); }); moxy.on('test-two', { get: { status: 200 } }); await request.get('/_moxy/router').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ - '/a/b/c': { get: { status: 200 } }, - 'test-two': { get: { status: 200 } }, - }); + assert.deepStrictEqual( + { status, body }, + { + status: 200, + body: { + '/a/b/c': { get: { status: 200 } }, + 'test-two': { get: { status: 200 } }, + }, + }, + ); }); moxy.on('test', { @@ -139,64 +133,71 @@ describe(relative(process.cwd(), __filename), () => { }); await request.get('/_moxy/router').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ - '/a/b/c': { - get: { - status: 200, - }, - }, - 'test-two': { - get: { - status: 200, + assert.deepStrictEqual( + { status, body }, + { + status: 200, + body: { + '/a/b/c': { + get: { + status: 200, + }, + }, + 'test-two': { + get: { + status: 200, + }, + }, + 'test': { + get: "get(req, res) {\n return res.writeHead(200, 'ok');\n }", + }, }, }, - 'test': { - get: "get(req, res) {\n return res.writeHead(200, 'ok');\n }", - }, - }); + ); }); await request .get('/_moxy/router') .query({ serializeMethods: false }) .expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ - '/a/b/c': { - get: { - status: 200, - }, - }, - 'test-two': { - get: { - status: 200, + assert.deepStrictEqual( + { status, body }, + { + status: 200, + body: { + '/a/b/c': { + get: { + status: 200, + }, + }, + 'test-two': { + get: { + status: 200, + }, + }, + 'test': { + get: '[Function: handler]', + }, }, }, - 'test': { - get: '[Function: handler]', - }, - }); + ); }); }); - it('POST /_moxy/routes - can create routes', async () => { + await it('POST /_moxy/routes - can create routes', async () => { await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals([]); + assert.deepStrictEqual({ status, body }, { status: 200, body: [] }); }); // programatic moxy.on('/brew', basicRouteConfig); await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/brew']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/brew'] }); }); await request.get('/_moxy/router').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ '/brew': basicRouteConfig }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { '/brew': basicRouteConfig } }); }); moxy.once('/brew', updatedRouteConfig); @@ -205,23 +206,20 @@ describe(relative(process.cwd(), __filename), () => { .get('/_moxy/routes') .query({ once: true }) .expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/brew']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/brew'] }); }); await request .get('/_moxy/router') .query({ once: true }) .expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ '/brew': updatedRouteConfig }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { '/brew': updatedRouteConfig } }); }); moxy.resetRoutes(); await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals([]); + assert.deepStrictEqual({ status, body }, { status: 200, body: [] }); }); // http @@ -232,18 +230,15 @@ describe(relative(process.cwd(), __filename), () => { config: basicRouteConfig, }) .expect(({ status, body }) => { - expect(status).equals(201); - expect(body).deep.equals({ '/brew': basicRouteConfig }); + assert.deepStrictEqual({ status, body }, { status: 201, body: { '/brew': basicRouteConfig } }); }); await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/brew']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/brew'] }); }); await request.get('/_moxy/router').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ '/brew': basicRouteConfig }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { '/brew': basicRouteConfig } }); }); await request @@ -254,52 +249,45 @@ describe(relative(process.cwd(), __filename), () => { config: { get: basicRouteConfig.post }, }) .expect(({ status, body }) => { - expect(status).equals(201); - expect(body).deep.equals({ '/brew': { get: basicRouteConfig.post } }); + assert.deepStrictEqual({ status, body }, { status: 201, body: { '/brew': { get: basicRouteConfig.post } } }); }); await request .get('/_moxy/routes') .query({ once: true }) .expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/brew']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/brew'] }); }); await request .get('/_moxy/router') .query({ once: true }) .expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ '/brew': { get: basicRouteConfig.post } }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { '/brew': { get: basicRouteConfig.post } } }); }); moxy.resetRoutes(); await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals([]); + assert.deepStrictEqual({ status, body }, { status: 200, body: [] }); }); await request .get('/_moxy/routes') .query({ once: true }) .expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals([]); + assert.deepStrictEqual({ status, body }, { status: 200, body: [] }); }); // programatic moxy.on('/brew/:file', '/data/:file'); await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/brew/:file']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/brew/:file'] }); }); await request.get('/_moxy/router').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ '/brew/:file': { get: '/data/:file' } }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { '/brew/:file': { get: '/data/:file' } } }); }); moxy.once('/brew/:file', '/www-data/:file'); @@ -308,22 +296,20 @@ describe(relative(process.cwd(), __filename), () => { .get('/_moxy/routes') .query({ once: true }) .expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/brew/:file']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/brew/:file'] }); }); await request .get('/_moxy/router') .query({ once: true }) .expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ '/brew/:file': { get: '/www-data/:file' } }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { '/brew/:file': { get: '/www-data/:file' } } }); }); // http }); - it('PUT /_moxy/routes/:route - can create or replace a route', async () => { + await it('PUT /_moxy/routes/:route - can create or replace a route', async () => { // programatic await clearRoutes(); @@ -331,13 +317,11 @@ describe(relative(process.cwd(), __filename), () => { moxy.on('/brew', updatedRouteConfig); await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/brew']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/brew'] }); }); await request.get('/_moxy/router').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ '/brew': updatedRouteConfig }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { '/brew': updatedRouteConfig } }); }); // http @@ -347,46 +331,39 @@ describe(relative(process.cwd(), __filename), () => { .put('/_moxy/routes/brew') .send(updatedRouteConfig) .expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ '/brew': updatedRouteConfig }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { '/brew': updatedRouteConfig } }); }); await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/brew']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/brew'] }); }); await request.get('/_moxy/router').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ '/brew': updatedRouteConfig }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { '/brew': updatedRouteConfig } }); }); }); - it('PATCH /_moxy/routes/:route - can update a route', async () => { + await it('PATCH /_moxy/routes/:route - can update a route', async () => { // programatic await clearRoutes(); moxy.on('/brew', updatedRouteConfig); await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/brew']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/brew'] }); }); await request.get('/_moxy/router').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ '/brew': { ...basicRouteConfig, ...updatedRouteConfig } }); + assert.deepStrictEqual( + { status, body }, + { status: 200, body: { '/brew': { ...basicRouteConfig, ...updatedRouteConfig } } }, + ); }); // http moxy.resetRoutes(); - await request - .patch('/_moxy/routes/brew') - .send(basicRouteConfig) - .expect(({ status }) => { - expect(status).equals(404); - }); + await request.patch('/_moxy/routes/brew').send(basicRouteConfig).expect(404); await clearRoutes(); @@ -394,74 +371,73 @@ describe(relative(process.cwd(), __filename), () => { .patch('/_moxy/routes/brew') .send(updatedRouteConfig) .expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ '/brew': { ...basicRouteConfig, ...updatedRouteConfig } }); + assert.deepStrictEqual( + { status, body }, + { status: 200, body: { '/brew': { ...basicRouteConfig, ...updatedRouteConfig } } }, + ); }); await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/brew']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/brew'] }); }); await request.get('/_moxy/router').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ '/brew': { ...basicRouteConfig, ...updatedRouteConfig } }); + assert.deepStrictEqual( + { status, body }, + { status: 200, body: { '/brew': { ...basicRouteConfig, ...updatedRouteConfig } } }, + ); }); }); - it('DELETE /_moxy/routes/:route - can remove routes', async () => { + await it('DELETE /_moxy/routes/:route - can remove routes', async () => { // programatic await clearRoutes(); moxy.off('/brew'); - expect(moxy.router.routes).deep.equals({}); + assert.deepStrictEqual(moxy.router.routes, {}); await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals([]); + assert.deepStrictEqual({ status, body }, { status: 200, body: [] }); }); // http await clearRoutes(); await request.delete('/_moxy/routes/brew').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ message: 'Ok' }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { message: 'Ok' } }); }); await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals([]); + assert.deepStrictEqual({ status, body }, { status: 200, body: [] }); }); }); - it('disables http modification by default', async () => { + await it('disables http modification by default', async () => { const nonExposedServer = new MoxyServer({ logging: 'error', router: { allowHttpRouteConfig: false } }); await nonExposedServer.listen(0); - after(async () => await nonExposedServer.close({ closeConnections: true })); + after(async () => { + await nonExposedServer.close({ closeConnections: true }); + }); - request = supertest(nonExposedServer.server); + request = getRequest(nonExposedServer); // programatic ok nonExposedServer.on('/private-router', { get: { status: 200 } }); // root available await request.get('/_moxy').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(privateRouteResponse); + assert.deepStrictEqual({ status, body }, { status: 200, body: privateRouteResponse }); }); // routes available await request.get('/_moxy/routes').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals(['/private-router']); + assert.deepStrictEqual({ status, body }, { status: 200, body: ['/private-router'] }); }); // routes available await request.get('/_moxy/router').expect(({ status, body }) => { - expect(status).equals(200); - expect(body).deep.equals({ '/private-router': { get: { status: 200 } } }); + assert.deepStrictEqual({ status, body }, { status: 200, body: { '/private-router': { get: { status: 200 } } } }); }); // all others are blocked @@ -470,4 +446,4 @@ describe(relative(process.cwd(), __filename), () => { await request.patch('/_moxy/routes/private-router').expect(404); await request.delete('/_moxy/routes/private-router').expect(404); }); -}); +}).catch(console.error); diff --git a/test/shared/test-util.ts b/test/shared/test-util.ts new file mode 100644 index 0000000..f8aaeae --- /dev/null +++ b/test/shared/test-util.ts @@ -0,0 +1,32 @@ +import { CallbackHandler, default as supertest } from 'supertest'; +import { default as TestAgent } from 'supertest/lib/agent'; +import { MoxyHttpServer, MoxyServer } from '../../src'; +import assert from 'node:assert'; + +interface SuperTestResponse extends supertest.Response { + body: T; +} + +interface SuperTestAgent extends supertest.Test { + /** @deprecated: supertest .expect does not accept / wait for async - use .then */ + expect(checker: (res: SuperTestResponse) => PromiseLike, callback?: CallbackHandler): never; + expect(checker: (res: SuperTestResponse) => void, callback?: CallbackHandler): this; + expect(statusOrBody: number | string | RegExp | object, callback?: CallbackHandler): this; + expect(status: number, body: unknown, callback?: CallbackHandler): this; + expect(field: string, val: string | RegExp, callback?: CallbackHandler): this; + then( + onfulfilled?: (value: SuperTestResponse) => Resolve | PromiseLike, + onrejected?: (reason: unknown) => Reject | PromiseLike, + ): Promise; + /* eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters */ + query(val: T | string): this; +} + +export type TestRequest = TestAgent; + +export const getRequest = (moxy: MoxyServer): TestRequest => { + assert.strictEqual(typeof moxy.server !== 'undefined', true); + const request = supertest.agent(moxy.server as MoxyHttpServer) as TestRequest; + + return request; +}; diff --git a/tsconfig.json b/tsconfig.json index edb726c..965726b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,7 @@ "resolveJsonModule": true, "rootDir": ".", "sourceMap": true, - "strictNullChecks": false + "strictNullChecks": true }, "include": [ "src",