From 2fe783a600db4874143bf6dea6d80c2df398dee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Wed, 2 Apr 2025 10:35:23 +0200 Subject: [PATCH 1/3] chore: configure neostandard + prettier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upgrade from `standard` to `neostandard` + `prettier`. Signed-off-by: Miroslav Bajtoš --- .prettierignore | 7 - .prettierrc.yaml | 5 +- eslint.config.js | 6 + package-lock.json | 3160 ++++++++++++++++++++++++++++++++++++--------- package.json | 7 +- 5 files changed, 2550 insertions(+), 635 deletions(-) create mode 100644 eslint.config.js diff --git a/.prettierignore b/.prettierignore index a0c9239..07e78c2 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,9 +1,2 @@ -# We are using https://standardjs.com coding style. It is unfortunately incompatible with Prettier; -# see https://github.com/standard/standard/issues/996 and the linked issues. -# Standard does not handle Markdown files though, so we want to use Prettier formatting. -# The goal of the configuration below is to configure Prettier to lint only Markdown files. -**/*.* -!**/*.md - # Let's keep LICENSE.md in the same formatting as we use in other PL repositories LICENSE.md diff --git a/.prettierrc.yaml b/.prettierrc.yaml index 282cbf2..1b0f74f 100644 --- a/.prettierrc.yaml +++ b/.prettierrc.yaml @@ -1,2 +1,5 @@ -printWidth: 80 +semi: false +singleQuote: true +printWidth: 100 +trailingComma: all proseWrap: always diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..6650128 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,6 @@ +import neostandard from 'neostandard' + +export default neostandard({ + noStyle: true, // Disable style-related rules, we use Prettier + ts: true, +}) diff --git a/package-lock.json b/package-lock.json index 06ad4d1..374c413 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,8 +16,9 @@ "devDependencies": { "@types/debug": "^4.1.12", "@types/node": "^22.13.17", + "eslint": "^9.23.0", + "neostandard": "^0.12.1", "prettier": "^3.5.3", - "standard": "^17.1.2", "typescript": "^5.8.2" } }, @@ -49,40 +50,118 @@ "standard": "^17.1.2" } }, + "node_modules/@emnapi/core": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.0.tgz", + "integrity": "sha512-H+N/FqT07NmLmt6OFFtDfwe8PNygprzBikrEMyQfgqSmT0vzE515Pz7R8izwB9q/zsH/MA64AKoul3sA6/CzVg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.0.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.0.tgz", + "integrity": "sha512-64WYIf4UYcdLnbKn/umDlNjQDSS8AgZrI/R9+x5ilkUVFxXcA1Ebl+gQLc/6mERA4407Xof0R7wEyEuj091CVw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.1.tgz", + "integrity": "sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz", + "integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", + "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", + "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", + "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", + "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.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, + "license": "MIT", "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", @@ -90,19 +169,57 @@ "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/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.23.0.tgz", + "integrity": "sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==", "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" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", + "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.13.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", + "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "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/@fastify/ajv-compiler": { @@ -220,14 +337,53 @@ "resolved": "repository", "link": true }, + "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.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "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", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", + "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", "minimatch": "^3.0.5" }, @@ -235,6 +391,17 @@ "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/gitignore-to-minimatch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", + "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", + "dev": true, + "license": "Apache-2.0", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -253,7 +420,22 @@ "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", - "dev": true + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@ioredis/commands": { "version": "1.2.0", @@ -273,11 +455,25 @@ "npm": ">=7.0.0" } }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.8.tgz", + "integrity": "sha512-OBlgKdX7gin7OIq4fadsjpg+cp2ZphvAIKucHsNfTdJiqdOmOEwQd/bHi0VwNrcw5xpBJyUw6cK/QilCqy1BSg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.0", + "@emnapi/runtime": "^1.4.0", + "@tybys/wasm-util": "^0.9.0" + } + }, "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==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -291,6 +487,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -300,6 +497,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -308,6 +506,16 @@ "node": ">= 8" } }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, "node_modules/@opentelemetry/api": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", @@ -886,6 +1094,19 @@ "@opentelemetry/api": "^1.1.0" } }, + "node_modules/@pkgr/core": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.0.tgz", + "integrity": "sha512-vsJDAkYR6qCPu+ioGScGiMYR7LvZYIXh/dlQeviqoTWNCVfKTLYD/LkNWH4Mxsv2a5vpIRc77FN5DnmK1eBggQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@prisma/instrumentation": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/@prisma/instrumentation/-/instrumentation-6.5.0.tgz", @@ -902,7 +1123,8 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@sentry/core": { "version": "9.10.1", @@ -978,6 +1200,50 @@ "@opentelemetry/semantic-conventions": "^1.28.0" } }, + "node_modules/@stylistic/eslint-plugin": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.11.0.tgz", + "integrity": "sha512-PNRHbydNG5EH8NK4c+izdJlxajIR6GxcUhzsYNRsn6Myep4dsZt0qFCz3rCPnkvgO5FYibDcMqgNHUT+zvjYZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.13.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "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/@tybys/wasm-util": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", + "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", @@ -996,11 +1262,33 @@ "@types/ms": "*" } }, + "node_modules/@types/doctrine": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz", + "integrity": "sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/ms": { "version": "0.7.34", @@ -1066,82 +1354,530 @@ "@types/node": "*" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/abstract-logging": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", - "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==", - "license": "MIT" - }, - "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.29.0.tgz", + "integrity": "sha512-PAIpk/U7NIS6H7TEtN45SPGLQaHNgB7wSjsQV/8+KYokAb2T/gloOA/Bee2yd4/yKVhPKe5LlaUGhAZk5zmSaQ==", + "dev": true, "license": "MIT", - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.29.0", + "@typescript-eslint/type-utils": "8.29.0", + "@typescript-eslint/utils": "8.29.0", + "@typescript-eslint/visitor-keys": "8.29.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.1" }, "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", - "license": "MIT", + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, "peerDependencies": { - "acorn": "^8" + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/@typescript-eslint/parser": { + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.29.0.tgz", + "integrity": "sha512-8C0+jlNJOwQso2GapCVWWfW/rzaq7Lbme+vGUFKE31djwNncIpgXD7Cd4weEsDdkoZDjH0lwwr3QDQFuyrMg9g==", "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.29.0", + "@typescript-eslint/types": "8.29.0", + "@typescript-eslint/typescript-estree": "8.29.0", + "@typescript-eslint/visitor-keys": "8.29.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.29.0.tgz", + "integrity": "sha512-aO1PVsq7Gm+tcghabUpzEnVSFMCU4/nYIgC2GOatJcllvWfnhrgW0ZEbnTxm36QsikmCN1K/6ZgM7fok2I7xNw==", "dev": true, + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "@typescript-eslint/types": "8.29.0", + "@typescript-eslint/visitor-keys": "8.29.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "node_modules/@typescript-eslint/type-utils": { + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.29.0.tgz", + "integrity": "sha512-ahaWQ42JAOx+NKEf5++WC/ua17q5l+j1GFrbbpVKzFL/tKVc0aYY8rVSYUpUvt2hUP1YBr7mwXzx+E/DfUWI9Q==", + "dev": true, "license": "MIT", "dependencies": { - "ajv": "^8.0.0" + "@typescript-eslint/typescript-estree": "8.29.0", + "@typescript-eslint/utils": "8.29.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.0.1" }, - "peerDependencies": { - "ajv": "^8.0.0" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-formats/node_modules/ajv": { + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.29.0.tgz", + "integrity": "sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.29.0.tgz", + "integrity": "sha512-yOfen3jE9ISZR/hHpU/bmNvTtBW1NjRbkSFdZOksL1N+ybPEE7UVGMwqvS6CP022Rp00Sb0tdiIkhSCe6NI8ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.29.0", + "@typescript-eslint/visitor-keys": "8.29.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.1" + }, + "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 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/typescript-estree/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" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.29.0.tgz", + "integrity": "sha512-gX/A0Mz9Bskm8avSWFcK0gP7cZpbY4AIo6B0hWYFCaIsz750oaiWR4Jr2CI+PQhfW1CpcQr9OlfPS+kMFegjXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.29.0", + "@typescript-eslint/types": "8.29.0", + "@typescript-eslint/typescript-estree": "8.29.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.29.0.tgz", + "integrity": "sha512-Sne/pVz8ryR03NFK21VpN88dZ2FdQXOlq3VIklbrTYEt8yXtRFr9tvUhqvCeKjqYk5FSim37sHbooT6vzBTZcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.29.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "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/@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==", + "dev": true, + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.3.3.tgz", + "integrity": "sha512-EpRILdWr3/xDa/7MoyfO7JuBIJqpBMphtu4+80BK1bRfFcniVT74h3Z7q1+WOc92FuIAYatB1vn9TJR67sORGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.3.3.tgz", + "integrity": "sha512-ntj/g7lPyqwinMJWZ+DKHBse8HhVxswGTmNgFKJtdgGub3M3zp5BSZ3bvMP+kBT6dnYJLSVlDqdwOq1P8i0+/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.3.3.tgz", + "integrity": "sha512-l6BT8f2CU821EW7U8hSUK8XPq4bmyTlt9Mn4ERrfjJNoCw0/JoHAh9amZZtV3cwC3bwwIat+GUnrcHTG9+qixw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.3.3.tgz", + "integrity": "sha512-8ScEc5a4y7oE2BonRvzJ+2GSkBaYWyh0/Ko4Q25e/ix6ANpJNhwEPZvCR6GVRmsQAYMIfQvYLdM6YEN+qRjnAQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.3.3.tgz", + "integrity": "sha512-8qQ6l1VTzLNd3xb2IEXISOKwMGXDCzY/UNy/7SovFW2Sp0K3YbL7Ao7R18v6SQkLqQlhhqSBIFRk+u6+qu5R5A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.3.3.tgz", + "integrity": "sha512-v81R2wjqcWXJlQY23byqYHt9221h4anQ6wwN64oMD/WAE+FmxPHFZee5bhRkNVtzqO/q7wki33VFWlhiADwUeQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.3.3.tgz", + "integrity": "sha512-cAOx/j0u5coMg4oct/BwMzvWJdVciVauUvsd+GQB/1FZYKQZmqPy0EjJzJGbVzFc6gbnfEcSqvQE6gvbGf2N8Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.3.3.tgz", + "integrity": "sha512-mq2blqwErgDJD4gtFDlTX/HZ7lNP8YCHYFij2gkXPtMzrXxPW1hOtxL6xg4NWxvnj4bppppb0W3s/buvM55yfg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.3.3.tgz", + "integrity": "sha512-u0VRzfFYysarYHnztj2k2xr+eu9rmgoTUUgCCIT37Nr+j0A05Xk2c3RY8Mh5+DhCl2aYibihnaAEJHeR0UOFIQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.3.3.tgz", + "integrity": "sha512-OrVo5ZsG29kBF0Ug95a2KidS16PqAMmQNozM6InbquOfW/udouk063e25JVLqIBhHLB2WyBnixOQ19tmeC/hIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.3.3.tgz", + "integrity": "sha512-PYnmrwZ4HMp9SkrOhqPghY/aoL+Rtd4CQbr93GlrRTjK6kDzfMfgz3UH3jt6elrQAfupa1qyr1uXzeVmoEAxUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.3.3.tgz", + "integrity": "sha512-81AnQY6fShmktQw4hWDUIilsKSdvr/acdJ5azAreu2IWNlaJOKphJSsUVWE+yCk6kBMoQyG9ZHCb/krb5K0PEA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.7" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.3.3.tgz", + "integrity": "sha512-X/42BMNw7cW6xrB9syuP5RusRnWGoq+IqvJO8IDpp/BZg64J1uuIW6qA/1Cl13Y4LyLXbJVYbYNSKwR/FiHEng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.3.3.tgz", + "integrity": "sha512-EGNnNGQxMU5aTN7js3ETYvuw882zcO+dsVjs+DwO2j/fRVKth87C8e2GzxW1L3+iWAXMyJhvFBKRavk9Og1Z6A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.3.3.tgz", + "integrity": "sha512-GraLbYqOJcmW1qY3osB+2YIiD62nVf2/bVLHZmrb4t/YSUwE03l7TwcDJl08T/Tm3SVhepX8RQkpzWbag/Sb4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/abstract-logging": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==", + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", @@ -1168,6 +1904,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1191,16 +1928,18 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" }, "engines": { "node": ">= 0.4" @@ -1250,17 +1989,19 @@ } }, "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", - "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", + "es-abstract": "^1.23.9", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -1288,15 +2029,16 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -1322,19 +2064,19 @@ } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" }, "engines": { "node": ">= 0.4" @@ -1349,6 +2091,16 @@ "integrity": "sha512-HdUr5u0Y8RRrODGpwKuvrmxevXT4gJTPApsKHKJlwjfOJv9vdj6jNWGWUwPMI2rsyNWsYiobOGFeaLpkvV18gg==", "license": "(Apache-2.0 AND MIT)" }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/atomic-sleep": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", @@ -1363,6 +2115,7 @@ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" }, @@ -1399,6 +2152,19 @@ "concat-map": "0.0.1" } }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/builtins": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", @@ -1421,16 +2187,47 @@ } }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "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": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "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.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -1444,6 +2241,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1520,10 +2318,11 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -1534,14 +2333,15 @@ } }, "node_modules/data-view-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "is-data-view": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -1551,29 +2351,31 @@ } }, "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "is-data-view": "^1.0.2" }, "engines": { "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/inspect-js" } }, "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" }, @@ -1662,6 +2464,7 @@ "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" }, @@ -1669,6 +2472,35 @@ "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", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1679,57 +2511,63 @@ } }, "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "version": "1.23.9", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", + "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", "dev": true, + "license": "MIT", "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.0", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", + "is-data-view": "^1.0.2", + "is-regex": "^1.2.1", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.0", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.3", "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.3", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.18" }, "engines": { "node": ">= 0.4" @@ -1739,13 +2577,11 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -1760,35 +2596,39 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", - "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", + "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", + "get-intrinsic": "^1.2.6", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.1.2" + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.4", + "safe-array-concat": "^1.1.3" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, @@ -1797,37 +2637,44 @@ } }, "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "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": { - "get-intrinsic": "^1.2.4", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", "dev": true, + "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, + "license": "MIT", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { "node": ">= 0.4" @@ -1849,111 +2696,93 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.23.0.tgz", + "integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==", "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.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.2", + "@eslint/config-helpers": "^0.2.0", + "@eslint/core": "^0.12.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.23.0", + "@eslint/plugin-kit": "^0.2.7", + "@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", + "@types/json-schema": "^7.0.15", "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.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.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" - } - }, - "node_modules/eslint-config-standard": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", - "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", - "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" - } - ], - "engines": { - "node": ">=12.0.0" + "url": "https://eslint.org/donate" }, "peerDependencies": { - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", - "eslint-plugin-promise": "^6.0.0" + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "node_modules/eslint-config-standard-jsx": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-11.0.0.tgz", - "integrity": "sha512-+1EV/R0JxEK1L0NGolAr8Iktm3Rgotx3BKwgaX+eAuSX8D952LULKtjgZD3F+e6SvibONnhLwoTi9DPxN5LvvQ==", + "node_modules/eslint-compat-utils": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", + "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", "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": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, "peerDependencies": { - "eslint": "^8.8.0", - "eslint-plugin-react": "^7.28.0" + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-compat-utils/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/eslint-import-resolver-node": { @@ -1961,6 +2790,7 @@ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", @@ -1972,15 +2802,52 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.0.tgz", + "integrity": "sha512-aV3/dVsT0/H9BtpNwbaqvl+0xGMRGzncLyhm793NFGvbwGGvzyAykqWZ8oZlZuGwuHkwJjhWJkG1cM3ynvd2pQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.12", + "unrs-resolver": "^1.3.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, "node_modules/eslint-module-utils": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.9.0.tgz", - "integrity": "sha512-McVbYmwA3NEKwRQY5g4aWMdcZE5xZxV8i8l7CqJSrameuGSQJtSWaL/LxTEzSKKaCcOhlpDR8XEfYXWPrdo/ZQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7" }, @@ -1998,6 +2865,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } @@ -2021,6 +2889,28 @@ "eslint": ">=4.19.1" } }, + "node_modules/eslint-plugin-es-x": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", + "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/ota-meshi", + "https://opencollective.com/eslint" + ], + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.11.0", + "eslint-compat-utils": "^0.5.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": ">=8" + } + }, "node_modules/eslint-plugin-es/node_modules/eslint-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", @@ -2046,10 +2936,11 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz", - "integrity": "sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", + "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, + "license": "MIT", "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -2059,7 +2950,7 @@ "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.9.0", + "eslint-module-utils": "^2.12.0", "hasown": "^2.0.2", "is-core-module": "^2.15.1", "is-glob": "^4.0.3", @@ -2068,13 +2959,81 @@ "object.groupby": "^1.0.3", "object.values": "^1.2.0", "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.8", "tsconfig-paths": "^3.15.0" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import-x": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.10.0.tgz", + "integrity": "sha512-5ej+0WILhX3D6wkcdsyYmPp10SUIK6fmuZ6KS8nf9MD8CJ6/S/3Dl7m21g+MLeaTMsvcEXo3JunNAbgHwXxs/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.0", + "@types/doctrine": "^0.0.9", + "@typescript-eslint/utils": "^8.28.0", + "debug": "^4.4.0", + "doctrine": "^3.0.0", + "eslint-import-resolver-node": "^0.3.9", + "get-tsconfig": "^4.10.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.3 || ^10.0.1", + "semver": "^7.7.1", + "stable-hash": "^0.0.5", + "tslib": "^2.8.1", + "unrs-resolver": "^1.3.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-import-x/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/eslint-plugin-import-x/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/eslint-plugin-import-x/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/eslint-plugin-import/node_modules/debug": { @@ -2082,6 +3041,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } @@ -2091,6 +3051,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -2151,28 +3112,29 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.36.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz", - "integrity": "sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA==", + "version": "7.37.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz", + "integrity": "sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==", "dev": true, + "license": "MIT", "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.2", + "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.19", + "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.8", "object.fromentries": "^2.0.8", - "object.values": "^1.2.0", + "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11", + "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "engines": { @@ -2212,16 +3174,17 @@ } }, "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==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.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" @@ -2266,18 +3229,45 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "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/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.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.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/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -2300,6 +3290,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -2336,11 +3327,42 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "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" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-json-stringify": { "version": "6.0.1", @@ -2481,16 +3503,45 @@ "reusify": "^1.0.4" } }, + "node_modules/fdir": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", + "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "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==", + "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": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, "node_modules/find-my-way": { @@ -2524,32 +3575,40 @@ } }, "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.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true + "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/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, + "license": "MIT", "dependencies": { - "is-callable": "^1.1.3" + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/forwarded-parse": { @@ -2562,7 +3621,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/function-bind": { "version": "1.1.2", @@ -2573,15 +3633,18 @@ } }, "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" }, "engines": { "node": ">= 0.4" @@ -2600,16 +3663,22 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "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.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -2618,6 +3687,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stdin": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", @@ -2631,14 +3714,15 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -2647,12 +3731,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", + "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2681,15 +3779,13 @@ } }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2712,12 +3808,13 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2733,13 +3830,18 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2766,10 +3868,14 @@ } }, "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -2778,10 +3884,11 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -2825,10 +3932,11 @@ } }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -2867,6 +3975,7 @@ "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" @@ -2876,17 +3985,19 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" + "hasown": "^2.0.2", + "side-channel": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -2926,13 +4037,15 @@ } }, "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -2948,12 +4061,17 @@ "dev": true }, "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -2963,25 +4081,30 @@ } }, "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-bigints": "^1.0.1" + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -2990,11 +4113,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-bun-module/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3017,11 +4164,14 @@ } }, "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, + "license": "MIT", "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" }, "engines": { @@ -3032,12 +4182,14 @@ } }, "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -3056,24 +4208,32 @@ } }, "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -3099,18 +4259,7 @@ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3129,13 +4278,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -3149,18 +4310,22 @@ "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-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -3174,6 +4339,7 @@ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3182,12 +4348,13 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -3197,12 +4364,14 @@ } }, "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -3212,12 +4381,15 @@ } }, "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -3227,12 +4399,13 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, + "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.14" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -3246,6 +4419,7 @@ "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3254,25 +4428,30 @@ } }, "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-weakset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", - "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4" + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -3285,25 +4464,32 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", "dev": true, + "license": "MIT", "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/js-tokens": { @@ -3317,6 +4503,7 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -3328,7 +4515,8 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-parse-better-errors": { "version": "1.0.2", @@ -3359,7 +4547,8 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -3372,6 +4561,7 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.0" }, @@ -3399,6 +4589,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -3505,6 +4696,53 @@ "loose-envify": "cli.js" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "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/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/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3549,6 +4787,132 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/neostandard": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/neostandard/-/neostandard-0.12.1.tgz", + "integrity": "sha512-As/LDK+xx591BLb1rPRaPs+JfXFgyNx5BoBui1KBeF/J4s0mW8+NBohrYnMfgm1w1t7E/Y/tU34MjMiP6lns6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@stylistic/eslint-plugin": "2.11.0", + "eslint-import-resolver-typescript": "^3.7.0", + "eslint-plugin-import-x": "^4.5.0", + "eslint-plugin-n": "^17.14.0", + "eslint-plugin-promise": "^7.2.1", + "eslint-plugin-react": "^7.37.2", + "find-up": "^5.0.0", + "globals": "^15.13.0", + "peowly": "^1.3.2", + "typescript-eslint": "^8.17.0" + }, + "bin": { + "neostandard": "cli.mjs" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.0.0" + } + }, + "node_modules/neostandard/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/neostandard/node_modules/eslint-plugin-n": { + "version": "17.17.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.17.0.tgz", + "integrity": "sha512-2VvPK7Mo73z1rDFb6pTvkH6kFibAmnTubFq5l83vePxu0WiY1s0LOtj2WHb6Sa40R3w4mnh8GFYbHBQyMlotKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.5.0", + "enhanced-resolve": "^5.17.1", + "eslint-plugin-es-x": "^7.8.0", + "get-tsconfig": "^4.8.1", + "globals": "^15.11.0", + "ignore": "^5.3.2", + "minimatch": "^9.0.5", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": ">=8.23.0" + } + }, + "node_modules/neostandard/node_modules/eslint-plugin-promise": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-7.2.1.tgz", + "integrity": "sha512-SWKjd+EuvWkYaS+uN2csvj0KoP43YTu7+phKQ5v+xw6+A0gutVX2yqCeCkC3uLCJFiPfR2dD8Es5L7yUsmvEaA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/neostandard/node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/neostandard/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" + } + }, + "node_modules/neostandard/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -3559,10 +4923,11 @@ } }, "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "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": { "node": ">= 0.4" }, @@ -3580,14 +4945,17 @@ } }, "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", "object-keys": "^1.1.1" }, "engines": { @@ -3634,6 +5002,7 @@ "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -3644,12 +5013,14 @@ } }, "node_modules/object.values": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" }, @@ -3674,6 +5045,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "dependencies": { "wrappy": "1" } @@ -3695,6 +5067,24 @@ "node": ">= 0.8.0" } }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -3755,6 +5145,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -3789,6 +5180,7 @@ "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" } @@ -3798,6 +5190,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3807,6 +5200,16 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/peowly": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/peowly/-/peowly-1.3.2.tgz", + "integrity": "sha512-BYIrwr8JCXY49jUZscgw311w9oGEKo7ux/s+BxrhKTQbiQ0iYNdZNJ5LgagaeercQdFHwnR7Z5IxxFWVQ+BasQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.6.0" + } + }, "node_modules/pg-int8": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", @@ -3838,6 +5241,19 @@ "node": ">=4" } }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -3959,10 +5375,11 @@ } }, "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -4063,6 +5480,7 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -4085,7 +5503,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/quick-format-unescaped": { "version": "4.0.4", @@ -4128,18 +5547,20 @@ } }, "node_modules/reflect.getprototypeof": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", - "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "es-abstract": "^1.23.1", + "es-abstract": "^1.23.9", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -4149,15 +5570,18 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -4222,10 +5646,21 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/ret": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz", @@ -4264,6 +5699,7 @@ "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" }, @@ -4293,19 +5729,22 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", "isarray": "^2.0.5" }, "engines": { @@ -4315,15 +5754,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.2", "es-errors": "^1.3.0", - "is-regex": "^1.1.4" + "is-regex": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -4423,11 +5880,27 @@ "node": ">= 0.4" } }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -4440,6 +5913,7 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4451,15 +5925,73 @@ "license": "BSD-2-Clause" }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -4483,13 +6015,182 @@ "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "license": "ISC", "engines": { - "node": ">= 10.x" + "node": ">= 10.x" + } + }, + "node_modules/stable-hash": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/standard": { + "version": "17.1.2", + "resolved": "https://registry.npmjs.org/standard/-/standard-17.1.2.tgz", + "integrity": "sha512-WLm12WoXveKkvnPnPnaFUUHuOB2cUdAsJ4AiGHL2G0UNMrcRAWY2WriQaV8IQ3oRmYr0AWUbLNr94ekYFAHOrA==", + "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" + } + ], + "dependencies": { + "eslint": "^8.41.0", + "eslint-config-standard": "17.1.0", + "eslint-config-standard-jsx": "^11.0.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-n": "^15.7.0", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-react": "^7.36.1", + "standard-engine": "^15.1.0", + "version-guard": "^1.1.1" + }, + "bin": { + "standard": "bin/cmd.cjs" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, + "node_modules/standard-engine": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-15.1.0.tgz", + "integrity": "sha512-VHysfoyxFu/ukT+9v49d4BRXIokFRZuH3z1VRxzFArZdjSCFpro6rEIU3ji7e4AoAtuSfKBkiOmsrDqKW5ZSRw==", + "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" + } + ], + "dependencies": { + "get-stdin": "^8.0.0", + "minimist": "^1.2.6", + "pkg-conf": "^3.1.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/standard/node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/standard/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/standard/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", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "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", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "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" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/standard": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/standard/-/standard-17.1.2.tgz", - "integrity": "sha512-WLm12WoXveKkvnPnPnaFUUHuOB2cUdAsJ4AiGHL2G0UNMrcRAWY2WriQaV8IQ3oRmYr0AWUbLNr94ekYFAHOrA==", + "node_modules/standard/node_modules/eslint-config-standard": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", + "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", "dev": true, "funding": [ { @@ -4505,33 +6206,21 @@ "url": "https://feross.org/support" } ], - "dependencies": { - "eslint": "^8.41.0", - "eslint-config-standard": "17.1.0", - "eslint-config-standard-jsx": "^11.0.0", - "eslint-plugin-import": "^2.27.5", - "eslint-plugin-n": "^15.7.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-react": "^7.36.1", - "standard-engine": "^15.1.0", - "version-guard": "^1.1.1" - }, - "bin": { - "standard": "bin/cmd.cjs" - }, + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-promise": "^6.0.0" } }, - "node_modules/standard-as-callback": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", - "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" - }, - "node_modules/standard-engine": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-15.1.0.tgz", - "integrity": "sha512-VHysfoyxFu/ukT+9v49d4BRXIokFRZuH3z1VRxzFArZdjSCFpro6rEIU3ji7e4AoAtuSfKBkiOmsrDqKW5ZSRw==", + "node_modules/standard/node_modules/eslint-config-standard-jsx": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-11.0.0.tgz", + "integrity": "sha512-+1EV/R0JxEK1L0NGolAr8Iktm3Rgotx3BKwgaX+eAuSX8D952LULKtjgZD3F+e6SvibONnhLwoTi9DPxN5LvvQ==", "dev": true, "funding": [ { @@ -4547,34 +6236,111 @@ "url": "https://feross.org/support" } ], + "license": "MIT", + "peerDependencies": { + "eslint": "^8.8.0", + "eslint-plugin-react": "^7.28.0" + } + }, + "node_modules/standard/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==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "get-stdin": "^8.0.0", - "minimist": "^1.2.6", - "pkg-conf": "^3.1.0", - "xdg-basedir": "^4.0.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/standard/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==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/standard/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/standard/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/standard/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/string.prototype.matchall": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", - "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", + "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "regexp.prototype.flags": "^1.5.2", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", "set-function-name": "^2.0.2", - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -4594,15 +6360,19 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -4612,15 +6382,20 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4647,6 +6422,7 @@ "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" }, @@ -4668,6 +6444,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -4698,11 +6475,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "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 + "dev": true, + "license": "MIT" }, "node_modules/thread-stream": { "version": "3.1.0", @@ -4713,6 +6501,36 @@ "real-require": "^0.2.0" } }, + "node_modules/tinyglobby": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", + "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.3", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/toad-cache": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz", @@ -4722,11 +6540,25 @@ "node": ">=12" } }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -4734,6 +6566,13 @@ "strip-bom": "^3.0.0" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -4751,6 +6590,7 @@ "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" }, @@ -4759,30 +6599,32 @@ } }, "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" } }, "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -4792,17 +6634,19 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" }, "engines": { "node": ">= 0.4" @@ -4812,17 +6656,18 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-proto": "^1.0.3", "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" }, "engines": { "node": ">= 0.4" @@ -4845,16 +6690,43 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.29.0.tgz", + "integrity": "sha512-ep9rVd9B4kQsZ7ZnWCVxUE/xDLUUUsRzE0poAeNu+4CkFErLfuvPt/qtm2EpnSyfvsR0S6QzDFSrPCFBwf64fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.29.0", + "@typescript-eslint/parser": "8.29.0", + "@typescript-eslint/utils": "8.29.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bound": "^1.0.3", "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4866,11 +6738,39 @@ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "license": "MIT" }, + "node_modules/unrs-resolver": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.3.3.tgz", + "integrity": "sha512-PFLAGQzYlyjniXdbmQ3dnGMZJXX5yrl2YS4DLRfR3BhgUsE1zpRIrccp9XMOGRfIHpdFvCn/nr5N1KMVda4x3A==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/JounQin" + }, + "optionalDependencies": { + "@unrs/resolver-binding-darwin-arm64": "1.3.3", + "@unrs/resolver-binding-darwin-x64": "1.3.3", + "@unrs/resolver-binding-freebsd-x64": "1.3.3", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.3.3", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.3.3", + "@unrs/resolver-binding-linux-arm64-gnu": "1.3.3", + "@unrs/resolver-binding-linux-arm64-musl": "1.3.3", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.3.3", + "@unrs/resolver-binding-linux-s390x-gnu": "1.3.3", + "@unrs/resolver-binding-linux-x64-gnu": "1.3.3", + "@unrs/resolver-binding-linux-x64-musl": "1.3.3", + "@unrs/resolver-binding-wasm32-wasi": "1.3.3", + "@unrs/resolver-binding-win32-arm64-msvc": "1.3.3", + "@unrs/resolver-binding-win32-ia32-msvc": "1.3.3", + "@unrs/resolver-binding-win32-x64-msvc": "1.3.3" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -4889,6 +6789,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -4900,39 +6801,45 @@ } }, "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", "dev": true, + "license": "MIT", "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/which-builtin-type": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", - "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", "dev": true, + "license": "MIT", "dependencies": { + "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", + "is-regex": "^1.2.1", "is-weakref": "^1.0.2", "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", + "which-boxed-primitive": "^1.1.0", "which-collection": "^1.0.2", - "which-typed-array": "^1.1.15" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -4946,6 +6853,7 @@ "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, + "license": "MIT", "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", @@ -4960,15 +6868,18 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" }, "engines": { @@ -4991,7 +6902,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/xdg-basedir": { "version": "4.0.0", diff --git a/package.json b/package.json index ef3d52a..b32ba9b 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ "repository" ], "scripts": { - "lint": "prettier --check . && standard", - "lint:fix": "prettier --write . && standard --fix .", + "lint": "eslint && prettier --check .", + "lint:fix": "eslint --fix && prettier --write .", "test:types": "tsc -p .", "test:unit": "npm test --workspaces --if-present", "test": "npm run lint && npm run test:types && npm run test:unit" @@ -27,8 +27,9 @@ "devDependencies": { "@types/debug": "^4.1.12", "@types/node": "^22.13.17", + "eslint": "^9.23.0", + "neostandard": "^0.12.1", "prettier": "^3.5.3", - "standard": "^17.1.2", "typescript": "^5.8.2" } } From 772c10a96c3651882485886f63901be4a5514465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Wed, 2 Apr 2025 10:35:53 +0200 Subject: [PATCH 2/3] chore: `npm run lint:fix` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miroslav Bajtoš --- .github/dependabot.yml | 36 +- .../dependabot-auto-approve-always.yml | 2 +- .../dependabot-auto-approve-minor.yml | 7 +- README.md | 15 +- api/bin/server.js | 8 +- api/lib/app.js | 6 +- api/lib/instrument.js | 15 +- api/test/app.test.js | 77 ++- api/test/test-helpers.js | 2 +- docs/design.md | 344 ++++++------ indexer/bin/piece-indexer.js | 12 +- indexer/lib/advertisement-walker.js | 221 +++++--- indexer/lib/instrument.js | 13 +- indexer/lib/ipni-watcher.js | 11 +- indexer/lib/typings.d.ts | 11 +- indexer/lib/vendored/multiaddr.js | 33 +- indexer/test/advertisement-walker.test.js | 504 ++++++++++-------- indexer/test/helpers/http-server.js | 6 +- repository/lib/redis-repository.js | 14 +- repository/lib/typings.d.ts | 15 +- repository/test/redis-repository.test.js | 2 +- tsconfig.json | 4 +- 22 files changed, 707 insertions(+), 651 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index cfa4a05..4295d15 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,27 +1,27 @@ version: 2 updates: - - package-ecosystem: "npm" - directory: "/" + - package-ecosystem: 'npm' + directory: '/' versioning-strategy: increase schedule: - interval: "daily" - time: "09:00" - timezone: "Europe/Berlin" + interval: 'daily' + time: '09:00' + timezone: 'Europe/Berlin' commit-message: - prefix: "deps" - prefix-development: "deps(dev)" - - package-ecosystem: "github-actions" - directory: "/" + prefix: 'deps' + prefix-development: 'deps(dev)' + - package-ecosystem: 'github-actions' + directory: '/' schedule: - interval: "daily" - time: "09:00" - timezone: "Europe/Berlin" + interval: 'daily' + time: '09:00' + timezone: 'Europe/Berlin' commit-message: - prefix: "ci" - - package-ecosystem: "docker" + prefix: 'ci' + - package-ecosystem: 'docker' directories: - - "/" + - '/' schedule: - interval: "daily" - time: "15:00" - timezone: "Europe/Berlin" + interval: 'daily' + time: '15:00' + timezone: 'Europe/Berlin' diff --git a/.github/workflows/dependabot-auto-approve-always.yml b/.github/workflows/dependabot-auto-approve-always.yml index 0a2dc2f..ad8eb68 100644 --- a/.github/workflows/dependabot-auto-approve-always.yml +++ b/.github/workflows/dependabot-auto-approve-always.yml @@ -17,7 +17,7 @@ jobs: id: metadata uses: dependabot/fetch-metadata@v2 with: - github-token: "${{ secrets.GITHUB_TOKEN }}" + github-token: '${{ secrets.GITHUB_TOKEN }}' - name: Approve a PR if: ${{startsWith(steps.metadata.outputs.dependency-names, matrix.dependencyStartsWith)}} run: gh pr review --approve "$PR_URL" diff --git a/.github/workflows/dependabot-auto-approve-minor.yml b/.github/workflows/dependabot-auto-approve-minor.yml index c81d3ec..1ee1c8e 100644 --- a/.github/workflows/dependabot-auto-approve-minor.yml +++ b/.github/workflows/dependabot-auto-approve-minor.yml @@ -26,9 +26,12 @@ jobs: id: metadata uses: dependabot/fetch-metadata@v2 with: - github-token: "${{ secrets.GITHUB_TOKEN }}" + github-token: '${{ secrets.GITHUB_TOKEN }}' - name: Approve a PR - if: ${{startsWith(steps.metadata.outputs.dependency-names, matrix.dependencyStartsWith) && (steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor')}} + if: + ${{startsWith(steps.metadata.outputs.dependency-names, matrix.dependencyStartsWith) && + (steps.metadata.outputs.update-type == 'version-update:semver-patch' || + steps.metadata.outputs.update-type == 'version-update:semver-minor')}} run: gh pr review --approve "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} diff --git a/README.md b/README.md index ee3407b..26f6ffc 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,12 @@ A lightweight IPNI node mapping Filecoin PieceCID → payload block CID. ## Basic use -Note: this will change soon, see -https://github.com/filecoin-station/piece-indexer/issues/33 +Note: this will change soon, see https://github.com/filecoin-station/piece-indexer/issues/33 ## `GET /sample/{provider-id}/{piece-cid}` -Sample a set of multihashes ingested by IPNI for a given ContextID, matching the -route eventually to be exposed by an IPNI reverse index. +Sample a set of multihashes ingested by IPNI for a given ContextID, matching the route eventually to +be exposed by an IPNI reverse index. _This is an alternative implementation of the IPNI Reverse Index as specified in [xedni/openapi.yaml](https://github.com/ipni/xedni/blob/526f90f5a6001cb50b52e6376f8877163f8018af/openapi.yaml)._ @@ -20,13 +19,13 @@ _This is an alternative implementation of the IPNI Reverse Index as specified in Parameters: - `provider-id` - the peer ID of the storage provider (index publisher) -- `piece-cid` - the Filecoin deal's PieceCID as advertised by the provider in - Graphsync retrieval metadata +- `piece-cid` - the Filecoin deal's PieceCID as advertised by the provider in Graphsync retrieval + metadata Response: -- `samples` - a list of exactly one payload block CID contained inside the piece - identified by the requested PieceCID. +- `samples` - a list of exactly one payload block CID contained inside the piece identified by the + requested PieceCID. Example: diff --git a/api/bin/server.js b/api/bin/server.js index 3d9d1c7..4796400 100644 --- a/api/bin/server.js +++ b/api/bin/server.js @@ -9,7 +9,7 @@ const { HOST = '127.0.0.1', DOMAIN: domain = 'localhost', REDIS_URL: redisUrl = 'redis://localhost:6379', - REQUEST_LOGGING: requestLogging = 'true' + REQUEST_LOGGING: requestLogging = 'true', } = process.env const redisUrlParsed = new URL(redisUrl) @@ -19,7 +19,7 @@ const redis = new Redis({ username: redisUrlParsed.username, password: redisUrlParsed.password, lazyConnect: true, // call connect() explicitly so that we can exit on connection error - family: 6 // required for upstash + family: 6, // required for upstash }) await redis.connect() @@ -29,8 +29,8 @@ const app = createApp({ repository, domain, logger: { - level: ['1', 'true'].includes(requestLogging) ? 'info' : 'error' - } + level: ['1', 'true'].includes(requestLogging) ? 'info' : 'error', + }, }) console.log('Starting the http server on host %j port %s', HOST, PORT) const baseUrl = await app.listen({ host: HOST, port: Number(PORT) }) diff --git a/api/lib/app.js b/api/lib/app.js index a3087f8..15241d3 100644 --- a/api/lib/app.js +++ b/api/lib/app.js @@ -7,7 +7,7 @@ import Fastify from 'fastify' * @param {string|boolean} args.domain * @param {Fastify.FastifyLoggerOptions} args.logger */ -export function createApp ({ repository, domain, logger }) { +export function createApp({ repository, domain, logger }) { const app = Fastify({ logger }) Sentry.setupFastifyErrorHandler(app) @@ -41,7 +41,7 @@ export function createApp ({ repository, domain, logger }) { if (!walkerState) { return reply.send({ providerId, - ingestionStatus: 'Unknown provider ID' + ingestionStatus: 'Unknown provider ID', }) } @@ -54,7 +54,7 @@ export function createApp ({ repository, domain, logger }) { lastHeadWalkedFrom: walkerState.lastHead ?? walkerState.head, adsMissingPieceCID: walkerState.adsMissingPieceCID ?? 0, entriesNotRetrievable: walkerState.entriesNotRetrievable ?? 0, - piecesIndexed: await repository.countPiecesIndexed(providerId) + piecesIndexed: await repository.countPiecesIndexed(providerId), }) }) diff --git a/api/lib/instrument.js b/api/lib/instrument.js index 26f2c35..242820d 100644 --- a/api/lib/instrument.js +++ b/api/lib/instrument.js @@ -7,14 +7,9 @@ const { SENTRY_ENVIRONMENT = 'development' } = process.env const pkg = JSON.parse( await fs.readFile( - join( - dirname(fileURLToPath(import.meta.url)), - '..', - '..', - 'package.json' - ), - 'utf8' - ) + join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'package.json'), + 'utf8', + ), ) Sentry.init({ @@ -24,7 +19,7 @@ Sentry.init({ tracesSampleRate: 0.1, // Ignore Fastify 4xx errors // Remove once https://github.com/getsentry/sentry-javascript/pull/13198 lands - beforeSend (event, { originalException: err }) { + beforeSend(event, { originalException: err }) { const isBadRequest = typeof err === 'object' && err !== null && @@ -32,5 +27,5 @@ Sentry.init({ typeof err.statusCode === 'number' && err.statusCode < 500 return isBadRequest ? null : event - } + }, }) diff --git a/api/test/app.test.js b/api/test/app.test.js index 9e7bd5e..23a1421 100644 --- a/api/test/app.test.js +++ b/api/test/app.test.js @@ -24,10 +24,8 @@ describe('HTTP request handler', () => { repository, domain: false, logger: { - level: process.env.DEBUG === '*' || process.env.DEBUG?.includes('test') - ? 'debug' - : 'error' - } + level: process.env.DEBUG === '*' || process.env.DEBUG?.includes('test') ? 'debug' : 'error', + }, }) baseUrl = await app.listen() }) @@ -48,20 +46,35 @@ describe('HTTP request handler', () => { describe('GET /samples/{providerId}/{pieceCid}', () => { it('returns the first payload block from the index', async () => { - await repository.addPiecePayloadBlocks('provider-id', 'piece-cid', 'payload-cid-1', 'payload-cid-2') - await repository.addPiecePayloadBlocks('provider-id2', 'piece-cid', 'payload-cid-1', 'payload-cid-2') - await repository.addPiecePayloadBlocks('provider-id', 'piece-cid2', 'payload-cid-1', 'payload-cid-2') + await repository.addPiecePayloadBlocks( + 'provider-id', + 'piece-cid', + 'payload-cid-1', + 'payload-cid-2', + ) + await repository.addPiecePayloadBlocks( + 'provider-id2', + 'piece-cid', + 'payload-cid-1', + 'payload-cid-2', + ) + await repository.addPiecePayloadBlocks( + 'provider-id', + 'piece-cid2', + 'payload-cid-1', + 'payload-cid-2', + ) const res = await fetch(new URL('/sample/provider-id/piece-cid', baseUrl)) await assertResponseStatus(res, 200) const body = await res.json() assert.deepStrictEqual(body, { - samples: ['payload-cid-1'] + samples: ['payload-cid-1'], }) assert.strictEqual( res.headers.get('cache-control'), - `public, max-age=${24 * 3600}, immutable` + `public, max-age=${24 * 3600}, immutable`, ) }) @@ -73,12 +86,9 @@ describe('HTTP request handler', () => { const body = await res.json() assert.deepStrictEqual(body, { - error: 'PROVIDER_OR_PIECE_NOT_FOUND' + error: 'PROVIDER_OR_PIECE_NOT_FOUND', }) - assert.strictEqual( - res.headers.get('cache-control'), - `public, max-age=${60}` - ) + assert.strictEqual(res.headers.get('cache-control'), `public, max-age=${60}`) }) it('returns error when provider piece is not found', async () => { @@ -89,12 +99,9 @@ describe('HTTP request handler', () => { const body = await res.json() assert.deepStrictEqual(body, { - error: 'PROVIDER_OR_PIECE_NOT_FOUND' + error: 'PROVIDER_OR_PIECE_NOT_FOUND', }) - assert.strictEqual( - res.headers.get('cache-control'), - `public, max-age=${60}` - ) + assert.strictEqual(res.headers.get('cache-control'), `public, max-age=${60}`) }) }) @@ -115,20 +122,17 @@ describe('HTTP request handler', () => { lastHeadWalkedFrom: 'last-head', adsMissingPieceCID: 0, entriesNotRetrievable: 0, - piecesIndexed: 1 + piecesIndexed: 1, }) - assert.strictEqual( - res.headers.get('cache-control'), - `public, max-age=${60}` - ) + assert.strictEqual(res.headers.get('cache-control'), `public, max-age=${60}`) }) it('returns error for an unknown provider', async () => { await repository.setWalkerState('provider-id', { status: 'walking', tail: 'tail', - lastHead: 'last-head' + lastHead: 'last-head', }) await repository.addPiecePayloadBlocks('provider-id', 'piece-cid', 'bafy1') @@ -138,13 +142,10 @@ describe('HTTP request handler', () => { assert.deepStrictEqual(body, { providerId: 'unknown-provider-id', - ingestionStatus: 'Unknown provider ID' + ingestionStatus: 'Unknown provider ID', }) - assert.strictEqual( - res.headers.get('cache-control'), - `public, max-age=${60}` - ) + assert.strictEqual(res.headers.get('cache-control'), `public, max-age=${60}`) }) it('returns "head" as "lastHead" when the initial walk has not finished yet', async () => { @@ -161,13 +162,10 @@ describe('HTTP request handler', () => { lastHeadWalkedFrom: 'head', adsMissingPieceCID: 0, entriesNotRetrievable: 0, - piecesIndexed: 1 + piecesIndexed: 1, }) - assert.strictEqual( - res.headers.get('cache-control'), - `public, max-age=${60}` - ) + assert.strictEqual(res.headers.get('cache-control'), `public, max-age=${60}`) }) it('returns the number of adsMissingPieceCID and entriesNotRetrievable', async () => { @@ -175,7 +173,7 @@ describe('HTTP request handler', () => { status: 'walking', head: 'head', entriesNotRetrievable: 10, - adsMissingPieceCID: 20 + adsMissingPieceCID: 20, }) const res = await fetch(new URL('/ingestion-status/provider-id', baseUrl)) @@ -188,13 +186,10 @@ describe('HTTP request handler', () => { lastHeadWalkedFrom: 'head', entriesNotRetrievable: 10, adsMissingPieceCID: 20, - piecesIndexed: 0 + piecesIndexed: 0, }) - assert.strictEqual( - res.headers.get('cache-control'), - `public, max-age=${60}` - ) + assert.strictEqual(res.headers.get('cache-control'), `public, max-age=${60}`) }) }) }) diff --git a/api/test/test-helpers.js b/api/test/test-helpers.js index f4a3904..5b95c84 100644 --- a/api/test/test-helpers.js +++ b/api/test/test-helpers.js @@ -5,7 +5,7 @@ export const assertResponseStatus = async (res, status) => { throw new AssertionError({ actual: res.status, expected: status, - message: `Unexpected status code ${res.status} (expected ${status}). Response body: ${await res.text() || '(empty)'}` + message: `Unexpected status code ${res.status} (expected ${status}). Response body: ${(await res.text()) || '(empty)'}`, }) } } diff --git a/docs/design.md b/docs/design.md index 9ff5d30..1081a3d 100644 --- a/docs/design.md +++ b/docs/design.md @@ -4,86 +4,77 @@ ### Context -Filecoin defines a `Piece` as the main unit of negotiation for data that users -_store_ on the Filecoin network. This is reflected in the on-chain metadata -field `PieceCID`. +Filecoin defines a `Piece` as the main unit of negotiation for data that users _store_ on the +Filecoin network. This is reflected in the on-chain metadata field `PieceCID`. -On the other hand, content is _retrieved_ from Filecoin using the CID of the -requested payload. +On the other hand, content is _retrieved_ from Filecoin using the CID of the requested payload. -This dichotomy poses a challenge for retrieval checkers like Spark: for a given -deal storing some PieceCID, what payload CID to request when testing the -retrieval? +This dichotomy poses a challenge for retrieval checkers like Spark: for a given deal storing some +PieceCID, what payload CID to request when testing the retrieval? -Spark v1 relies on StorageMarket's DealProposal metadata `Label`, which is often -(but not always!) set by the client to the root CID of the payload stored. +Spark v1 relies on StorageMarket's DealProposal metadata `Label`, which is often (but not always!) +set by the client to the root CID of the payload stored. -In the first half of 2024, the Filecoin network added support for DDO (Direct -Data Onboarding) deals. These deals don't have any DealProposal, there is no -`Label` field. Only `PieceCID`. We need to find a different solution to support -these deals. +In the first half of 2024, the Filecoin network added support for DDO (Direct Data Onboarding) +deals. These deals don't have any DealProposal, there is no `Label` field. Only `PieceCID`. We need +to find a different solution to support these deals. -In the longer term, we want IPNI to provide a reverse lookup functionality that -will allow clients like Spark to request a sample of payload block CIDs -associated with the given ContextID or PieceCID, see the +In the longer term, we want IPNI to provide a reverse lookup functionality that will allow clients +like Spark to request a sample of payload block CIDs associated with the given ContextID or +PieceCID, see the [design proposal for InterPlanetary Piece Index](https://docs.google.com/document/d/1jhvP48ccUltmCr4xmquTnbwfTSD7LbO1i1OVil04T2w). -To cover the gap until the InterPlanetary Piece Index is live, we want to -implement a lightweight solution that can serve as a stepping stone between -Label-based CID discovery and full Piece Index sampling. +To cover the gap until the InterPlanetary Piece Index is live, we want to implement a lightweight +solution that can serve as a stepping stone between Label-based CID discovery and full Piece Index +sampling. ### High-Level Idea -Let's implement a lightweight IPNI ingester that will process the advertisements -from Filecoin SPs and extract the list of `(ProviderID, PieceCID, PayloadCID)` -entries. Store these entries in a persisted datastore (Redis). Provide a REST -API endpoint accepting `(ProviderID, PieceCID)` and returning a single -`PayloadCID`. +Let's implement a lightweight IPNI ingester that will process the advertisements from Filecoin SPs +and extract the list of `(ProviderID, PieceCID, PayloadCID)` entries. Store these entries in a +persisted datastore (Redis). Provide a REST API endpoint accepting `(ProviderID, PieceCID)` and +returning a single `PayloadCID`. ### Terminology -- **Indexer:** A network node that keeps a mappings of multihashes to provider - records. Example: https://cid.contact +- **Indexer:** A network node that keeps a mappings of multihashes to provider records. Example: + https://cid.contact -- **Index Provider (a.k.a Publisher):** An entity that publishes advertisements - and index data to an indexer. It is usually, but not always, the same as the - data provider. Example: a [Boost](https://boost.filecoin.io) instance operated - by a Storage Provider. +- **Index Provider (a.k.a Publisher):** An entity that publishes advertisements and index data to an + indexer. It is usually, but not always, the same as the data provider. Example: a + [Boost](https://boost.filecoin.io) instance operated by a Storage Provider. Quoting from [IPNI spec](https://github.com/ipni/specs/blob/90648bca4749ef912b2d18f221514bc26b5bef0a/IPNI.md#terminology): -- **Advertisement**: A record available from a publisher that contains, a link - to a chain of multihash blocks, the CID of the previous advertisement, and - provider-specific content metadata that is referenced by all the multihashes - in the linked multihash blocks. The provider data is identified by a key - called a context ID. - -- **Announce Message**: A message that informs indexers about the availability - of an advertisement. This is usually sent via gossip pubsub, but can also be - sent via HTTP. An announce message contains the advertisement CID it is - announcing, which allows indexers to ignore the announce if they have already - indexed the advertisement. The publisher's address is included in the announce +- **Advertisement**: A record available from a publisher that contains, a link to a chain of + multihash blocks, the CID of the previous advertisement, and provider-specific content metadata + that is referenced by all the multihashes in the linked multihash blocks. The provider data is + identified by a key called a context ID. + +- **Announce Message**: A message that informs indexers about the availability of an advertisement. + This is usually sent via gossip pubsub, but can also be sent via HTTP. An announce message + contains the advertisement CID it is announcing, which allows indexers to ignore the announce if + they have already indexed the advertisement. The publisher's address is included in the announce to tell indexers where to retrieve the advertisement from. -- **Context ID**: A key that, for a provider, uniquely identifies content - metadata. This allows content metadata to be updated or delete on the indexer - without having to refer to it using the multihashes that map to it. +- **Context ID**: A key that, for a provider, uniquely identifies content metadata. This allows + content metadata to be updated or delete on the indexer without having to refer to it using the + multihashes that map to it. -- **Metadata**: Provider-specific data that a retrieval client gets from an - indexer query and passed to the provider when retrieving content. This - metadata is used by the provider to identify and find specific content and - deliver that content via the protocol (e.g. graphsync) specified in the +- **Metadata**: Provider-specific data that a retrieval client gets from an indexer query and passed + to the provider when retrieving content. This metadata is used by the provider to identify and + find specific content and deliver that content via the protocol (e.g. graphsync) specified in the metadata. -- **Provider**: Also called a Storage Provider, this is the entity from which - content can be retrieved by a retrieval client. When multihashes are looked up - on an indexer, the responses contain provider that provide the content - referenced by the multihashes. A provider is identified by a libp2p peer ID. +- **Provider**: Also called a Storage Provider, this is the entity from which content can be + retrieved by a retrieval client. When multihashes are looked up on an indexer, the responses + contain provider that provide the content referenced by the multihashes. A provider is identified + by a libp2p peer ID. -- **Publisher**: This is an entity that publishes advertisements and index data - to an indexer. It is usually, but not always, the same as the data provider. A - publisher is identified by a libp2p peer ID. +- **Publisher**: This is an entity that publishes advertisements and index data to an indexer. It is + usually, but not always, the same as the data provider. A publisher is identified by a libp2p peer + ID. ### Notes @@ -91,101 +82,90 @@ Quoting from There are two components in this design: -- A deal tracker component observing StorageMarket & DDO deals to build a list - of deals eligible for Spark retrieval testing. We define deal as a tuple - `(PieceCID, MinerID, ClientID)`. +- A deal tracker component observing StorageMarket & DDO deals to build a list of deals eligible for + Spark retrieval testing. We define deal as a tuple `(PieceCID, MinerID, ClientID)`. -- A piece indexer observing IPNI announcements to build an index mapping - PieceCIDs to PayloadCIDs. +- A piece indexer observing IPNI announcements to build an index mapping PieceCIDs to PayloadCIDs. -When Spark builds a list of tasks for the current round, it will ask the deal -tracker for 1000 active deals. This ensures we test retrievals for active deals -only. +When Spark builds a list of tasks for the current round, it will ask the deal tracker for 1000 +active deals. This ensures we test retrievals for active deals only. -When Spark checker tests retrieval, it will first consult the piece indexer to -convert deal's PieceCID to a payload CID to retrieve. +When Spark checker tests retrieval, it will first consult the piece indexer to convert deal's +PieceCID to a payload CID to retrieve. **Expired Deals** -Pieces are immutable. If we receive an advertisement saying that a payload block -CID was found in a piece CID, then this information remains valid forever, even -after the SP advertise that they are no longer storing that block. This means -our indexer can ignore `IsRm` advertisements. +Pieces are immutable. If we receive an advertisement saying that a payload block CID was found in a +piece CID, then this information remains valid forever, even after the SP advertise that they are no +longer storing that block. This means our indexer can ignore `IsRm` advertisements. -It's ok if the piece indexer stores data for expired deals, because Spark is not -going to ask for that data. (Of course, there is the cost of storing data we -don't need, but we don't have to deal with that yet.) +It's ok if the piece indexer stores data for expired deals, because Spark is not going to ask for +that data. (Of course, there is the cost of storing data we don't need, but we don't have to deal +with that yet.) **Payload CIDs Are Scoped to Providers** -The indexer protocol does not provide any guarantees about the list of CIDs -advertised for the same Piece CID. Different SPs can advertise different lists -(e.g. the entries can be ordered differently) or can even cheat and submit CIDs -that are not part of the Piece. Our indexer must scope the information to each -index provider (each Filecoin SP). +The indexer protocol does not provide any guarantees about the list of CIDs advertised for the same +Piece CID. Different SPs can advertise different lists (e.g. the entries can be ordered differently) +or can even cheat and submit CIDs that are not part of the Piece. Our indexer must scope the +information to each index provider (each Filecoin SP). ### Anatomy of IPNI Advertisements Quoting from [Ingestion](https://github.com/ipni/specs/blob/90648bca4749ef912b2d18f221514bc26b5bef0a/IPNI.md#ingestion): -> The indexer reads the advertisement chain starting from the head, reading -> previous advertisements until a previously seen advertisement, or the end of -> the chain, is reached. The advertisements and their entries are then processed -> in order from earliest to head. +> The indexer reads the advertisement chain starting from the head, reading previous advertisements +> until a previously seen advertisement, or the end of the chain, is reached. The advertisements and +> their entries are then processed in order from earliest to head. An Advertisement has several properties (see [the full spec](https://github.com/ipni/specs/blob/90648bca4749ef912b2d18f221514bc26b5bef0a/IPNI.md#advertisements)), we need the following ones: -- **`PreviousID`** is the CID of the previous advertisement, and is empty for - the 'genesis'. +- **`PreviousID`** is the CID of the previous advertisement, and is empty for the 'genesis'. -- **`Metadata`** represents additional opaque data. The metadata for Graphsync - retrievals includes the PieceCID that we are looking for. +- **`Metadata`** represents additional opaque data. The metadata for Graphsync retrievals includes + the PieceCID that we are looking for. -- **`Entries`** is a link to a data structure that contains the advertised - multihashes. For our purposes, it's enough to take the first entry and ignore - the rest. +- **`Entries`** is a link to a data structure that contains the advertised multihashes. For our + purposes, it's enough to take the first entry and ignore the rest. -Advertisements are made available for consumption by indexer nodes as a set of -files that can be fetched via HTTP. +Advertisements are made available for consumption by indexer nodes as a set of files that can be +fetched via HTTP. Quoting from [Advertisement Transfer](https://github.com/ipni/specs/blob/90648bca4749ef912b2d18f221514bc26b5bef0a/IPNI.md#advertisement-transfer): -> All IPNI HTTP requests use the IPNI URL path prefix, `/ipni/v1/ad/`. Indexers -> and advertisement publishers implicitly use and expect this prefix to precede -> the requested resource. +> All IPNI HTTP requests use the IPNI URL path prefix, `/ipni/v1/ad/`. Indexers and advertisement +> publishers implicitly use and expect this prefix to precede the requested resource. > -> The IPLD objects of advertisements and entries are represented as files named -> by their CIDs in an HTTP directory. These files are immutable, so can be -> safely cached or stored on CDNs. To fetch an advertisement or entries file by -> CID, the request made by the indexer to the publisher is +> The IPLD objects of advertisements and entries are represented as files named by their CIDs in an +> HTTP directory. These files are immutable, so can be safely cached or stored on CDNs. To fetch an +> advertisement or entries file by CID, the request made by the indexer to the publisher is > `GET /ipni/v1/ad/{CID}`. -The IPNI instance running at https://cid.contact provides an API returning the -list of all index providers from which cid.contact have received announcements: +The IPNI instance running at https://cid.contact provides an API returning the list of all index +providers from which cid.contact have received announcements: https://cid.contact/providers -The response provides all the metadata we need to download the advertisements. -For each index provider, the response includes: +The response provides all the metadata we need to download the advertisements. For each index +provider, the response includes: -- `Publisher.Addrs` describes where we can contact SP's index provider to - retrieve content for CIDs, e.g., advertisements. +- `Publisher.Addrs` describes where we can contact SP's index provider to retrieve content for CIDs, + e.g., advertisements. - `LastAdvertisement` contains the CID of the head advertisement from the SP ## Proposed Design ### Ingestion -Ingesting announcements from all Storage Providers is the most complex -component. For each storage provider, we need to periodically check for the -latest advertisement head and process the chain from head until we find an -advertisement we have already processed before. The chain can be very long, -therefore we need to account for the cases when the service restarts or a new -head is published before we finish processing the chain. +Ingesting announcements from all Storage Providers is the most complex component. For each storage +provider, we need to periodically check for the latest advertisement head and process the chain from +head until we find an advertisement we have already processed before. The chain can be very long, +therefore we need to account for the cases when the service restarts or a new head is published +before we finish processing the chain. #### Proposed algorithm @@ -197,49 +177,45 @@ Use the following per-provider state: - Provider info obtained from IPNI - stored in memory only: - - `providerAddress` - Provider's address where we can fetch advertisements - from. + - `providerAddress` - Provider's address where we can fetch advertisements from. - - `lastAdvertisementCID` - The CID of the most recent head seen by - cid.contact. This is where we need to start the next walk from. + - `lastAdvertisementCID` - The CID of the most recent head seen by cid.contact. This is where we + need to start the next walk from. - Provider walker state - persisted in our datastore (Redis): - - `head` - The CID of the head advertisement we started the current walk from. - We update this value whenever we start a new walk. + - `head` - The CID of the head advertisement we started the current walk from. We update this + value whenever we start a new walk. - - `tail` - The CID of the next advertisement in the chain that we need to - process in the current walk. + - `tail` - The CID of the next advertisement in the chain that we need to process in the current + walk. - - `lastHead` - The CID of the head where we started the previous walk (the - last walk that has already finished). All advertisements from `lastHead` to - the end of the chain have already been processed. + - `lastHead` - The CID of the head where we started the previous walk (the last walk that has + already finished). All advertisements from `lastHead` to the end of the chain have already been + processed. - > **Note:** The initial walk will take a long time to complete. While we are - > walking the "old" chain, new advertisements (new heads) will be announced - > to IPNI. + > **Note:** The initial walk will take a long time to complete. While we are walking the "old" + > chain, new advertisements (new heads) will be announced to IPNI. > > - `lastAdvertisementCID` is the latest head announced to IPNI > - `head` is the advertisement where the current walk-in-progress started > - > I suppose we don't need to keep track of `lastAdvertisementCID`. When the - > current walk finishes, we could wait up to one minute until we make - > another request to cid.contact to find what are the latest heads for each - > SPs. + > I suppose we don't need to keep track of `lastAdvertisementCID`. When the current walk + > finishes, we could wait up to one minute until we make another request to cid.contact to find + > what are the latest heads for each SPs. > - > In the current proposal, when the current walk finishes, we can - > immediately continue with walking from the `lastAdvertisementCID`. + > In the current proposal, when the current walk finishes, we can immediately continue with + > walking from the `lastAdvertisementCID`. -We must always walk the chain all the way to the genesis or to the entry we have -already seen & processed. +We must always walk the chain all the way to the genesis or to the entry we have already seen & +processed. -The current walk starts from `head` and walks up to `lastHead`. When the current -walk reaches `lastHead`, we need to set `lastHead ← head` so that the next walk -knows where to stop. +The current walk starts from `head` and walks up to `lastHead`. When the current walk reaches +`lastHead`, we need to set `lastHead ← head` so that the next walk knows where to stop. -`lastAdvertisementCID` is updated every minute when we query cid.contact for the -latest heads. If the walk takes longer than a minute to finish, then -`lastAdvertisementCID` will change and we cannot use it for `lastHead`. +`lastAdvertisementCID` is updated every minute when we query cid.contact for the latest heads. If +the walk takes longer than a minute to finish, then `lastAdvertisementCID` will change and we cannot +use it for `lastHead`. Here is how the state looks like in the middle of a walk: @@ -278,26 +254,22 @@ Every minute, run the following high-level loop: 1. Fetch the list of providers and their latest advertisements (heads) from https://cid.contact/providers. (This is **one** HTTP request.) -2. Update the in-memory info we keep for each provider (address, CID of the last - advertisement). +2. Update the in-memory info we keep for each provider (address, CID of the last advertisement). -> **Note:** Instead of running the loop every minute, we can introduce a -> one-minute delay between the iterations instead. It should not matter too much -> in practice, though. I expect each iteration to finish within one minute, as -> it's just a single HTTP call to cid.contact. +> **Note:** Instead of running the loop every minute, we can introduce a one-minute delay between +> the iterations instead. It should not matter too much in practice, though. I expect each iteration +> to finish within one minute, as it's just a single HTTP call to cid.contact. **Walk advertisement chains (in background)** -The chain-walking algorithm runs in the background and loops over the following -steps. +The chain-walking algorithm runs in the background and loops over the following steps. 1. Preparation - - If `tail` is not null, then there is an ongoing walk of the chain we need - to continue. + - If `tail` is not null, then there is an ongoing walk of the chain we need to continue. - - Otherwise, if `nextHead` is the same as `lastHead`, then there are no new - advertisement to process and the walk immediately returns. + - Otherwise, if `nextHead` is the same as `lastHead`, then there are no new advertisement to + process and the walk immediately returns. - Otherwise, we are starting a new walk. Update the walker state as follows: @@ -312,14 +284,13 @@ steps. 1. Fetch the advertisement identified by `tail` from the index provider. - 2. Process the metadata and entries to extract up to one - `(PieceCID, PayloadCID)` entry to be added to the index and `PreviousID` - linking to the next advertisement in the chain to process. + 2. Process the metadata and entries to extract up to one `(PieceCID, PayloadCID)` entry to be + added to the index and `PreviousID` linking to the next advertisement in the chain to process. 3. Update the worker state - - If `PreviousID == lastHead || PreviousID == null`, then we finished the - walk. Update the state as follows: + - If `PreviousID == lastHead || PreviousID == null`, then we finished the walk. Update the state + as follows: ``` lastHead := head @@ -327,8 +298,7 @@ steps. tail := null ``` - - Otherwise, update the `tail` field using the `PreviousID` field from the - advertisement. + - Otherwise, update the `tail` field using the `PreviousID` field from the advertisement. ``` tail := PreviousID @@ -338,33 +308,29 @@ steps. #### Handling the Scale -At the time of writing this document, cid.contact was tracking 322 index -providers. From Sparks' measurements, we know there are an additional 843 -storage providers that don't advertise to IPNI. The number of storage providers -grows over time, our system must be prepared to ingest advertisements from -thousands of providers. +At the time of writing this document, cid.contact was tracking 322 index providers. From Sparks' +measurements, we know there are an additional 843 storage providers that don't advertise to IPNI. +The number of storage providers grows over time, our system must be prepared to ingest +advertisements from thousands of providers. -Each storage/index provider produces tens of thousands to hundreds of thousands -of advertisements (in total). The initial ingestion run will take a while to -complete. We also must be careful to not overload the SP by sending too many -requests. +Each storage/index provider produces tens of thousands to hundreds of thousands of advertisements +(in total). The initial ingestion run will take a while to complete. We also must be careful to not +overload the SP by sending too many requests. -The design outlined in the previous section divides the ingestion process into -small steps that can be scheduled and executed independently. This allows us to -avoid the complexity of managing long-running per-provider tasks and instead -repeatedly execute one step of the process. +The design outlined in the previous section divides the ingestion process into small steps that can +be scheduled and executed independently. This allows us to avoid the complexity of managing +long-running per-provider tasks and instead repeatedly execute one step of the process. -However, requests for advertisements from providers can take different amount of -time. Some providers are not configured properly and the request fails after a -long timeout. Such slow providers must not block the ingestion of advertisements -from faster providers, therefore we still need some sort of a per-provider task -runner. +However, requests for advertisements from providers can take different amount of time. Some +providers are not configured properly and the request fails after a long timeout. Such slow +providers must not block the ingestion of advertisements from faster providers, therefore we still +need some sort of a per-provider task runner. ### REST API -Implement the following endpoint that will be called by Spark checker nodes. The -endpoint will sign the response using the server's private key to allow -spark-evaluate to verify the authenticity of results reported by checker nodes: +Implement the following endpoint that will be called by Spark checker nodes. The endpoint will sign +the response using the server's private key to allow spark-evaluate to verify the authenticity of +results reported by checker nodes: ``` GET /sample/{providerId}/{pieceCid}?seed={seed} @@ -390,24 +356,22 @@ Response in JSON format, when the piece or the provider was not found: } ``` -In the initial version, the server will ignore the `seed` value and use it only -as a nonce preventing replay attacks. Spark checker nodes will set the seed -using the DRAND randomness string for the current Spark round. +In the initial version, the server will ignore the `seed` value and use it only as a nonce +preventing replay attacks. Spark checker nodes will set the seed using the DRAND randomness string +for the current Spark round. -In the future, when IPNI implements the proposed reverse-index sampling -endpoint, the seed will be used to pick the samples at random. See the +In the future, when IPNI implements the proposed reverse-index sampling endpoint, the seed will be +used to pick the samples at random. See the [IPNI Multihash Sampling API proposal](https://github.com/ipni/xedni/blob/526f90f5a6001cb50b52e6376f8877163f8018af/openapi.yaml) ### Observability -We need visibility into the status of ingestion for any given provider. Some -providers don't advertise at all, some may have misconfigured integration with -IPNI, we need to understand why our index does not include any data for a -provider. +We need visibility into the status of ingestion for any given provider. Some providers don't +advertise at all, some may have misconfigured integration with IPNI, we need to understand why our +index does not include any data for a provider. -Let's enhance the state table with another column describing the ingestion -status as a free-form string and implement a new REST API endpoint to query the -ingestion status. +Let's enhance the state table with another column describing the ingestion status as a free-form +string and implement a new REST API endpoint to query the ingestion status. ``` GET /ingestion-status/{providerId} diff --git a/indexer/bin/piece-indexer.js b/indexer/bin/piece-indexer.js index 563e2dd..0a8d994 100644 --- a/indexer/bin/piece-indexer.js +++ b/indexer/bin/piece-indexer.js @@ -8,9 +8,7 @@ import { runIpniSync } from '../lib/ipni-watcher.js' /** @import { ProviderToInfoMap } from '../lib/typings.d.ts' */ -const { - REDIS_URL: redisUrl = 'redis://localhost:6379' -} = process.env +const { REDIS_URL: redisUrl = 'redis://localhost:6379' } = process.env const redisUrlParsed = new URL(redisUrl) const redis = new Redis({ @@ -19,7 +17,7 @@ const redis = new Redis({ username: redisUrlParsed.username, password: redisUrlParsed.password, lazyConnect: true, // call connect() explicitly so that we can exit on connection error - family: 6 // required for upstash + family: 6, // required for upstash }) await redis.connect() @@ -50,9 +48,7 @@ for await (const providerInfos of runIpniSync({ minSyncIntervalInMs: 60_000 })) repository, providerId, getProviderInfo, - minStepIntervalInMs: 100 - }).finally( - () => providerIdsBeingWalked.delete(providerId) - ) + minStepIntervalInMs: 100, + }).finally(() => providerIdsBeingWalked.delete(providerId)) } } diff --git a/indexer/lib/advertisement-walker.js b/indexer/lib/advertisement-walker.js index a2647d2..64caa6b 100644 --- a/indexer/lib/advertisement-walker.js +++ b/indexer/lib/advertisement-walker.js @@ -22,12 +22,12 @@ const debug = createDebug('spark-piece-indexer:advertisement-walker') * @param {number} args.minStepIntervalInMs * @param {AbortSignal} [args.signal] */ -export async function walkChain ({ +export async function walkChain({ repository, providerId, getProviderInfo, minStepIntervalInMs, - signal + signal, }) { let stepInterval = minStepIntervalInMs let walkerState @@ -45,12 +45,17 @@ export async function walkChain ({ failed = !!result.failed } catch (err) { failed = true - console.error('Error indexing provider %s (%s):', providerId, providerInfo.providerAddress, err) + console.error( + 'Error indexing provider %s (%s):', + providerId, + providerInfo.providerAddress, + err, + ) Sentry.captureException(err, { extra: { providerId, - providerAddress: providerInfo.providerAddress - } + providerAddress: providerInfo.providerAddress, + }, }) } @@ -65,7 +70,12 @@ export async function walkChain ({ const delay = stepInterval - (Date.now() - started) if (delay > 0) { - debug('Waiting for %sms before the next walk for provider %s (%s)', delay, providerId, providerInfo.providerAddress) + debug( + 'Waiting for %sms before the next walk for provider %s (%s)', + delay, + providerId, + providerInfo.providerAddress, + ) await timers.setTimeout(delay) } } @@ -79,19 +89,29 @@ export async function walkChain ({ * @param {WalkerState} [args.walkerState] * @param {number} [args.fetchTimeout] */ -export async function walkOneStep ({ repository, providerId, providerInfo, fetchTimeout, walkerState }) { +export async function walkOneStep({ + repository, + providerId, + providerInfo, + fetchTimeout, + walkerState, +}) { if (!walkerState) { - debug('FETCHING walker state from the repository for provider %s (%s)', providerId, providerInfo.providerAddress) + debug( + 'FETCHING walker state from the repository for provider %s (%s)', + providerId, + providerInfo.providerAddress, + ) walkerState = await repository.getWalkerState(providerId) } else { debug('REUSING walker state for provider %s (%s)', providerId, providerInfo.providerAddress) } - const { - newState, - indexEntry, - failed, - finished - } = await processNextAdvertisement({ providerId, providerInfo, walkerState, fetchTimeout }) + const { newState, indexEntry, failed, finished } = await processNextAdvertisement({ + providerId, + providerInfo, + walkerState, + fetchTimeout, + }) if (newState) { await repository.setWalkerState(providerId, newState) @@ -110,20 +130,24 @@ export async function walkOneStep ({ repository, providerId, providerInfo, fetch * @param {WalkerState | undefined} args.walkerState * @param {number} [args.fetchTimeout] */ -export async function processNextAdvertisement ({ +export async function processNextAdvertisement({ providerId, providerInfo, walkerState, - fetchTimeout + fetchTimeout, }) { if (!providerInfo.providerAddress?.match(/^https?:\/\//)) { - debug('Skipping provider %s - address is not HTTP(s): %s', providerId, providerInfo.providerAddress) + debug( + 'Skipping provider %s - address is not HTTP(s): %s', + providerId, + providerInfo.providerAddress, + ) return { /** @type {WalkerState} */ newState: { - status: `Index provider advertises over an unsupported protocol: ${providerInfo.providerAddress}` + status: `Index provider advertises over an unsupported protocol: ${providerInfo.providerAddress}`, }, - finished: true + finished: true, } } @@ -133,18 +157,28 @@ export async function processNextAdvertisement ({ let state if (walkerState?.tail) { - debug('Next step for provider %s (%s): %s', providerId, providerInfo.providerAddress, walkerState.tail) + debug( + 'Next step for provider %s (%s): %s', + providerId, + providerInfo.providerAddress, + walkerState.tail, + ) state = { ...walkerState } } else if (nextHead === walkerState?.lastHead) { debug('No new advertisements from provider %s (%s)', providerId, providerInfo.providerAddress) return { finished: true } } else { - debug('New walk for provider %s (%s): %s', providerId, providerInfo.providerAddress, providerInfo.lastAdvertisementCID) + debug( + 'New walk for provider %s (%s): %s', + providerId, + providerInfo.providerAddress, + providerInfo.lastAdvertisementCID, + ) state = { head: nextHead, tail: nextHead, lastHead: walkerState?.lastHead, - status: 'placeholder' + status: 'placeholder', } } @@ -155,7 +189,7 @@ export async function processNextAdvertisement ({ const { previousAdvertisementCid, entry, error } = await fetchAdvertisedPayload( providerInfo.providerAddress, state.tail, - { fetchTimeout } + { fetchTimeout }, ) if (!previousAdvertisementCid || previousAdvertisementCid === state.lastHead) { @@ -181,7 +215,7 @@ export async function processNextAdvertisement ({ return { newState: state, indexEntry, - finished + finished, } } catch (err) { const errorDescription = describeFetchError(err, providerInfo.providerAddress) @@ -191,12 +225,12 @@ export async function processNextAdvertisement ({ providerId, providerInfo.providerAddress, state.tail, - errorDescription ?? err + errorDescription ?? err, ) state.status = `Error processing ${state.tail}: ${errorDescription ?? 'internal error'}` return { newState: state, - failed: true + failed: true, } } } @@ -206,7 +240,7 @@ export async function processNextAdvertisement ({ * @param {string} providerAddress * @returns {string | undefined} */ -function describeFetchError (err, providerAddress) { +function describeFetchError(err, providerAddress) { if (!(err instanceof Error)) return undefined let reason @@ -221,9 +255,9 @@ function describeFetchError (err, providerAddress) { reason = 'operation timed out' } else if ( err.name === 'TypeError' && - err.message === 'fetch failed' && - err.cause && - err.cause instanceof Error + err.message === 'fetch failed' && + err.cause && + err.cause instanceof Error ) { reason = err.cause.message } @@ -240,9 +274,12 @@ function describeFetchError (err, providerAddress) { * @param {object} [options] * @param {number} [options.fetchTimeout] */ -export async function fetchAdvertisedPayload (providerAddress, advertisementCid, { fetchTimeout } = {}) { - const advertisement = - /** @type {{ +export async function fetchAdvertisedPayload( + providerAddress, + advertisementCid, + { fetchTimeout } = {}, +) { + const advertisement = /** @type {{ Addresses: string[], ContextID: { '/': { bytes: string } }, Entries: { '/': string }, @@ -255,9 +292,7 @@ export async function fetchAdvertisedPayload (providerAddress, advertisementCid, bytes: string } } - }} */( - await pRetry(() => fetchCid(providerAddress, advertisementCid, { fetchTimeout })) - ) + }} */ (await pRetry(() => fetchCid(providerAddress, advertisementCid, { fetchTimeout }))) const previousAdvertisementCid = advertisement.PreviousID?.['/'] debug('advertisement %s %j', advertisementCid, advertisement) @@ -278,10 +313,15 @@ export async function fetchAdvertisedPayload (providerAddress, advertisementCid, } if (!pieceCid) { - debug('advertisement %s has no PieceCID in ContextId: %j or metadata: %j', advertisementCid, advertisement.ContextID, meta?.deal) + debug( + 'advertisement %s has no PieceCID in ContextId: %j or metadata: %j', + advertisementCid, + advertisement.ContextID, + meta?.deal, + ) return { - error: /** @type {const} */('MISSING_PIECE_CID'), - previousAdvertisementCid + error: /** @type {const} */ ('MISSING_PIECE_CID'), + previousAdvertisementCid, } } @@ -291,28 +331,21 @@ export async function fetchAdvertisedPayload (providerAddress, advertisementCid, () => /** @type {Promise<{ Entries: { '/' : { bytes: string } }[] - }>} */( - fetchCid(providerAddress, entriesCid, { fetchTimeout }) - ), + }>} */ (fetchCid(providerAddress, entriesCid, { fetchTimeout })), { shouldRetry: (err) => - err && 'statusCode' in err && typeof err.statusCode === 'number' && err.statusCode >= 500 - } + err && 'statusCode' in err && typeof err.statusCode === 'number' && err.statusCode >= 500, + }, ) } catch (err) { // We are not able to fetch the advertised entries. Skip this advertisement so that we can // continue the ingestion of other advertisements. const errorDescription = describeFetchError(err, providerAddress) - const log = /** @type {any} */(err)?.statusCode === 404 ? debug : console.warn - log( - 'Cannot fetch ad %s entries %s: %s', - advertisementCid, - entriesCid, - errorDescription ?? err - ) + const log = /** @type {any} */ (err)?.statusCode === 404 ? debug : console.warn + log('Cannot fetch ad %s entries %s: %s', advertisementCid, entriesCid, errorDescription ?? err) return { - error: /** @type {const} */('ENTRIES_NOT_RETRIEVABLE'), - previousAdvertisementCid + error: /** @type {const} */ ('ENTRIES_NOT_RETRIEVABLE'), + previousAdvertisementCid, } } @@ -322,14 +355,14 @@ export async function fetchAdvertisedPayload (providerAddress, advertisementCid, } catch (err) { debug('Error processing entries: %s', err) return { - error: /** @type {const} */('PAYLOAD_CID_NOT_EXTRACTABLE'), - previousAdvertisementCid + error: /** @type {const} */ ('PAYLOAD_CID_NOT_EXTRACTABLE'), + previousAdvertisementCid, } } return { previousAdvertisementCid, - entry: { pieceCid, payloadCid } + entry: { pieceCid, payloadCid }, } } @@ -341,7 +374,7 @@ export async function fetchAdvertisedPayload (providerAddress, advertisementCid, * @param {typeof fetch} [options.fetchFn] * @returns {Promise} */ -export async function fetchCid (providerBaseUrl, cid, { fetchTimeout, fetchFn } = {}) { +export async function fetchCid(providerBaseUrl, cid, { fetchTimeout, fetchFn } = {}) { let url = new URL(providerBaseUrl) // Check if the URL already has a path @@ -355,7 +388,9 @@ export async function fetchCid (providerBaseUrl, cid, { fetchTimeout, fetchFn } url = new URL(cid, url) debug('Fetching %s', url) try { - const res = await (fetchFn ?? fetch)(url, { signal: AbortSignal.timeout(fetchTimeout ?? 30_000) }) + const res = await (fetchFn ?? fetch)(url, { + signal: AbortSignal.timeout(fetchTimeout ?? 30_000), + }) debug('Response from %s → %s %o', url, res.status, res.headers) await assertOkResponse(res) @@ -369,9 +404,11 @@ export async function fetchCid (providerBaseUrl, cid, { fetchTimeout, fetchFn } case 297: // DAG-JSON return await res.json() - case 113: { // DAG-CBOR + case 113: { + // DAG-CBOR const buffer = await res.arrayBuffer() - return cbor.decode(new Uint8Array(buffer)) } + return cbor.decode(new Uint8Array(buffer)) + } default: throw new Error(`Unknown codec ${codec} for CID ${cid}`) @@ -388,15 +425,16 @@ export async function fetchCid (providerBaseUrl, cid, { fetchTimeout, fetchFn } /** * @param {string} meta */ -export function parseMetadata (meta) { +export function parseMetadata(meta) { const bytes = Buffer.from(meta, 'base64') const [protocolCode, nextOffset] = varint.decode(bytes) - const protocol = { - 0x900: 'bitswap', - 0x910: 'graphsync', - 0x0920: 'http' - }[protocolCode] ?? '0x' + protocolCode.toString(16) + const protocol = + { + 0x900: 'bitswap', + 0x910: 'graphsync', + 0x0920: 'http', + }[protocolCode] ?? '0x' + protocolCode.toString(16) if (protocol === 'graphsync') { // console.log(bytes.subarray(nextOffset).toString('hex')) @@ -420,7 +458,7 @@ export function parseMetadata (meta) { * @param {function} [options.logDebugMessage] - Function to log debug messages * @returns {{pieceCid: string;pieceSize: number}|null} - Object containing pieceCid and pieceSize if successful, null otherwise */ -export function extractPieceInfoFromContextID (contextID, { logDebugMessage } = {}) { +export function extractPieceInfoFromContextID(contextID, { logDebugMessage } = {}) { logDebugMessage ??= debug // Check if ContextID exists and has the expected structure if (!contextID || !contextID['/'] || !contextID['/'].bytes) { @@ -437,35 +475,52 @@ export function extractPieceInfoFromContextID (contextID, { logDebugMessage } = // Validate the decoded data with specific error messages if (!Array.isArray(decoded)) { - logDebugMessage('ContextID validation failed for %s: decoded value is not an array, got %s', - contextID, typeof decoded) + logDebugMessage( + 'ContextID validation failed for %s: decoded value is not an array, got %s', + contextID, + typeof decoded, + ) return null } if (decoded.length !== 2) { - logDebugMessage('ContextID validation failed for %s: expected array with 2 items, got %d items', - contextID, decoded.length) + logDebugMessage( + 'ContextID validation failed for %s: expected array with 2 items, got %d items', + contextID, + decoded.length, + ) return null } const [pieceSize, pieceCid] = decoded if (typeof pieceSize !== 'number') { - logDebugMessage('ContextID validation failed for %s: pieceSize is not a number, got %s', - contextID, typeof decoded[0]) + logDebugMessage( + 'ContextID validation failed for %s: pieceSize is not a number, got %s', + contextID, + typeof decoded[0], + ) return null } if (!(typeof pieceCid === 'object')) { - logDebugMessage('ContextID validation failed for %s: pieceCID is not an object, got %s', - contextID, typeof pieceCid) + logDebugMessage( + 'ContextID validation failed for %s: pieceCID is not an object, got %s', + contextID, + typeof pieceCid, + ) return null } if (pieceCid === null || pieceCid === undefined) { - logDebugMessage('ContextID validation failed for %s: pieceCID is null or undefined', - contextID) + logDebugMessage( + 'ContextID validation failed for %s: pieceCID is null or undefined', + contextID, + ) return null } if (!(pieceCid?.constructor?.name === 'CID')) { - logDebugMessage('ContextID validation failed for %s: pieceCID is not a CID, got %s', - contextID, pieceCid?.constructor?.name) + logDebugMessage( + 'ContextID validation failed for %s: pieceCID is not a CID, got %s', + contextID, + pieceCid?.constructor?.name, + ) return null } @@ -481,7 +536,7 @@ export function extractPieceInfoFromContextID (contextID, { logDebugMessage } = * @param {{Entries: Array}} entriesChunk - The decoded entries * @returns {string} The payload CID */ -export function processEntries (entriesCid, entriesChunk) { +export function processEntries(entriesCid, entriesChunk) { if (!entriesChunk.Entries || !entriesChunk.Entries.length) { throw new Error(`No entries found in the response for ${entriesCid}`) } @@ -509,13 +564,15 @@ export function processEntries (entriesCid, entriesChunk) { throw new Error('DAG-JSON entry\'s ["/"]["bytes"] property must be a string') } entryBytes = Buffer.from(entryHash, 'base64') - break } + break + } case 113: { // DAG-CBOR // For DAG-CBOR format, the entry is already a Uint8Array with the multihash entryBytes = entriesChunk.Entries[0] assert(entryBytes instanceof Uint8Array, 'DAG-CBOR entry must be a Uint8Array') - break } + break + } default: throw new Error(`Unsupported codec ${codec}`) } diff --git a/indexer/lib/instrument.js b/indexer/lib/instrument.js index 7159ad9..8cf7950 100644 --- a/indexer/lib/instrument.js +++ b/indexer/lib/instrument.js @@ -7,19 +7,14 @@ const { SENTRY_ENVIRONMENT = 'development' } = process.env const pkg = JSON.parse( await fs.readFile( - join( - dirname(fileURLToPath(import.meta.url)), - '..', - '..', - 'package.json' - ), - 'utf8' - ) + join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'package.json'), + 'utf8', + ), ) Sentry.init({ dsn: 'https://063b6300f825d76ef0013cfbfdbde270@o1408530.ingest.us.sentry.io/4508002543206400', release: pkg.version, environment: SENTRY_ENVIRONMENT, - tracesSampleRate: 0.1 + tracesSampleRate: 0.1, }) diff --git a/indexer/lib/ipni-watcher.js b/indexer/lib/ipni-watcher.js index 354edd0..18ad578 100644 --- a/indexer/lib/ipni-watcher.js +++ b/indexer/lib/ipni-watcher.js @@ -13,7 +13,7 @@ const debug = createDebug('spark-piece-indexer:ipni-watcher') * @param {number} args.minSyncIntervalInMs * @param {AbortSignal} [args.signal] */ -export async function * runIpniSync ({ minSyncIntervalInMs, signal }) { +export async function* runIpniSync({ minSyncIntervalInMs, signal }) { while (!signal?.aborted) { const started = Date.now() try { @@ -22,7 +22,8 @@ export async function * runIpniSync ({ minSyncIntervalInMs, signal }) { console.log( 'Found %s providers, %s support(s) HTTP(s)', providers.size, - Array.from(providers.values()).filter(p => p.providerAddress.match(/^https?:\/\//)).length + Array.from(providers.values()).filter((p) => p.providerAddress.match(/^https?:\/\//)) + .length, ) yield providers } catch (err) { @@ -40,7 +41,7 @@ export async function * runIpniSync ({ minSyncIntervalInMs, signal }) { /** * @returns {Promise} */ -export async function getProvidersWithMetadata () { +export async function getProvidersWithMetadata() { const res = await fetch('https://cid.contact/providers') assertOkResponse(res) @@ -59,10 +60,10 @@ export async function getProvidersWithMetadata () { }, // Ignored: ExtendedProviders, FrozenAt * }[]} - */(await res.json()) + */ (await res.json()) /** @type {[string, ProviderInfo][]} */ - const entries = providers.map(p => { + const entries = providers.map((p) => { const providerId = p.Publisher.ID const lastAdvertisementCID = p.LastAdvertisement['/'] diff --git a/indexer/lib/typings.d.ts b/indexer/lib/typings.d.ts index f492702..a535907 100644 --- a/indexer/lib/typings.d.ts +++ b/indexer/lib/typings.d.ts @@ -1,16 +1,15 @@ export { PiecePayloadCIDs, ProviderToWalkerStateMap, - WalkerState -} from '@filecoin-station/spark-piece-indexer-repository/lib/typings.d.ts'; + WalkerState, +} from '@filecoin-station/spark-piece-indexer-repository/lib/typings.d.ts' /** * Data synced from IPNI */ export interface ProviderInfo { - providerAddress: string; - lastAdvertisementCID: string; + providerAddress: string + lastAdvertisementCID: string } -export type ProviderToInfoMap = Map; - +export type ProviderToInfoMap = Map diff --git a/indexer/lib/vendored/multiaddr.js b/indexer/lib/vendored/multiaddr.js index da80592..417c22e 100644 --- a/indexer/lib/vendored/multiaddr.js +++ b/indexer/lib/vendored/multiaddr.js @@ -5,12 +5,12 @@ * @param {string} addr Multiaddr, e.g. `/ip4/127.0.0.1/tcp/80/http` * @returns {string} Parsed URI, e.g. `http://127.0.0.1:80` */ -export function multiaddrToHttpUrl (addr) { +export function multiaddrToHttpUrl(addr) { const [multiAddr, httpPathMultiAddr] = addr.split('/http-path') const [, hostType, hostValue, ...multiAddrParts] = multiAddr.split('/') let scheme, path, rest, port if (addr.includes('/http-path')) { - [scheme, ...rest] = multiAddrParts + ;[scheme, ...rest] = multiAddrParts try { // Remove leading slash and parse URI-encoded path // See https://github.com/multiformats/multiaddr/blob/cab92e8e6da2e70c5f1b8aa59976e71e6922b392/protocols/http-path.md#usage @@ -18,7 +18,7 @@ export function multiaddrToHttpUrl (addr) { } catch (err) { throw Object.assign( new Error(`Cannot parse "${addr}": unsupported http path`, { cause: err }), - { code: 'INVALID_HTTP_PATH' } + { code: 'INVALID_HTTP_PATH' }, ) } } else { @@ -28,23 +28,21 @@ export function multiaddrToHttpUrl (addr) { if (ipProtocol !== 'tcp') { throw Object.assign( new Error(`Cannot parse "${addr}": unsupported protocol "${ipProtocol}"`), - { code: 'UNSUPPORTED_MULTIADDR_PROTO' } + { code: 'UNSUPPORTED_MULTIADDR_PROTO' }, ) } } if (scheme !== 'http' && scheme !== 'https') { - throw Object.assign( - new Error(`Cannot parse "${addr}": unsupported scheme "${scheme}"`), - { code: 'UNSUPPORTED_MULTIADDR_SCHEME' } - ) + throw Object.assign(new Error(`Cannot parse "${addr}": unsupported scheme "${scheme}"`), { + code: 'UNSUPPORTED_MULTIADDR_SCHEME', + }) } if (rest.length) { - throw Object.assign( - new Error(`Cannot parse "${addr}": too many parts`), - { code: 'MULTIADDR_HAS_TOO_MANY_PARTS' } - ) + throw Object.assign(new Error(`Cannot parse "${addr}": too many parts`), { + code: 'MULTIADDR_HAS_TOO_MANY_PARTS', + }) } let url = `${scheme}://${getUriHost(hostType, hostValue)}` @@ -53,7 +51,7 @@ export function multiaddrToHttpUrl (addr) { return url } -function getUriHost (hostType, hostValue) { +function getUriHost(hostType, hostValue) { switch (hostType) { case 'ip4': case 'dns': @@ -66,13 +64,12 @@ function getUriHost (hostType, hostValue) { return `[${hostValue}]` } - throw Object.assign( - new Error(`Unsupported multiaddr host type "${hostType}"`), - { code: 'UNSUPPORTED_MULTIADDR_HOST_TYPE' } - ) + throw Object.assign(new Error(`Unsupported multiaddr host type "${hostType}"`), { + code: 'UNSUPPORTED_MULTIADDR_HOST_TYPE', + }) } -function getUriPort (scheme, port) { +function getUriPort(scheme, port) { if (scheme === 'http' && port === '80') return '' if (scheme === 'https' && port === '443') return '' return `:${port}` diff --git a/indexer/test/advertisement-walker.test.js b/indexer/test/advertisement-walker.test.js index b372c43..aacf369 100644 --- a/indexer/test/advertisement-walker.test.js +++ b/indexer/test/advertisement-walker.test.js @@ -8,9 +8,9 @@ import { extractPieceInfoFromContextID, fetchAdvertisedPayload, processNextAdvertisement, - walkOneStep - , processEntries, - fetchCid + walkOneStep, + processEntries, + fetchCid, } from '../lib/advertisement-walker.js' import pRetry from 'p-retry' import { givenHttpServer } from './helpers/http-server.js' @@ -42,27 +42,27 @@ const knownAdvertisement = { previousAdCid: 'baguqeerau2rz67nvzcaotgowm2olalanx3eynr2asbjwdkaq3y5umqvdi2ea', previousPreviousAdCid: 'baguqeeraa5mjufqdwuwrrrqboctnn3vhdlq63rj3hce2igpzbmae7sazkfea', payloadCid: 'bafkreigrnnl64xuevvkhknbhrcqzbdvvmqnchp7ae2a4ulninsjoc5svoq', - pieceCid: 'baga6ea4seaqlwzed5tgjtyhrugjziutzthx2wrympvsuqhfngwdwqzvosuchmja' + pieceCid: 'baga6ea4seaqlwzed5tgjtyhrugjziutzthx2wrympvsuqhfngwdwqzvosuchmja', } describe('processNextAdvertisement', () => { it('ignores non-HTTP(s) addresses and explains the problem in the status', async () => { /** @type {ProviderInfo} */ const providerInfo = { providerAddress: '/ip4/127.0.0.1/tcp/80', - lastAdvertisementCID: 'baguqeeraTEST' + lastAdvertisementCID: 'baguqeeraTEST', } const result = await processNextAdvertisement({ providerId, providerInfo, - walkerState: undefined + walkerState: undefined, }) assert.deepStrictEqual(result, { finished: true, newState: { - status: 'Index provider advertises over an unsupported protocol: /ip4/127.0.0.1/tcp/80' - } + status: 'Index provider advertises over an unsupported protocol: /ip4/127.0.0.1/tcp/80', + }, }) }) @@ -70,19 +70,20 @@ describe('processNextAdvertisement', () => { /** @type {ProviderInfo} */ const providerInfo = { providerAddress: '/dns/meridian.space/http/http-path/invalid%path', - lastAdvertisementCID: 'baguqeeraTEST' + lastAdvertisementCID: 'baguqeeraTEST', } const result = await processNextAdvertisement({ providerId, providerInfo, - walkerState: undefined + walkerState: undefined, }) assert.deepStrictEqual(result, { finished: true, newState: { - status: 'Index provider advertises over an unsupported protocol: /dns/meridian.space/http/http-path/invalid%path' - } + status: + 'Index provider advertises over an unsupported protocol: /dns/meridian.space/http/http-path/invalid%path', + }, }) }) @@ -90,7 +91,7 @@ describe('processNextAdvertisement', () => { /** @type {ProviderInfo} */ const providerInfo = { providerAddress, - lastAdvertisementCID: knownAdvertisement.adCid + lastAdvertisementCID: knownAdvertisement.adCid, } const walkerState = undefined const result = await processNextAdvertisement({ providerId, providerInfo, walkerState }) @@ -100,13 +101,13 @@ describe('processNextAdvertisement', () => { head: providerInfo.lastAdvertisementCID, tail: knownAdvertisement.previousAdCid, lastHead: undefined, - status: `Walking the advertisements from ${knownAdvertisement.adCid}, next step: ${knownAdvertisement.previousAdCid}` + status: `Walking the advertisements from ${knownAdvertisement.adCid}, next step: ${knownAdvertisement.previousAdCid}`, }, indexEntry: { payloadCid: knownAdvertisement.payloadCid, - pieceCid: knownAdvertisement.pieceCid + pieceCid: knownAdvertisement.pieceCid, }, - finished: false + finished: false, }) }) @@ -114,7 +115,7 @@ describe('processNextAdvertisement', () => { /** @type {ProviderInfo} */ const providerInfo = { providerAddress, - lastAdvertisementCID: knownAdvertisement.adCid + lastAdvertisementCID: knownAdvertisement.adCid, } /** @type {WalkerState} */ @@ -122,12 +123,12 @@ describe('processNextAdvertisement', () => { head: undefined, tail: undefined, lastHead: knownAdvertisement.adCid, - status: 'some-status' + status: 'some-status', } const result = await processNextAdvertisement({ providerId, providerInfo, walkerState }) assert.deepStrictEqual(result, { - finished: true + finished: true, }) }) @@ -135,7 +136,7 @@ describe('processNextAdvertisement', () => { /** @type {ProviderInfo} */ const providerInfo = { providerAddress, - lastAdvertisementCID: knownAdvertisement.adCid + lastAdvertisementCID: knownAdvertisement.adCid, } /** @type {WalkerState} */ @@ -143,17 +144,24 @@ describe('processNextAdvertisement', () => { head: knownAdvertisement.adCid, tail: knownAdvertisement.previousAdCid, lastHead: undefined, - status: 'some-status' + status: 'some-status', } - const { newState, indexEntry, finished } = await processNextAdvertisement({ providerId, providerInfo, walkerState }) + const { newState, indexEntry, finished } = await processNextAdvertisement({ + providerId, + providerInfo, + walkerState, + }) - assert.deepStrictEqual(newState, /** @type {WalkerState} */({ - head: walkerState.head, // this does not change during the walk - tail: knownAdvertisement.previousPreviousAdCid, - lastHead: walkerState.lastHead, // this does not change during the walk - status: `Walking the advertisements from ${walkerState.head}, next step: ${knownAdvertisement.previousPreviousAdCid}` - })) + assert.deepStrictEqual( + newState, + /** @type {WalkerState} */ ({ + head: walkerState.head, // this does not change during the walk + tail: knownAdvertisement.previousPreviousAdCid, + lastHead: walkerState.lastHead, // this does not change during the walk + status: `Walking the advertisements from ${walkerState.head}, next step: ${knownAdvertisement.previousPreviousAdCid}`, + }), + ) assert(indexEntry, 'the step found an index entry') @@ -164,24 +172,31 @@ describe('processNextAdvertisement', () => { /** @type {ProviderInfo} */ const providerInfo = { providerAddress, - lastAdvertisementCID: knownAdvertisement.adCid + lastAdvertisementCID: knownAdvertisement.adCid, } const walkerState = { head: undefined, // previous walk was finished tail: undefined, // previous walk was finished lastHead: knownAdvertisement.previousPreviousAdCid, // an advertisement later in the chain - status: 'some-status' + status: 'some-status', } - const { newState, finished } = await processNextAdvertisement({ providerId, providerInfo, walkerState }) + const { newState, finished } = await processNextAdvertisement({ + providerId, + providerInfo, + walkerState, + }) - assert.deepStrictEqual(newState, /** @type {WalkerState} */({ - head: knownAdvertisement.adCid, - tail: knownAdvertisement.previousAdCid, - lastHead: walkerState.lastHead, // this does not change during the walk - status: `Walking the advertisements from ${knownAdvertisement.adCid}, next step: ${knownAdvertisement.previousAdCid}` - })) + assert.deepStrictEqual( + newState, + /** @type {WalkerState} */ ({ + head: knownAdvertisement.adCid, + tail: knownAdvertisement.previousAdCid, + lastHead: walkerState.lastHead, // this does not change during the walk + status: `Walking the advertisements from ${knownAdvertisement.adCid}, next step: ${knownAdvertisement.previousAdCid}`, + }), + ) assert.strictEqual(finished, false, 'finished') }) @@ -190,20 +205,27 @@ describe('processNextAdvertisement', () => { /** @type {ProviderInfo} */ const providerInfo = { providerAddress: FRISBII_ADDRESS, - lastAdvertisementCID: FRISBII_AD_CID + lastAdvertisementCID: FRISBII_AD_CID, } const walkerState = undefined - const { newState, finished } = await processNextAdvertisement({ providerId, providerInfo, walkerState }) + const { newState, finished } = await processNextAdvertisement({ + providerId, + providerInfo, + walkerState, + }) - assert.deepStrictEqual(newState, /** @type {WalkerState} */({ - head: undefined, // we finished the walk, there is no head - tail: undefined, // we finished the walk, there is no next step - lastHead: FRISBII_AD_CID, // lastHead was updated to head of the walk we finished - adsMissingPieceCID: 1, - status: `All advertisements from ${newState?.lastHead} to the end of the chain were processed.` - })) + assert.deepStrictEqual( + newState, + /** @type {WalkerState} */ ({ + head: undefined, // we finished the walk, there is no head + tail: undefined, // we finished the walk, there is no next step + lastHead: FRISBII_AD_CID, // lastHead was updated to head of the walk we finished + adsMissingPieceCID: 1, + status: `All advertisements from ${newState?.lastHead} to the end of the chain were processed.`, + }), + ) assert.strictEqual(finished, true, 'finished') }) @@ -212,25 +234,32 @@ describe('processNextAdvertisement', () => { /** @type {ProviderInfo} */ const providerInfo = { providerAddress: FRISBII_ADDRESS, - lastAdvertisementCID: FRISBII_AD_CID + lastAdvertisementCID: FRISBII_AD_CID, } const walkerState = { head: undefined, // previous walk was finished tail: undefined, // previous walk was finished lastHead: knownAdvertisement.adCid, // arbitrary advertisement - status: 'some-status' + status: 'some-status', } - const { newState, finished } = await processNextAdvertisement({ providerId, providerInfo, walkerState }) + const { newState, finished } = await processNextAdvertisement({ + providerId, + providerInfo, + walkerState, + }) - assert.deepStrictEqual(newState, /** @type {WalkerState} */({ - head: undefined, // we finished the walk, there is no head - tail: undefined, // we finished the walk, there is no next step - lastHead: FRISBII_AD_CID, // lastHead was updated to head of the walk we finished - adsMissingPieceCID: 1, - status: `All advertisements from ${newState?.lastHead} to the end of the chain were processed.` - })) + assert.deepStrictEqual( + newState, + /** @type {WalkerState} */ ({ + head: undefined, // we finished the walk, there is no head + tail: undefined, // we finished the walk, there is no next step + lastHead: FRISBII_AD_CID, // lastHead was updated to head of the walk we finished + adsMissingPieceCID: 1, + status: `All advertisements from ${newState?.lastHead} to the end of the chain were processed.`, + }), + ) assert.strictEqual(finished, true, 'finished') }) @@ -239,7 +268,7 @@ describe('processNextAdvertisement', () => { /** @type {ProviderInfo} */ const providerInfo = { providerAddress, - lastAdvertisementCID: knownAdvertisement.adCid + lastAdvertisementCID: knownAdvertisement.adCid, } /** @type {WalkerState} */ @@ -247,17 +276,24 @@ describe('processNextAdvertisement', () => { head: knownAdvertisement.adCid, tail: knownAdvertisement.previousAdCid, lastHead: knownAdvertisement.previousPreviousAdCid, - status: 'some-status' + status: 'some-status', } - const { newState, indexEntry, finished } = await processNextAdvertisement({ providerId, providerInfo, walkerState }) + const { newState, indexEntry, finished } = await processNextAdvertisement({ + providerId, + providerInfo, + walkerState, + }) - assert.deepStrictEqual(newState, /** @type {WalkerState} */({ - head: undefined, // we finished the walk, there is no head - tail: undefined, // we finished the walk, there is no next step - lastHead: walkerState.head, // lastHead was updated to head of the walk we finished - status: `All advertisements from ${newState?.lastHead} to the end of the chain were processed.` - })) + assert.deepStrictEqual( + newState, + /** @type {WalkerState} */ ({ + head: undefined, // we finished the walk, there is no head + tail: undefined, // we finished the walk, there is no next step + lastHead: walkerState.head, // lastHead was updated to head of the walk we finished + status: `All advertisements from ${newState?.lastHead} to the end of the chain were processed.`, + }), + ) assert(indexEntry, 'the step found an index entry') @@ -268,10 +304,14 @@ describe('processNextAdvertisement', () => { /** @type {ProviderInfo} */ const providerInfo = { providerAddress: 'http://127.0.0.1:80/', - lastAdvertisementCID: 'baguqeeraTEST' + lastAdvertisementCID: 'baguqeeraTEST', } - const result = await processNextAdvertisement({ providerId, providerInfo, walkerState: undefined }) + const result = await processNextAdvertisement({ + providerId, + providerInfo, + walkerState: undefined, + }) assert.deepStrictEqual(result, { failed: true, @@ -279,8 +319,9 @@ describe('processNextAdvertisement', () => { head: 'baguqeeraTEST', tail: 'baguqeeraTEST', lastHead: undefined, - status: 'Error processing baguqeeraTEST: HTTP request to http://127.0.0.1/ipni/v1/ad/baguqeeraTEST failed: connect ECONNREFUSED 127.0.0.1:80' - } + status: + 'Error processing baguqeeraTEST: HTTP request to http://127.0.0.1/ipni/v1/ad/baguqeeraTEST failed: connect ECONNREFUSED 127.0.0.1:80', + }, }) }) @@ -294,14 +335,14 @@ describe('processNextAdvertisement', () => { /** @type {ProviderInfo} */ const providerInfo = { providerAddress: serverUrl, - lastAdvertisementCID: 'baguqeeraTEST' + lastAdvertisementCID: 'baguqeeraTEST', } const result = await processNextAdvertisement({ providerId, providerInfo, walkerState: undefined, - fetchTimeout: 1 + fetchTimeout: 1, }) assert.deepStrictEqual(result, { @@ -310,8 +351,8 @@ describe('processNextAdvertisement', () => { head: 'baguqeeraTEST', tail: 'baguqeeraTEST', lastHead: undefined, - status: `Error processing baguqeeraTEST: HTTP request to ${serverUrl}ipni/v1/ad/baguqeeraTEST failed: operation timed out` - } + status: `Error processing baguqeeraTEST: HTTP request to ${serverUrl}ipni/v1/ad/baguqeeraTEST failed: operation timed out`, + }, }) }) @@ -334,13 +375,13 @@ describe('processNextAdvertisement', () => { /** @type {ProviderInfo} */ const providerInfo = { providerAddress: serverUrl, - lastAdvertisementCID: adCid + lastAdvertisementCID: adCid, } const result = await processNextAdvertisement({ providerId, providerInfo, - walkerState: undefined + walkerState: undefined, }) assert.deepStrictEqual(result, { @@ -351,8 +392,8 @@ describe('processNextAdvertisement', () => { head: adCid, tail: previousAdCid, lastHead: undefined, - status: `Walking the advertisements from ${adCid}, next step: ${previousAdCid}` - } + status: `Walking the advertisements from ${adCid}, next step: ${previousAdCid}`, + }, }) }) @@ -360,13 +401,13 @@ describe('processNextAdvertisement', () => { /** @type {ProviderInfo} */ const providerInfo = { providerAddress: FRISBII_ADDRESS, - lastAdvertisementCID: FRISBII_AD_CID + lastAdvertisementCID: FRISBII_AD_CID, } const result = await processNextAdvertisement({ providerId, providerInfo, - walkerState: undefined + walkerState: undefined, }) assert.deepStrictEqual(result, { @@ -377,39 +418,53 @@ describe('processNextAdvertisement', () => { head: undefined, tail: undefined, lastHead: FRISBII_AD_CID, - status: `All advertisements from ${FRISBII_AD_CID} to the end of the chain were processed.` - } + status: `All advertisements from ${FRISBII_AD_CID} to the end of the chain were processed.`, + }, }) }) it('correctly processes Curio advertisement with DAG-CBOR entries', async function () { // Real Curio provider details const curioProviderId = '12D3KooWJ91c6xQshrNe7QAXPFAaeRrHWq2UrgXGPf8UmMZMwyZ5' - const curioProviderAddress = multiaddrToHttpUrl('/dns/f03303347-market.duckdns.org/https/http-path/%2Fipni-provider%2F12D3KooWJ91c6xQshrNe7QAXPFAaeRrHWq2UrgXGPf8UmMZMwyZ5') + const curioProviderAddress = multiaddrToHttpUrl( + '/dns/f03303347-market.duckdns.org/https/http-path/%2Fipni-provider%2F12D3KooWJ91c6xQshrNe7QAXPFAaeRrHWq2UrgXGPf8UmMZMwyZ5', + ) const advertisementCid = 'baguqeerakqnjugtecgj5hhfmnh46pthk5k3vy6vf4bw3vpmwmudknlatun5a' const providerInfo = { providerAddress: curioProviderAddress, - lastAdvertisementCID: advertisementCid + lastAdvertisementCID: advertisementCid, } // Call processNextAdvertisement against the real provider const result = await processNextAdvertisement({ providerId: curioProviderId, providerInfo, - walkerState: undefined + walkerState: undefined, }) // Basic verification assert(result.indexEntry, 'Should return an indexEntry') - assert.strictEqual(result.newState.head, advertisementCid, 'Head should be the advertisement CID') + assert.strictEqual( + result.newState.head, + advertisementCid, + 'Head should be the advertisement CID', + ) // Verify piece and payload CIDs are present assert(result.indexEntry.pieceCid, 'Piece CID should be present') - assert.strictEqual(result.indexEntry.pieceCid, 'baga6ea4seaqfpjfs473fni3pv22fjrv3yd5cw3zgdlbumo5u5e4fvalosqwkynq', 'Piece CID should have correct prefix') + assert.strictEqual( + result.indexEntry.pieceCid, + 'baga6ea4seaqfpjfs473fni3pv22fjrv3yd5cw3zgdlbumo5u5e4fvalosqwkynq', + 'Piece CID should have correct prefix', + ) const parsedPieceCid = CID.parse(result.indexEntry.pieceCid) assert.strictEqual(parsedPieceCid.code, 61697) - assert.strictEqual(result.indexEntry.payloadCid, 'bafkreih74ljilat42tptlywlnuejfkyigun6ahor5gmkxemqkvvdftasg4', 'Payload CID should be present') + assert.strictEqual( + result.indexEntry.payloadCid, + 'bafkreih74ljilat42tptlywlnuejfkyigun6ahor5gmkxemqkvvdftasg4', + 'Payload CID should be present', + ) const parsedPayloadCid = CID.parse(result.indexEntry.payloadCid) assert.strictEqual(parsedPayloadCid.code, 85) }) @@ -420,23 +475,29 @@ describe('processNextAdvertisement', () => { describe('fetchAdvertisedPayload', () => { it('returns previousAdvertisementCid, pieceCid and payloadCid for Graphsync retrievals', async () => { const result = await fetchAdvertisedPayload(providerAddress, knownAdvertisement.adCid) - assert.deepStrictEqual(result, /** @type {AdvertisedPayload} */({ - entry: { - payloadCid: knownAdvertisement.payloadCid, - pieceCid: knownAdvertisement.pieceCid - }, - previousAdvertisementCid: knownAdvertisement.previousAdCid - })) + assert.deepStrictEqual( + result, + /** @type {AdvertisedPayload} */ ({ + entry: { + payloadCid: knownAdvertisement.payloadCid, + pieceCid: knownAdvertisement.pieceCid, + }, + previousAdvertisementCid: knownAdvertisement.previousAdCid, + }), + ) }) it('returns MISSING_PIECE_CID error for HTTP retrievals', async () => { const result = await fetchAdvertisedPayload(FRISBII_ADDRESS, FRISBII_AD_CID) - assert.deepStrictEqual(result, /** @type {AdvertisedPayload} */({ - error: 'MISSING_PIECE_CID', - // Our Frisbii instance announced only one advertisement - // That's unrelated to HTTP vs Graphsync retrievals - previousAdvertisementCid: undefined - })) + assert.deepStrictEqual( + result, + /** @type {AdvertisedPayload} */ ({ + error: 'MISSING_PIECE_CID', + // Our Frisbii instance announced only one advertisement + // That's unrelated to HTTP vs Graphsync retrievals + previousAdvertisementCid: undefined, + }), + ) }) }) @@ -466,7 +527,7 @@ describe('walkOneStep', () => { /** @type {ProviderInfo} */ const providerInfo = { providerAddress, - lastAdvertisementCID: nextHead + lastAdvertisementCID: nextHead, } const result = await walkOneStep({ repository, providerId, providerInfo }) @@ -474,16 +535,22 @@ describe('walkOneStep', () => { assert.strictEqual(!!result.failed, false) const newState = await repository.getWalkerState(providerId) - assert.deepStrictEqual(newState, /** @type {WalkerState} */({ - head: nextHead, - tail: knownAdvertisement.previousAdCid, - // lastHead: undefined, - status: `Walking the advertisements from ${nextHead}, next step: ${knownAdvertisement.previousAdCid}` - })) + assert.deepStrictEqual( + newState, + /** @type {WalkerState} */ ({ + head: nextHead, + tail: knownAdvertisement.previousAdCid, + // lastHead: undefined, + status: `Walking the advertisements from ${nextHead}, next step: ${knownAdvertisement.previousAdCid}`, + }), + ) assert.deepStrictEqual(result.walkerState, { lastHead: undefined, ...newState }) - const pieceBlocks = await repository.getPiecePayloadBlocks(providerId, knownAdvertisement.pieceCid) + const pieceBlocks = await repository.getPiecePayloadBlocks( + providerId, + knownAdvertisement.pieceCid, + ) assert.deepStrictEqual(pieceBlocks, [knownAdvertisement.payloadCid]) }) }) @@ -502,7 +569,7 @@ describe('data schema for REST API', () => { /** @type {ProviderInfo} */ const providerInfo = { providerAddress, - lastAdvertisementCID: knownAdvertisement.adCid + lastAdvertisementCID: knownAdvertisement.adCid, } await walkOneStep({ repository, providerId, providerInfo }) @@ -545,7 +612,7 @@ describe('data schema for REST API', () => { lastHeadWalkedFrom: walkerState.lastHead ?? walkerState.head, adsMissingPieceCID: walkerState.adsMissingPieceCID ?? 0, entriesNotRetrievable: walkerState.entriesNotRetrievable ?? 0, - piecesIndexed: await repository.countPiecesIndexed(providerId) + piecesIndexed: await repository.countPiecesIndexed(providerId), } assert.deepStrictEqual(response, { @@ -554,7 +621,7 @@ describe('data schema for REST API', () => { lastHeadWalkedFrom: knownAdvertisement.adCid, adsMissingPieceCID: 0, entriesNotRetrievable: 0, - piecesIndexed: 1 + piecesIndexed: 1, }) }) }) @@ -589,8 +656,8 @@ describe('extractPieceCidFromContextID', () => { const encoded = cbor.encode([pieceSize, pieceCid]) return { '/': { - bytes: Buffer.from(encoded).toString('base64') - } + bytes: Buffer.from(encoded).toString('base64'), + }, } } @@ -600,8 +667,8 @@ describe('extractPieceCidFromContextID', () => { */ const validContextIdExample = { '/': { - bytes: 'ghsAAAAIAAAAANgqWCgAAYHiA5IgIFeksuf2VqNvrrRUxrvA+itvJhrDRju06ThagW6ULKw2' - } + bytes: 'ghsAAAAIAAAAANgqWCgAAYHiA5IgIFeksuf2VqNvrrRUxrvA+itvJhrDRju06ThagW6ULKw2', + }, } beforeEach(() => { @@ -611,19 +678,26 @@ describe('extractPieceCidFromContextID', () => { it('should return null when contextID is null or undefined', () => { assert.strictEqual(extractPieceInfoFromContextID(null, { logDebugMessage }), null) assert.strictEqual(extractPieceInfoFromContextID(undefined, { logDebugMessage }), null) - assert.ok(debugMessages.some(msg => - msg.includes('has no properly formatted ContextID') - )) + assert.ok(debugMessages.some((msg) => msg.includes('has no properly formatted ContextID'))) }) it('should return null when contextID is missing the expected structure', () => { // We are testing cases that violate the expected type structures - assert.strictEqual(extractPieceInfoFromContextID(/** @type {any} */ ({}), { logDebugMessage }), null) - assert.strictEqual(extractPieceInfoFromContextID(/** @type {any} */({ '/': {} }), { logDebugMessage }), null) - assert.strictEqual(extractPieceInfoFromContextID(/** @type {any} */({ wrong: 'structure' }), { logDebugMessage }), null) - assert.ok(debugMessages.every(msg => - msg.includes('has no properly formatted ContextID') - )) + assert.strictEqual( + extractPieceInfoFromContextID(/** @type {any} */ ({}), { logDebugMessage }), + null, + ) + assert.strictEqual( + extractPieceInfoFromContextID(/** @type {any} */ ({ '/': {} }), { logDebugMessage }), + null, + ) + assert.strictEqual( + extractPieceInfoFromContextID(/** @type {any} */ ({ wrong: 'structure' }), { + logDebugMessage, + }), + null, + ) + assert.ok(debugMessages.every((msg) => msg.includes('has no properly formatted ContextID'))) }) it('should return null when decoded data is not an array', () => { @@ -631,14 +705,12 @@ describe('extractPieceCidFromContextID', () => { const encoded = cbor.encode('not-an-array') const contextID = { '/': { - bytes: Buffer.from(encoded).toString('base64') - } + bytes: Buffer.from(encoded).toString('base64'), + }, } assert.strictEqual(extractPieceInfoFromContextID(contextID, { logDebugMessage }), null) - assert.ok(debugMessages.some(msg => - msg.includes('decoded value is not an array') - )) + assert.ok(debugMessages.some((msg) => msg.includes('decoded value is not an array'))) }) it('should return null when decoded array does not have exactly 2 items', () => { @@ -651,21 +723,19 @@ describe('extractPieceCidFromContextID', () => { const contextIDTooFew = { '/': { - bytes: Buffer.from(encodedTooFew).toString('base64') - } + bytes: Buffer.from(encodedTooFew).toString('base64'), + }, } const contextIDTooMany = { '/': { - bytes: Buffer.from(encodedTooMany).toString('base64') - } + bytes: Buffer.from(encodedTooMany).toString('base64'), + }, } assert.strictEqual(extractPieceInfoFromContextID(contextIDTooFew, { logDebugMessage }), null) assert.strictEqual(extractPieceInfoFromContextID(contextIDTooMany, { logDebugMessage }), null) - assert.ok(debugMessages.some(msg => - msg.includes('expected array with 2 items') - )) + assert.ok(debugMessages.some((msg) => msg.includes('expected array with 2 items'))) }) it('should return null when pieceSize is not a number', () => { @@ -676,14 +746,12 @@ describe('extractPieceCidFromContextID', () => { const encoded = cbor.encode(['not-a-number', mockCid]) const contextID = { '/': { - bytes: Buffer.from(encoded).toString('base64') - } + bytes: Buffer.from(encoded).toString('base64'), + }, } assert.strictEqual(extractPieceInfoFromContextID(contextID, { logDebugMessage }), null) - assert.ok(debugMessages.some(msg => - msg.includes('pieceSize is not a number') - )) + assert.ok(debugMessages.some((msg) => msg.includes('pieceSize is not a number'))) }) it('should return null when pieceCid is not an object', () => { @@ -691,14 +759,12 @@ describe('extractPieceCidFromContextID', () => { const encoded = cbor.encode([validPieceSize, 'not-an-object']) const contextID = { '/': { - bytes: Buffer.from(encoded).toString('base64') - } + bytes: Buffer.from(encoded).toString('base64'), + }, } assert.strictEqual(extractPieceInfoFromContextID(contextID, { logDebugMessage }), null) - assert.ok(debugMessages.some(msg => - msg.includes('pieceCID is not an object') - )) + assert.ok(debugMessages.some((msg) => msg.includes('pieceCID is not an object'))) }) it('should return null when pieceCid is null', () => { @@ -708,14 +774,12 @@ describe('extractPieceCidFromContextID', () => { /** @type {{'/': {bytes: string}}} */ const contextIDNull = { '/': { - bytes: Buffer.from(encodedNull).toString('base64') - } + bytes: Buffer.from(encodedNull).toString('base64'), + }, } assert.strictEqual(extractPieceInfoFromContextID(contextIDNull, { logDebugMessage }), null) - assert.ok(debugMessages.some(msg => - msg.includes('pieceCID is null or undefined') - )) + assert.ok(debugMessages.some((msg) => msg.includes('pieceCID is null or undefined'))) }) it('should return null when pieceCid is not a CID object', () => { @@ -726,14 +790,12 @@ describe('extractPieceCidFromContextID', () => { /** @type {{'/': {bytes: string}}} */ const contextID = { '/': { - bytes: Buffer.from(encoded).toString('base64') - } + bytes: Buffer.from(encoded).toString('base64'), + }, } assert.strictEqual(extractPieceInfoFromContextID(contextID, { logDebugMessage }), null) - assert.ok(debugMessages.some(msg => - msg.includes('pieceCID is not a CID') - )) + assert.ok(debugMessages.some((msg) => msg.includes('pieceCID is not a CID'))) }) it('should handle CBOR decoding errors', () => { @@ -741,14 +803,12 @@ describe('extractPieceCidFromContextID', () => { /** @type {{'/': {bytes: string}}} */ const contextID = { '/': { - bytes: 'ghsA'.concat('invalid-cbor') - } + bytes: 'ghsA'.concat('invalid-cbor'), + }, } assert.strictEqual(extractPieceInfoFromContextID(contextID, { logDebugMessage }), null) - assert.ok(debugMessages.some(msg => - msg.includes('Failed to decode ContextID') - )) + assert.ok(debugMessages.some((msg) => msg.includes('Failed to decode ContextID'))) }) it('should successfully extract pieceCid and pieceSize from valid input', () => { @@ -762,7 +822,11 @@ describe('extractPieceCidFromContextID', () => { assert.strictEqual(result.pieceSize, validPieceSize) assert.strictEqual(result.pieceCid.constructor.name, 'CID') assert.deepStrictEqual(result.pieceCid, mockCid) - assert.strictEqual(debugMessages.length, 0, 'No debug messages should be generated for valid input') + assert.strictEqual( + debugMessages.length, + 0, + 'No debug messages should be generated for valid input', + ) }) it('should process the provided valid context example correctly', () => { @@ -772,11 +836,15 @@ describe('extractPieceCidFromContextID', () => { assert.ok(result !== null) assert.strictEqual(typeof result.pieceSize, 'number', 'Should extract a numeric pieceSize') assert.strictEqual(result.pieceCid.constructor.name, 'CID', 'Should extract a CID object') - assert.strictEqual(debugMessages.length, 0, 'No debug messages should be generated for valid input') + assert.strictEqual( + debugMessages.length, + 0, + 'No debug messages should be generated for valid input', + ) }) const TEST_PIECE_CIDS = [ CID.parse('baga6ea4seaqpyzrxp423g6akmu3i2dnd7ymgf37z7m3nwhkbntt3stbocbroqdq'), - CID.parse('baga6ea4seaqlwzed5tgjtyhrugjziutzthx2wrympvsuqhfngwdwqzvosuchmja') + CID.parse('baga6ea4seaqlwzed5tgjtyhrugjziutzthx2wrympvsuqhfngwdwqzvosuchmja'), ] for (const pieceCid of TEST_PIECE_CIDS) { it('should handle multiple successful extractions', () => { @@ -787,7 +855,11 @@ describe('extractPieceCidFromContextID', () => { assert.ok(result !== null) assert.strictEqual(result.pieceSize, validPieceSize) assert.deepStrictEqual(result.pieceCid, pieceCid) - assert.strictEqual(debugMessages.length, 0, 'No debug messages should be generated for valid inputs') + assert.strictEqual( + debugMessages.length, + 0, + 'No debug messages should be generated for valid inputs', + ) }) } }) @@ -807,14 +879,14 @@ describe('processEntries', () => { Entries: [ { '/': { - bytes: entryBytes - } - } - ] + bytes: entryBytes, + }, + }, + ], } const dagCborChunk = { - Entries: [mh.bytes] + Entries: [mh.bytes], } it('processes DAG-JSON entries correctly', () => { // Process the entries with the real CID @@ -834,10 +906,7 @@ describe('processEntries', () => { // Error handling tests it('throws an error when entries array is empty', () => { - assert.throws( - () => processEntries(dagCborCid, { Entries: [] }), - /No entries found/ - ) + assert.throws(() => processEntries(dagCborCid, { Entries: [] }), /No entries found/) }) it('throws an error when Entries field is missing', () => { @@ -845,7 +914,7 @@ describe('processEntries', () => { // We need to ignore the type error here because we are testing an error case // @ts-ignore () => processEntries(dagCborCid, {}), - /No entries found/ + /No entries found/, ) }) @@ -853,10 +922,7 @@ describe('processEntries', () => { // Use a CID with an unsupported codec const unsupportedCid = 'bafkreigrnnl64xuevvkhknbhrcqzbdvvmqnchp7ae2a4ulninsjoc5svoq' - assert.throws( - () => processEntries(unsupportedCid, dagJsonChunk), - /Unsupported codec/ - ) + assert.throws(() => processEntries(unsupportedCid, dagJsonChunk), /Unsupported codec/) }) // Data integrity test using real multihash operations @@ -889,29 +955,23 @@ describe('processEntries', () => { Entries: [ { '/': { - bytes: 'This-is-not-valid-base64!' - } - } - ] + bytes: 'This-is-not-valid-base64!', + }, + }, + ], } // We expect an error when processing this malformed data - assert.throws( - () => processEntries(dagJsonCid, malformedChunk), - /Incorrect length/ - ) + assert.throws(() => processEntries(dagJsonCid, malformedChunk), /Incorrect length/) }) it('handles invalid multihash in DAG-CBOR gracefully', () => { const invalidChunk = { - Entries: [new Uint8Array([0, 1, 2, 3])] // Too short to be a valid multihash + Entries: [new Uint8Array([0, 1, 2, 3])], // Too short to be a valid multihash } // We expect an error when processing this invalid multihash - assert.throws( - () => processEntries(dagCborCid, invalidChunk), - /Incorrect length/ - ) + assert.throws(() => processEntries(dagCborCid, invalidChunk), /Incorrect length/) }) }) @@ -928,17 +988,15 @@ describe('fetchCid', () => { it('uses DAG-JSON codec (0x0129) to parse response as JSON', async () => { // Mock fetch to return JSON /** @type {typeof fetch} */ - const mockFetch = () => Promise.resolve( - new Response( - JSON.stringify(testResponse), - { + const mockFetch = () => + Promise.resolve( + new Response(JSON.stringify(testResponse), { status: 200, headers: new Headers({ - 'Content-Type': 'application/json' - }) - } + 'Content-Type': 'application/json', + }), + }), ) - ) const parsedCid = CID.parse(dagJsonCid) assert.strictEqual(parsedCid.code, 297) @@ -955,10 +1013,12 @@ describe('fetchCid', () => { // Mock fetch to return ArrayBuffer /** @type {typeof fetch} */ const mockFetch = () => { - return Promise.resolve(new Response(cborData.buffer, { - status: 200, - headers: { 'Content-Type': 'application/cbor' } - })) + return Promise.resolve( + new Response(cborData.buffer, { + status: 200, + headers: { 'Content-Type': 'application/cbor' }, + }), + ) } const parsedCid = CID.parse(dagCborCid) @@ -974,9 +1034,7 @@ describe('fetchCid', () => { // Mock fetch to return JSON /** @type {typeof fetch} */ - const mockFetch = () => Promise.resolve( - new Response() - ) + const mockFetch = () => Promise.resolve(new Response()) // Use a CID with a codec that is neither DAG-JSON (0x0129) nor DAG-CBOR (0x71) // This is a raw codec (0x55) CID @@ -989,20 +1047,19 @@ describe('fetchCid', () => { assert.fail('fetchCid should have thrown an error') } catch (error) { assert(error instanceof Error, 'Error should be an instance of Error') - assert.ok(error.message.includes(errorMessage), `Error message should include: ${errorMessage}`) + assert.ok( + error.message.includes(errorMessage), + `Error message should include: ${errorMessage}`, + ) } }) it('correctly fetches and processes real DAG-CBOR data from Curio provider', async function () { // Use a real Curio provider and known DAG-CBOR CID - const curioProviderUrl = 'https://f03303347-market.duckdns.org/ipni-provider/12D3KooWJ91c6xQshrNe7QAXPFAaeRrHWq2UrgXGPf8UmMZMwyZ5' + const curioProviderUrl = + 'https://f03303347-market.duckdns.org/ipni-provider/12D3KooWJ91c6xQshrNe7QAXPFAaeRrHWq2UrgXGPf8UmMZMwyZ5' const dagCborCid = 'baguqeeracgnw2ecmhaa6qkb3irrgjjk5zt5fes7wwwpb4aymoaogzyvvbrma' /** @type {unknown} */ - let result = await pRetry( - () => - ( - fetchCid(curioProviderUrl, dagCborCid) - ) - ) + let result = await pRetry(() => fetchCid(curioProviderUrl, dagCborCid)) // Verify the result has the expected structure for DAG-CBOR entries assert(result, 'Expected a non-null result') @@ -1011,7 +1068,10 @@ describe('fetchCid', () => { /** @type {Record} */ const resultObj = /** @type {Record} */ (result) assert('Entries' in resultObj, 'Result should have Entries property') - assert(typeof resultObj.Entries === 'object' && resultObj.Entries !== null, 'Entries should be an object') + assert( + typeof resultObj.Entries === 'object' && resultObj.Entries !== null, + 'Entries should be an object', + ) /** @type {Record} */ const entries = /** @type {Record} */ (resultObj.Entries) @@ -1021,16 +1081,14 @@ describe('fetchCid', () => { assert(typeof entriesCid === 'string', 'Entries CID should be a string') /** @type {unknown} */ - result = await pRetry( - () => - ( - fetchCid(curioProviderUrl, entriesCid) - ) - ) + result = await pRetry(() => fetchCid(curioProviderUrl, entriesCid)) /** @type {{ Entries: unknown[]; }} */ const entriesChunk = /** @type {{ Entries: unknown[]; }} */ (result) const payloadCid = processEntries(entriesCid, entriesChunk) console.log(payloadCid) - assert.deepStrictEqual(payloadCid, 'bafkreiefrclz7c6w57yl4u7uiq4kvht4z7pits5jpcj3cajbvowik3rvhm') + assert.deepStrictEqual( + payloadCid, + 'bafkreiefrclz7c6w57yl4u7uiq4kvht4z7pits5jpcj3cajbvowik3rvhm', + ) }) }) diff --git a/indexer/test/helpers/http-server.js b/indexer/test/helpers/http-server.js index 3239c85..8f617af 100644 --- a/indexer/test/helpers/http-server.js +++ b/indexer/test/helpers/http-server.js @@ -4,13 +4,13 @@ import http from 'node:http' /** * @param {http.RequestListener} handler */ -export async function givenHttpServer (handler) { +export async function givenHttpServer(handler) { const server = http.createServer((req, res) => { // Wrap the handler() call in an async function block to ensure synchronously thrown errors // are converted to rejected promises. ;(async () => { await handler(req, res) - })().catch(err => { + })().catch((err) => { console.log('Unhandled server error:', err) res.statusCode = 500 res.write(err.message || err.toString()) @@ -21,7 +21,7 @@ export async function givenHttpServer (handler) { server.listen(0, '127.0.0.1') server.unref() await once(server, 'listening') - const serverPort = /** @type {import('node:net').AddressInfo} */(server.address()).port + const serverPort = /** @type {import('node:net').AddressInfo} */ (server.address()).port const serverUrl = `http://127.0.0.1:${serverPort}/` return { server, serverPort, serverUrl } } diff --git a/repository/lib/redis-repository.js b/repository/lib/redis-repository.js index 676a5db..e037f54 100644 --- a/repository/lib/redis-repository.js +++ b/repository/lib/redis-repository.js @@ -6,7 +6,7 @@ export class RedisRepository { /** * @param {import('ioredis').Redis} redis */ - constructor (redis) { + constructor(redis) { this.#redis = redis } @@ -14,7 +14,7 @@ export class RedisRepository { * @param {string} providerId * @returns {Promise} */ - async getWalkerState (providerId) { + async getWalkerState(providerId) { const json = await this.#redis.get(`walker-state:${providerId}`) return json ? JSON.parse(json) : undefined } @@ -23,7 +23,7 @@ export class RedisRepository { * @param {string} providerId * @param {WalkerState} state */ - async setWalkerState (providerId, state) { + async setWalkerState(providerId, state) { const data = JSON.stringify(state) await this.#redis.set(`walker-state:${providerId}`, data) } @@ -33,7 +33,7 @@ export class RedisRepository { * @param {string} pieceCid * @param {string[]} payloadCids */ - async addPiecePayloadBlocks (providerId, pieceCid, ...payloadCids) { + async addPiecePayloadBlocks(providerId, pieceCid, ...payloadCids) { await this.#redis.sadd(`piece-payload:${providerId}:${pieceCid}`, ...payloadCids) } @@ -42,7 +42,7 @@ export class RedisRepository { * @param {string} pieceCid * @returns {Promise} */ - async getPiecePayloadBlocks (providerId, pieceCid) { + async getPiecePayloadBlocks(providerId, pieceCid) { const payloadCids = await this.#redis.smembers(`piece-payload:${providerId}:${pieceCid}`) return payloadCids } @@ -50,10 +50,10 @@ export class RedisRepository { /** * @param {string} providerId */ - async countPiecesIndexed (providerId) { + async countPiecesIndexed(providerId) { const keyStream = this.#redis.scanStream({ match: `piece-payload:${providerId}:*`, - count: 64_000 + count: 64_000, }) // We need to de-duplicate the keys returned by Redis. diff --git a/repository/lib/typings.d.ts b/repository/lib/typings.d.ts index 3732e02..e429146 100644 --- a/repository/lib/typings.d.ts +++ b/repository/lib/typings.d.ts @@ -26,15 +26,14 @@ lastAdCID --> [ ] -\ (null) */ export interface WalkerState { - head?: string; - tail?: string; - lastHead?: string; - status: string; - entriesNotRetrievable?: number; - adsMissingPieceCID?: number; + head?: string + tail?: string + lastHead?: string + status: string + entriesNotRetrievable?: number + adsMissingPieceCID?: number } export type ProviderToWalkerStateMap = Map -export type PiecePayloadCIDs = string[]; - +export type PiecePayloadCIDs = string[] diff --git a/repository/test/redis-repository.test.js b/repository/test/redis-repository.test.js index b4e1fdd..48a1b1a 100644 --- a/repository/test/redis-repository.test.js +++ b/repository/test/redis-repository.test.js @@ -30,7 +30,7 @@ describe('data schema for REST API', () => { head: 'head', tail: 'tail', lastHead: 'last head', - status: 'status' + status: 'status', } await repository.setWalkerState('providerId', state) diff --git a/tsconfig.json b/tsconfig.json index 986868c..5797fa5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,7 +18,5 @@ "noEmit": true, "resolveJsonModule": true }, - "include": [ - "indexer" - ] + "include": ["indexer"] } From 877876e4b91e9e5283ebc374e1069f8ad72e1e32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Tue, 22 Apr 2025 16:14:00 +0200 Subject: [PATCH 3/3] fixup! adopt `@checkernetwork/prettier-config` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miroslav Bajtoš --- .prettierrc.yaml | 5 - api/lib/app.js | 12 +- api/package.json | 10 +- api/test/app.test.js | 87 ++- indexer/bin/piece-indexer.js | 10 +- indexer/lib/advertisement-walker.js | 197 ++++-- indexer/lib/ipni-watcher.js | 46 +- indexer/lib/typings.d.ts | 4 +- indexer/lib/vendored/multiaddr.js | 26 +- indexer/package.json | 10 +- indexer/test/advertisement-walker.test.js | 311 ++++++--- indexer/test/helpers/http-server.js | 8 +- indexer/test/helpers/test-data.js | 3 +- package-lock.json | 767 ++++++++++++++++++++++ package.json | 26 +- repository/lib/redis-repository.js | 19 +- repository/lib/typings.d.ts | 31 +- repository/package.json | 4 +- repository/test/redis-repository.test.js | 2 +- 19 files changed, 1310 insertions(+), 268 deletions(-) delete mode 100644 .prettierrc.yaml diff --git a/.prettierrc.yaml b/.prettierrc.yaml deleted file mode 100644 index 1b0f74f..0000000 --- a/.prettierrc.yaml +++ /dev/null @@ -1,5 +0,0 @@ -semi: false -singleQuote: true -printWidth: 100 -trailingComma: all -proseWrap: always diff --git a/api/lib/app.js b/api/lib/app.js index 15241d3..2107ab9 100644 --- a/api/lib/app.js +++ b/api/lib/app.js @@ -4,7 +4,7 @@ import Fastify from 'fastify' /** * @param {object} args * @param {Repository} args.repository - * @param {string|boolean} args.domain + * @param {string | boolean} args.domain * @param {Fastify.FastifyLoggerOptions} args.logger */ export function createApp({ repository, domain, logger }) { @@ -21,11 +21,17 @@ export function createApp({ repository, domain, logger }) { app.get('/sample/:providerId/:pieceCid', async (request, reply) => { const { providerId, pieceCid } = request.params - const payloadCids = await repository.getPiecePayloadBlocks(providerId, pieceCid) + const payloadCids = await repository.getPiecePayloadBlocks( + providerId, + pieceCid, + ) const body = {} if (payloadCids.length) { body.samples = payloadCids.slice(0, 1) - reply.header('cache-control', `public, max-age=${24 * 3600 /* 24 hours */}, immutable`) + reply.header( + 'cache-control', + `public, max-age=${24 * 3600 /* 24 hours */}, immutable`, + ) } else { body.error = 'PROVIDER_OR_PIECE_NOT_FOUND' reply.header('cache-control', `public, max-age=${60 /* 1min */}`) diff --git a/api/package.json b/api/package.json index 14489f4..c76c824 100644 --- a/api/package.json +++ b/api/package.json @@ -1,19 +1,19 @@ { "name": "@filecoin-station/spark-piece-indexer-api", - "type": "module", "private": true, + "type": "module", "scripts": { - "start": "node bin/server.js", "lint": "standard", + "start": "node bin/server.js", "test": "node --test --test-reporter=spec" }, - "devDependencies": { - "standard": "^17.1.2" - }, "dependencies": { "@filecoin-station/spark-piece-indexer-repository": "^1.0.0", "@sentry/node": "^9.10.1", "fastify": "^5.2.2", "ioredis": "^5.6.0" + }, + "devDependencies": { + "standard": "^17.1.2" } } diff --git a/api/test/app.test.js b/api/test/app.test.js index 23a1421..4b5a830 100644 --- a/api/test/app.test.js +++ b/api/test/app.test.js @@ -24,7 +24,10 @@ describe('HTTP request handler', () => { repository, domain: false, logger: { - level: process.env.DEBUG === '*' || process.env.DEBUG?.includes('test') ? 'debug' : 'error', + level: + process.env.DEBUG === '*' || process.env.DEBUG?.includes('test') + ? 'debug' + : 'error', }, }) baseUrl = await app.listen() @@ -79,36 +82,61 @@ describe('HTTP request handler', () => { }) it('returns error when provider is not found', async () => { - await repository.addPiecePayloadBlocks('provider-id', 'piece-cid', 'payload-cid') + await repository.addPiecePayloadBlocks( + 'provider-id', + 'piece-cid', + 'payload-cid', + ) - const res = await fetch(new URL('/sample/unknown-provider-id/piece-cid', baseUrl)) + const res = await fetch( + new URL('/sample/unknown-provider-id/piece-cid', baseUrl), + ) await assertResponseStatus(res, 200) const body = await res.json() assert.deepStrictEqual(body, { error: 'PROVIDER_OR_PIECE_NOT_FOUND', }) - assert.strictEqual(res.headers.get('cache-control'), `public, max-age=${60}`) + assert.strictEqual( + res.headers.get('cache-control'), + `public, max-age=${60}`, + ) }) it('returns error when provider piece is not found', async () => { - await repository.addPiecePayloadBlocks('provider-id', 'piece-cid', 'payload-cid') + await repository.addPiecePayloadBlocks( + 'provider-id', + 'piece-cid', + 'payload-cid', + ) - const res = await fetch(new URL('/sample/provider-id/unknown-piece-cid', baseUrl)) + const res = await fetch( + new URL('/sample/provider-id/unknown-piece-cid', baseUrl), + ) await assertResponseStatus(res, 200) const body = await res.json() assert.deepStrictEqual(body, { error: 'PROVIDER_OR_PIECE_NOT_FOUND', }) - assert.strictEqual(res.headers.get('cache-control'), `public, max-age=${60}`) + assert.strictEqual( + res.headers.get('cache-control'), + `public, max-age=${60}`, + ) }) }) describe('GET /ingestion-status/{providerId}', () => { it('returns info about a provider seen by the indexer', async () => { - await repository.setWalkerState('provider-id', { status: 'walking', lastHead: 'last-head' }) - await repository.addPiecePayloadBlocks('provider-id', 'piece-cid', 'bafy1') + await repository.setWalkerState('provider-id', { + status: 'walking', + lastHead: 'last-head', + }) + await repository.addPiecePayloadBlocks( + 'provider-id', + 'piece-cid', + 'bafy1', + ) const res = await fetch(new URL('/ingestion-status/provider-id', baseUrl)) await assertResponseStatus(res, 200) @@ -125,7 +153,10 @@ describe('HTTP request handler', () => { piecesIndexed: 1, }) - assert.strictEqual(res.headers.get('cache-control'), `public, max-age=${60}`) + assert.strictEqual( + res.headers.get('cache-control'), + `public, max-age=${60}`, + ) }) it('returns error for an unknown provider', async () => { @@ -134,9 +165,15 @@ describe('HTTP request handler', () => { tail: 'tail', lastHead: 'last-head', }) - await repository.addPiecePayloadBlocks('provider-id', 'piece-cid', 'bafy1') + await repository.addPiecePayloadBlocks( + 'provider-id', + 'piece-cid', + 'bafy1', + ) - const res = await fetch(new URL('/ingestion-status/unknown-provider-id', baseUrl)) + const res = await fetch( + new URL('/ingestion-status/unknown-provider-id', baseUrl), + ) await assertResponseStatus(res, 200) const body = await res.json() @@ -145,12 +182,22 @@ describe('HTTP request handler', () => { ingestionStatus: 'Unknown provider ID', }) - assert.strictEqual(res.headers.get('cache-control'), `public, max-age=${60}`) + assert.strictEqual( + res.headers.get('cache-control'), + `public, max-age=${60}`, + ) }) it('returns "head" as "lastHead" when the initial walk has not finished yet', async () => { - await repository.setWalkerState('provider-id', { status: 'walking', head: 'head' }) - await repository.addPiecePayloadBlocks('provider-id', 'piece-cid', 'bafy1') + await repository.setWalkerState('provider-id', { + status: 'walking', + head: 'head', + }) + await repository.addPiecePayloadBlocks( + 'provider-id', + 'piece-cid', + 'bafy1', + ) const res = await fetch(new URL('/ingestion-status/provider-id', baseUrl)) await assertResponseStatus(res, 200) @@ -165,7 +212,10 @@ describe('HTTP request handler', () => { piecesIndexed: 1, }) - assert.strictEqual(res.headers.get('cache-control'), `public, max-age=${60}`) + assert.strictEqual( + res.headers.get('cache-control'), + `public, max-age=${60}`, + ) }) it('returns the number of adsMissingPieceCID and entriesNotRetrievable', async () => { @@ -189,7 +239,10 @@ describe('HTTP request handler', () => { piecesIndexed: 0, }) - assert.strictEqual(res.headers.get('cache-control'), `public, max-age=${60}`) + assert.strictEqual( + res.headers.get('cache-control'), + `public, max-age=${60}`, + ) }) }) }) diff --git a/indexer/bin/piece-indexer.js b/indexer/bin/piece-indexer.js index 0a8d994..a35684c 100644 --- a/indexer/bin/piece-indexer.js +++ b/indexer/bin/piece-indexer.js @@ -6,7 +6,7 @@ import { Redis } from 'ioredis' import { walkChain } from '../lib/advertisement-walker.js' import { runIpniSync } from '../lib/ipni-watcher.js' -/** @import { ProviderToInfoMap } from '../lib/typings.d.ts' */ +/** @import {ProviderToInfoMap} from '../lib/typings.d.ts' */ const { REDIS_URL: redisUrl = 'redis://localhost:6379' } = process.env @@ -29,16 +29,16 @@ const providerIdsBeingWalked = new Set() /** @type {ProviderToInfoMap} */ const recentProvidersInfo = new Map() -/** - * @param {string} providerId - */ +/** @param {string} providerId */ const getProviderInfo = async (providerId) => { const info = recentProvidersInfo.get(providerId) assert(info, `Unknown providerId ${providerId}`) return info } -for await (const providerInfos of runIpniSync({ minSyncIntervalInMs: 60_000 })) { +for await (const providerInfos of runIpniSync({ + minSyncIntervalInMs: 60_000, +})) { for (const [providerId, providerInfo] of providerInfos.entries()) { recentProvidersInfo.set(providerId, providerInfo) if (providerIdsBeingWalked.has(providerId)) continue diff --git a/indexer/lib/advertisement-walker.js b/indexer/lib/advertisement-walker.js index 64caa6b..9031b40 100644 --- a/indexer/lib/advertisement-walker.js +++ b/indexer/lib/advertisement-walker.js @@ -9,8 +9,8 @@ import timers from 'node:timers/promises' import { assertOkResponse } from 'assert-ok-response' import pRetry from 'p-retry' -/** @import { ProviderInfo, WalkerState } from './typings.js' */ -/** @import { RedisRepository as Repository } from '@filecoin-station/spark-piece-indexer-repository' */ +/** @import {ProviderInfo, WalkerState} from './typings.js' */ +/** @import {RedisRepository as Repository} from '@filecoin-station/spark-piece-indexer-repository' */ const debug = createDebug('spark-piece-indexer:advertisement-walker') @@ -38,7 +38,12 @@ export async function walkChain({ let failed = false /** @type {WalkerState | undefined} */ try { - const result = await walkOneStep({ repository, providerId, providerInfo, walkerState }) + const result = await walkOneStep({ + repository, + providerId, + providerInfo, + walkerState, + }) walkerState = result.walkerState debug('Got new walker state for provider %s: %o', providerId, walkerState) if (result.finished) break @@ -104,21 +109,30 @@ export async function walkOneStep({ ) walkerState = await repository.getWalkerState(providerId) } else { - debug('REUSING walker state for provider %s (%s)', providerId, providerInfo.providerAddress) + debug( + 'REUSING walker state for provider %s (%s)', + providerId, + providerInfo.providerAddress, + ) } - const { newState, indexEntry, failed, finished } = await processNextAdvertisement({ - providerId, - providerInfo, - walkerState, - fetchTimeout, - }) + const { newState, indexEntry, failed, finished } = + await processNextAdvertisement({ + providerId, + providerInfo, + walkerState, + fetchTimeout, + }) if (newState) { await repository.setWalkerState(providerId, newState) walkerState = newState } if (indexEntry?.pieceCid) { - await repository.addPiecePayloadBlocks(providerId, indexEntry.pieceCid, indexEntry.payloadCid) + await repository.addPiecePayloadBlocks( + providerId, + indexEntry.pieceCid, + indexEntry.payloadCid, + ) } return { failed, finished, walkerState } } @@ -165,7 +179,11 @@ export async function processNextAdvertisement({ ) state = { ...walkerState } } else if (nextHead === walkerState?.lastHead) { - debug('No new advertisements from provider %s (%s)', providerId, providerInfo.providerAddress) + debug( + 'No new advertisements from provider %s (%s)', + providerId, + providerInfo.providerAddress, + ) return { finished: true } } else { debug( @@ -186,13 +204,15 @@ export async function processNextAdvertisement({ assert(state.tail) try { - const { previousAdvertisementCid, entry, error } = await fetchAdvertisedPayload( - providerInfo.providerAddress, - state.tail, - { fetchTimeout }, - ) + const { previousAdvertisementCid, entry, error } = + await fetchAdvertisedPayload(providerInfo.providerAddress, state.tail, { + fetchTimeout, + }) - if (!previousAdvertisementCid || previousAdvertisementCid === state.lastHead) { + if ( + !previousAdvertisementCid || + previousAdvertisementCid === state.lastHead + ) { // We finished the walk state.lastHead = state.head state.head = undefined @@ -218,7 +238,10 @@ export async function processNextAdvertisement({ finished, } } catch (err) { - const errorDescription = describeFetchError(err, providerInfo.providerAddress) + const errorDescription = describeFetchError( + err, + providerInfo.providerAddress, + ) debug( 'Cannot process provider %s (%s) advertisement %s: %s', @@ -279,20 +302,26 @@ export async function fetchAdvertisedPayload( advertisementCid, { fetchTimeout } = {}, ) { - const advertisement = /** @type {{ - Addresses: string[], - ContextID: { '/': { bytes: string } }, - Entries: { '/': string }, - IsRm: false, - Metadata: { '/': { bytes: string } }, - PreviousID?: { '/': string }, - Provider: string - Signature: { - '/': { - bytes: string - } - } - }} */ (await pRetry(() => fetchCid(providerAddress, advertisementCid, { fetchTimeout }))) + const advertisement = /** + * @type {{ + * Addresses: string[] + * ContextID: { '/': { bytes: string } } + * Entries: { '/': string } + * IsRm: false + * Metadata: { '/': { bytes: string } } + * PreviousID?: { '/': string } + * Provider: string + * Signature: { + * '/': { + * bytes: string + * } + * } + * }} + */ ( + await pRetry(() => + fetchCid(providerAddress, advertisementCid, { fetchTimeout }), + ) + ) const previousAdvertisementCid = advertisement.PreviousID?.['/'] debug('advertisement %s %j', advertisementCid, advertisement) @@ -301,11 +330,17 @@ export async function fetchAdvertisedPayload( // An empty advertisement with no entries // See https://github.com/ipni/ipni-cli/blob/512ef8294eb717027b72e572897fbd8a1ed74564/pkg/adpub/client_store.go#L46-L48 // https://github.com/ipni/go-libipni/blob/489479457101ffe3cbe80682570b63c12ba2546d/ingest/schema/schema.go#L65-L71 - debug('advertisement %s has no entries: %j', advertisementCid, advertisement.Entries) + debug( + 'advertisement %s has no entries: %j', + advertisementCid, + advertisement.Entries, + ) return { previousAdvertisementCid } } - let pieceCid = extractPieceInfoFromContextID(advertisement.ContextID)?.pieceCid?.toString() + let pieceCid = extractPieceInfoFromContextID( + advertisement.ContextID, + )?.pieceCid?.toString() let meta if (!pieceCid) { meta = parseMetadata(advertisement.Metadata['/'].bytes) @@ -329,20 +364,31 @@ export async function fetchAdvertisedPayload( try { entriesChunk = await pRetry( () => - /** @type {Promise<{ - Entries: { '/' : { bytes: string } }[] - }>} */ (fetchCid(providerAddress, entriesCid, { fetchTimeout })), + /** + * @type {Promise<{ + * Entries: { '/': { bytes: string } }[] + * }>} + */ (fetchCid(providerAddress, entriesCid, { fetchTimeout })), { shouldRetry: (err) => - err && 'statusCode' in err && typeof err.statusCode === 'number' && err.statusCode >= 500, + err && + 'statusCode' in err && + typeof err.statusCode === 'number' && + err.statusCode >= 500, }, ) } catch (err) { // We are not able to fetch the advertised entries. Skip this advertisement so that we can // continue the ingestion of other advertisements. const errorDescription = describeFetchError(err, providerAddress) - const log = /** @type {any} */ (err)?.statusCode === 404 ? debug : console.warn - log('Cannot fetch ad %s entries %s: %s', advertisementCid, entriesCid, errorDescription ?? err) + const log = + /** @type {any} */ (err)?.statusCode === 404 ? debug : console.warn + log( + 'Cannot fetch ad %s entries %s: %s', + advertisementCid, + entriesCid, + errorDescription ?? err, + ) return { error: /** @type {const} */ ('ENTRIES_NOT_RETRIEVABLE'), previousAdvertisementCid, @@ -374,7 +420,11 @@ export async function fetchAdvertisedPayload( * @param {typeof fetch} [options.fetchFn] * @returns {Promise} */ -export async function fetchCid(providerBaseUrl, cid, { fetchTimeout, fetchFn } = {}) { +export async function fetchCid( + providerBaseUrl, + cid, + { fetchTimeout, fetchFn } = {}, +) { let url = new URL(providerBaseUrl) // Check if the URL already has a path @@ -422,9 +472,7 @@ export async function fetchCid(providerBaseUrl, cid, { fetchTimeout, fetchFn } = } } -/** - * @param {string} meta - */ +/** @param {string} meta */ export function parseMetadata(meta) { const bytes = Buffer.from(meta, 'base64') const [protocolCode, nextOffset] = varint.decode(bytes) @@ -438,11 +486,13 @@ export function parseMetadata(meta) { if (protocol === 'graphsync') { // console.log(bytes.subarray(nextOffset).toString('hex')) - /** @type {{ - PieceCID: import('multiformats/cid').CID, - VerifiedDeal: boolean, - FastRetrieval: boolean - }} */ + /** + * @type {{ + * PieceCID: import('multiformats/cid').CID + * VerifiedDeal: boolean + * FastRetrieval: boolean + * }} + */ const deal = cbor.decode(bytes.subarray(nextOffset)) return { protocol, deal } } else { @@ -453,16 +503,24 @@ export function parseMetadata(meta) { /** * Attempts to extract PieceCID and PieceSize from a ContextID * - * @param {{'/': {bytes: string}}|undefined | null} contextID - The ContextID object from an advertisement + * @param {{ '/': { bytes: string } } | undefined | null} contextID - The + * ContextID object from an advertisement * @param {object} [options] * @param {function} [options.logDebugMessage] - Function to log debug messages - * @returns {{pieceCid: string;pieceSize: number}|null} - Object containing pieceCid and pieceSize if successful, null otherwise + * @returns {{ pieceCid: string; pieceSize: number } | null} - Object containing + * pieceCid and pieceSize if successful, null otherwise */ -export function extractPieceInfoFromContextID(contextID, { logDebugMessage } = {}) { +export function extractPieceInfoFromContextID( + contextID, + { logDebugMessage } = {}, +) { logDebugMessage ??= debug // Check if ContextID exists and has the expected structure if (!contextID || !contextID['/'] || !contextID['/'].bytes) { - logDebugMessage('Advertisement %s has no properly formatted ContextID', contextID) + logDebugMessage( + 'Advertisement %s has no properly formatted ContextID', + contextID, + ) return null } @@ -526,14 +584,20 @@ export function extractPieceInfoFromContextID(contextID, { logDebugMessage } = { return { pieceCid, pieceSize } } catch (err) { - logDebugMessage('Failed to decode ContextID for advertisement %s: %s', contextID, err) + logDebugMessage( + 'Failed to decode ContextID for advertisement %s: %s', + contextID, + err, + ) return null } } -/** Process entries from either DAG-JSON or DAG-CBOR format +/** + * Process entries from either DAG-JSON or DAG-CBOR format + * * @param {string} entriesCid - The CID of the entries - * @param {{Entries: Array}} entriesChunk - The decoded entries + * @param {{ Entries: unknown[] }} entriesChunk - The decoded entries * @returns {string} The payload CID */ export function processEntries(entriesCid, entriesChunk) { @@ -555,13 +619,21 @@ export function processEntries(entriesCid, entriesChunk) { // Verify the '/' property is an object with 'bytes' property // In DAG-JSON, CIDs are represented as objects with a '/' property that contains 'bytes' - if (!entry['/'] || typeof entry['/'] !== 'object' || !('bytes' in entry['/'])) { - throw new Error('DAG-JSON entry\'s "/" property must be an object with a "bytes" property') + if ( + !entry['/'] || + typeof entry['/'] !== 'object' || + !('bytes' in entry['/']) + ) { + throw new Error( + 'DAG-JSON entry\'s "/" property must be an object with a "bytes" property', + ) } const entryHash = entry['/'].bytes if (typeof entryHash !== 'string') { - throw new Error('DAG-JSON entry\'s ["/"]["bytes"] property must be a string') + throw new Error( + 'DAG-JSON entry\'s ["/"]["bytes"] property must be a string', + ) } entryBytes = Buffer.from(entryHash, 'base64') break @@ -570,7 +642,10 @@ export function processEntries(entriesCid, entriesChunk) { // DAG-CBOR // For DAG-CBOR format, the entry is already a Uint8Array with the multihash entryBytes = entriesChunk.Entries[0] - assert(entryBytes instanceof Uint8Array, 'DAG-CBOR entry must be a Uint8Array') + assert( + entryBytes instanceof Uint8Array, + 'DAG-CBOR entry must be a Uint8Array', + ) break } default: diff --git a/indexer/lib/ipni-watcher.js b/indexer/lib/ipni-watcher.js index 18ad578..40824af 100644 --- a/indexer/lib/ipni-watcher.js +++ b/indexer/lib/ipni-watcher.js @@ -6,7 +6,7 @@ import { multiaddrToHttpUrl } from './vendored/multiaddr.js' const debug = createDebug('spark-piece-indexer:ipni-watcher') -/** @import { ProviderToInfoMap, ProviderInfo } from './typings.js' */ +/** @import {ProviderToInfoMap, ProviderInfo} from './typings.js' */ /** * @param {object} args @@ -22,8 +22,9 @@ export async function* runIpniSync({ minSyncIntervalInMs, signal }) { console.log( 'Found %s providers, %s support(s) HTTP(s)', providers.size, - Array.from(providers.values()).filter((p) => p.providerAddress.match(/^https?:\/\//)) - .length, + Array.from(providers.values()).filter((p) => + p.providerAddress.match(/^https?:\/\//), + ).length, ) yield providers } catch (err) { @@ -38,27 +39,26 @@ export async function* runIpniSync({ minSyncIntervalInMs, signal }) { } } -/** - * @returns {Promise} - */ +/** @returns {Promise} */ export async function getProvidersWithMetadata() { const res = await fetch('https://cid.contact/providers') assertOkResponse(res) - const providers = /** @type {{ - AddrInfo: { - ID: string; - Addrs: string[]; - }, - LastAdvertisement: { - "/": string; - }, - LastAdvertisementTime: string; - Publisher: { - ID: string; - Addrs: string[]; - }, - // Ignored: ExtendedProviders, FrozenAt + const providers = /** + * @type {{ + * AddrInfo: { + * ID: string + * Addrs: string[] + * } + * LastAdvertisement: { + * '/': string + * } + * LastAdvertisementTime: string + * Publisher: { + * ID: string + * Addrs: string[] + * } + * // Ignored: ExtendedProviders, FrozenAt * }[]} */ (await res.json()) @@ -72,7 +72,11 @@ export async function getProvidersWithMetadata() { try { providerAddress = multiaddrToHttpUrl(providerAddress) } catch (err) { - debug('Cannot convert address to HTTP(s) URL (provider: %s): %s', providerId, err) + debug( + 'Cannot convert address to HTTP(s) URL (provider: %s): %s', + providerId, + err, + ) } return [providerId, { providerAddress, lastAdvertisementCID }] diff --git a/indexer/lib/typings.d.ts b/indexer/lib/typings.d.ts index a535907..d1aadab 100644 --- a/indexer/lib/typings.d.ts +++ b/indexer/lib/typings.d.ts @@ -4,9 +4,7 @@ export { WalkerState, } from '@filecoin-station/spark-piece-indexer-repository/lib/typings.d.ts' -/** - * Data synced from IPNI - */ +/** Data synced from IPNI */ export interface ProviderInfo { providerAddress: string lastAdvertisementCID: string diff --git a/indexer/lib/vendored/multiaddr.js b/indexer/lib/vendored/multiaddr.js index 417c22e..b3e4f5a 100644 --- a/indexer/lib/vendored/multiaddr.js +++ b/indexer/lib/vendored/multiaddr.js @@ -17,7 +17,9 @@ export function multiaddrToHttpUrl(addr) { path = decodeURIComponent(httpPathMultiAddr.substring(1)) } catch (err) { throw Object.assign( - new Error(`Cannot parse "${addr}": unsupported http path`, { cause: err }), + new Error(`Cannot parse "${addr}": unsupported http path`, { + cause: err, + }), { code: 'INVALID_HTTP_PATH' }, ) } @@ -27,16 +29,21 @@ export function multiaddrToHttpUrl(addr) { if (ipProtocol !== 'tcp') { throw Object.assign( - new Error(`Cannot parse "${addr}": unsupported protocol "${ipProtocol}"`), + new Error( + `Cannot parse "${addr}": unsupported protocol "${ipProtocol}"`, + ), { code: 'UNSUPPORTED_MULTIADDR_PROTO' }, ) } } if (scheme !== 'http' && scheme !== 'https') { - throw Object.assign(new Error(`Cannot parse "${addr}": unsupported scheme "${scheme}"`), { - code: 'UNSUPPORTED_MULTIADDR_SCHEME', - }) + throw Object.assign( + new Error(`Cannot parse "${addr}": unsupported scheme "${scheme}"`), + { + code: 'UNSUPPORTED_MULTIADDR_SCHEME', + }, + ) } if (rest.length) { @@ -64,9 +71,12 @@ function getUriHost(hostType, hostValue) { return `[${hostValue}]` } - throw Object.assign(new Error(`Unsupported multiaddr host type "${hostType}"`), { - code: 'UNSUPPORTED_MULTIADDR_HOST_TYPE', - }) + throw Object.assign( + new Error(`Unsupported multiaddr host type "${hostType}"`), + { + code: 'UNSUPPORTED_MULTIADDR_HOST_TYPE', + }, + ) } function getUriPort(scheme, port) { diff --git a/indexer/package.json b/indexer/package.json index aa120f3..41187a1 100644 --- a/indexer/package.json +++ b/indexer/package.json @@ -1,15 +1,12 @@ { "name": "@filecoin-station/spark-piece-indexer", - "type": "module", "private": true, + "type": "module", "scripts": { - "start": "node bin/piece-indexer.js", "lint": "standard", + "start": "node bin/piece-indexer.js", "test": "node --test --test-reporter=spec" }, - "devDependencies": { - "standard": "^17.1.2" - }, "dependencies": { "@filecoin-station/spark-piece-indexer-repository": "^1.0.0", "@ipld/dag-cbor": "^9.2.2", @@ -19,5 +16,8 @@ "ioredis": "^5.6.0", "multiformats": "^13.3.2", "p-retry": "^6.2.1" + }, + "devDependencies": { + "standard": "^17.1.2" } } diff --git a/indexer/test/advertisement-walker.test.js b/indexer/test/advertisement-walker.test.js index aacf369..5ed0038 100644 --- a/indexer/test/advertisement-walker.test.js +++ b/indexer/test/advertisement-walker.test.js @@ -23,7 +23,7 @@ import { CID } from 'multiformats/cid' import * as crypto from 'node:crypto' import * as multihash from 'multiformats/hashes/digest' import { multiaddrToHttpUrl } from '../lib/vendored/multiaddr.js' -/** @import { ProviderInfo, WalkerState } from '../lib/typings.js' */ +/** @import {ProviderInfo, WalkerState} from '../lib/typings.js' */ // TODO(bajtos) We may need to replace this with a mock index provider const providerId = '12D3KooWHKeaNCnYByQUMS2n5PAZ1KZ9xKXqsb4bhpxVJ6bBJg5V' @@ -39,8 +39,10 @@ const providerAddress = 'http://f010479.twinquasar.io:3104' // (...) const knownAdvertisement = { adCid: 'baguqeerarbmakqcnzzuhki25xs357xyin4ieqxvumrp5cy7s44v7tzwwmg3q', - previousAdCid: 'baguqeerau2rz67nvzcaotgowm2olalanx3eynr2asbjwdkaq3y5umqvdi2ea', - previousPreviousAdCid: 'baguqeeraa5mjufqdwuwrrrqboctnn3vhdlq63rj3hce2igpzbmae7sazkfea', + previousAdCid: + 'baguqeerau2rz67nvzcaotgowm2olalanx3eynr2asbjwdkaq3y5umqvdi2ea', + previousPreviousAdCid: + 'baguqeeraa5mjufqdwuwrrrqboctnn3vhdlq63rj3hce2igpzbmae7sazkfea', payloadCid: 'bafkreigrnnl64xuevvkhknbhrcqzbdvvmqnchp7ae2a4ulninsjoc5svoq', pieceCid: 'baga6ea4seaqlwzed5tgjtyhrugjziutzthx2wrympvsuqhfngwdwqzvosuchmja', } @@ -61,7 +63,8 @@ describe('processNextAdvertisement', () => { assert.deepStrictEqual(result, { finished: true, newState: { - status: 'Index provider advertises over an unsupported protocol: /ip4/127.0.0.1/tcp/80', + status: + 'Index provider advertises over an unsupported protocol: /ip4/127.0.0.1/tcp/80', }, }) }) @@ -94,7 +97,11 @@ describe('processNextAdvertisement', () => { lastAdvertisementCID: knownAdvertisement.adCid, } const walkerState = undefined - const result = await processNextAdvertisement({ providerId, providerInfo, walkerState }) + const result = await processNextAdvertisement({ + providerId, + providerInfo, + walkerState, + }) assert.deepStrictEqual(result, { /** @type {WalkerState} */ newState: { @@ -126,7 +133,11 @@ describe('processNextAdvertisement', () => { status: 'some-status', } - const result = await processNextAdvertisement({ providerId, providerInfo, walkerState }) + const result = await processNextAdvertisement({ + providerId, + providerInfo, + walkerState, + }) assert.deepStrictEqual(result, { finished: true, }) @@ -424,11 +435,13 @@ describe('processNextAdvertisement', () => { }) it('correctly processes Curio advertisement with DAG-CBOR entries', async function () { // Real Curio provider details - const curioProviderId = '12D3KooWJ91c6xQshrNe7QAXPFAaeRrHWq2UrgXGPf8UmMZMwyZ5' + const curioProviderId = + '12D3KooWJ91c6xQshrNe7QAXPFAaeRrHWq2UrgXGPf8UmMZMwyZ5' const curioProviderAddress = multiaddrToHttpUrl( '/dns/f03303347-market.duckdns.org/https/http-path/%2Fipni-provider%2F12D3KooWJ91c6xQshrNe7QAXPFAaeRrHWq2UrgXGPf8UmMZMwyZ5', ) - const advertisementCid = 'baguqeerakqnjugtecgj5hhfmnh46pthk5k3vy6vf4bw3vpmwmudknlatun5a' + const advertisementCid = + 'baguqeerakqnjugtecgj5hhfmnh46pthk5k3vy6vf4bw3vpmwmudknlatun5a' const providerInfo = { providerAddress: curioProviderAddress, @@ -474,7 +487,10 @@ describe('processNextAdvertisement', () => { describe('fetchAdvertisedPayload', () => { it('returns previousAdvertisementCid, pieceCid and payloadCid for Graphsync retrievals', async () => { - const result = await fetchAdvertisedPayload(providerAddress, knownAdvertisement.adCid) + const result = await fetchAdvertisedPayload( + providerAddress, + knownAdvertisement.adCid, + ) assert.deepStrictEqual( result, /** @type {AdvertisedPayload} */ ({ @@ -545,7 +561,10 @@ describe('walkOneStep', () => { }), ) - assert.deepStrictEqual(result.walkerState, { lastHead: undefined, ...newState }) + assert.deepStrictEqual(result.walkerState, { + lastHead: undefined, + ...newState, + }) const pieceBlocks = await repository.getPiecePayloadBlocks( providerId, @@ -588,7 +607,10 @@ describe('data schema for REST API', () => { // } // pubkey & signature will be handled by the REST API server, // we are only interested in `samples` in this test - const samples = await repository.getPiecePayloadBlocks(providerId, knownAdvertisement.pieceCid) + const samples = await repository.getPiecePayloadBlocks( + providerId, + knownAdvertisement.pieceCid, + ) assert.deepStrictEqual(samples, [knownAdvertisement.payloadCid]) }) @@ -628,29 +650,24 @@ describe('data schema for REST API', () => { describe('extractPieceCidFromContextID', () => { const validPieceSize = 34359738368 - /** - * @type {Array} - */ + /** @type {string[]} */ let debugMessages = [] - /** - * @type {(format: string, ...args: any[]) => void} - */ + /** @type {(format: string, ...args: any[]) => void} */ const logDebugMessage = (format, ...args) => { debugMessages.push(util.format(format, ...args)) } - /** - * Clear debug messages before each test - */ + /** Clear debug messages before each test */ const clearDebugMessages = () => { debugMessages = [] } /** * Helper to create valid test data + * * @param {number} pieceSize - Size of the piece * @param {import('multiformats/cid').CID} pieceCid - CID of the piece - * @returns {{'/': {bytes: string}}} - Valid context ID object + * @returns {{ '/': { bytes: string } }} - Valid context ID object */ const createValidContextID = (pieceSize, pieceCid) => { const encoded = cbor.encode([pieceSize, pieceCid]) @@ -663,11 +680,13 @@ describe('extractPieceCidFromContextID', () => { /** * Example of valid contextId provided - * @type {{'/': {bytes: string}}} + * + * @type {{ '/': { bytes: string } }} */ const validContextIdExample = { '/': { - bytes: 'ghsAAAAIAAAAANgqWCgAAYHiA5IgIFeksuf2VqNvrrRUxrvA+itvJhrDRju06ThagW6ULKw2', + bytes: + 'ghsAAAAIAAAAANgqWCgAAYHiA5IgIFeksuf2VqNvrrRUxrvA+itvJhrDRju06ThagW6ULKw2', }, } @@ -676,28 +695,49 @@ describe('extractPieceCidFromContextID', () => { }) it('should return null when contextID is null or undefined', () => { - assert.strictEqual(extractPieceInfoFromContextID(null, { logDebugMessage }), null) - assert.strictEqual(extractPieceInfoFromContextID(undefined, { logDebugMessage }), null) - assert.ok(debugMessages.some((msg) => msg.includes('has no properly formatted ContextID'))) + assert.strictEqual( + extractPieceInfoFromContextID(null, { logDebugMessage }), + null, + ) + assert.strictEqual( + extractPieceInfoFromContextID(undefined, { logDebugMessage }), + null, + ) + assert.ok( + debugMessages.some((msg) => + msg.includes('has no properly formatted ContextID'), + ), + ) }) it('should return null when contextID is missing the expected structure', () => { // We are testing cases that violate the expected type structures assert.strictEqual( - extractPieceInfoFromContextID(/** @type {any} */ ({}), { logDebugMessage }), + extractPieceInfoFromContextID(/** @type {any} */ ({}), { + logDebugMessage, + }), null, ) assert.strictEqual( - extractPieceInfoFromContextID(/** @type {any} */ ({ '/': {} }), { logDebugMessage }), + extractPieceInfoFromContextID(/** @type {any} */ ({ '/': {} }), { + logDebugMessage, + }), null, ) assert.strictEqual( - extractPieceInfoFromContextID(/** @type {any} */ ({ wrong: 'structure' }), { - logDebugMessage, - }), + extractPieceInfoFromContextID( + /** @type {any} */ ({ wrong: 'structure' }), + { + logDebugMessage, + }, + ), null, ) - assert.ok(debugMessages.every((msg) => msg.includes('has no properly formatted ContextID'))) + assert.ok( + debugMessages.every((msg) => + msg.includes('has no properly formatted ContextID'), + ), + ) }) it('should return null when decoded data is not an array', () => { @@ -709,13 +749,22 @@ describe('extractPieceCidFromContextID', () => { }, } - assert.strictEqual(extractPieceInfoFromContextID(contextID, { logDebugMessage }), null) - assert.ok(debugMessages.some((msg) => msg.includes('decoded value is not an array'))) + assert.strictEqual( + extractPieceInfoFromContextID(contextID, { logDebugMessage }), + null, + ) + assert.ok( + debugMessages.some((msg) => + msg.includes('decoded value is not an array'), + ), + ) }) it('should return null when decoded array does not have exactly 2 items', () => { // Create a mock CID for testing - const mockCid = CID.parse('baga6ea4seaqlwzed5tgjtyhrugjziutzthx2wrympvsuqhfngwdwqzvosuchmja') + const mockCid = CID.parse( + 'baga6ea4seaqlwzed5tgjtyhrugjziutzthx2wrympvsuqhfngwdwqzvosuchmja', + ) // Create contextID with array of wrong length const encodedTooFew = cbor.encode([validPieceSize]) @@ -733,14 +782,24 @@ describe('extractPieceCidFromContextID', () => { }, } - assert.strictEqual(extractPieceInfoFromContextID(contextIDTooFew, { logDebugMessage }), null) - assert.strictEqual(extractPieceInfoFromContextID(contextIDTooMany, { logDebugMessage }), null) - assert.ok(debugMessages.some((msg) => msg.includes('expected array with 2 items'))) + assert.strictEqual( + extractPieceInfoFromContextID(contextIDTooFew, { logDebugMessage }), + null, + ) + assert.strictEqual( + extractPieceInfoFromContextID(contextIDTooMany, { logDebugMessage }), + null, + ) + assert.ok( + debugMessages.some((msg) => msg.includes('expected array with 2 items')), + ) }) it('should return null when pieceSize is not a number', () => { // Create a mock CID for testing - const mockCid = CID.parse('baga6ea4seaqlwzed5tgjtyhrugjziutzthx2wrympvsuqhfngwdwqzvosuchmja') + const mockCid = CID.parse( + 'baga6ea4seaqlwzed5tgjtyhrugjziutzthx2wrympvsuqhfngwdwqzvosuchmja', + ) // Create contextID with non-numeric pieceSize const encoded = cbor.encode(['not-a-number', mockCid]) @@ -750,8 +809,13 @@ describe('extractPieceCidFromContextID', () => { }, } - assert.strictEqual(extractPieceInfoFromContextID(contextID, { logDebugMessage }), null) - assert.ok(debugMessages.some((msg) => msg.includes('pieceSize is not a number'))) + assert.strictEqual( + extractPieceInfoFromContextID(contextID, { logDebugMessage }), + null, + ) + assert.ok( + debugMessages.some((msg) => msg.includes('pieceSize is not a number')), + ) }) it('should return null when pieceCid is not an object', () => { @@ -763,23 +827,35 @@ describe('extractPieceCidFromContextID', () => { }, } - assert.strictEqual(extractPieceInfoFromContextID(contextID, { logDebugMessage }), null) - assert.ok(debugMessages.some((msg) => msg.includes('pieceCID is not an object'))) + assert.strictEqual( + extractPieceInfoFromContextID(contextID, { logDebugMessage }), + null, + ) + assert.ok( + debugMessages.some((msg) => msg.includes('pieceCID is not an object')), + ) }) it('should return null when pieceCid is null', () => { // Create contextIDs with null/undefined pieceCid const encodedNull = cbor.encode([validPieceSize, null]) - /** @type {{'/': {bytes: string}}} */ + /** @type {{ '/': { bytes: string } }} */ const contextIDNull = { '/': { bytes: Buffer.from(encodedNull).toString('base64'), }, } - assert.strictEqual(extractPieceInfoFromContextID(contextIDNull, { logDebugMessage }), null) - assert.ok(debugMessages.some((msg) => msg.includes('pieceCID is null or undefined'))) + assert.strictEqual( + extractPieceInfoFromContextID(contextIDNull, { logDebugMessage }), + null, + ) + assert.ok( + debugMessages.some((msg) => + msg.includes('pieceCID is null or undefined'), + ), + ) }) it('should return null when pieceCid is not a CID object', () => { @@ -787,36 +863,50 @@ describe('extractPieceCidFromContextID', () => { const notACid = { not: 'a-cid' } // Make sure it's recognized as a regular object const encoded = cbor.encode([validPieceSize, notACid]) - /** @type {{'/': {bytes: string}}} */ + /** @type {{ '/': { bytes: string } }} */ const contextID = { '/': { bytes: Buffer.from(encoded).toString('base64'), }, } - assert.strictEqual(extractPieceInfoFromContextID(contextID, { logDebugMessage }), null) - assert.ok(debugMessages.some((msg) => msg.includes('pieceCID is not a CID'))) + assert.strictEqual( + extractPieceInfoFromContextID(contextID, { logDebugMessage }), + null, + ) + assert.ok( + debugMessages.some((msg) => msg.includes('pieceCID is not a CID')), + ) }) it('should handle CBOR decoding errors', () => { // Create contextID with invalid CBOR data - /** @type {{'/': {bytes: string}}} */ + /** @type {{ '/': { bytes: string } }} */ const contextID = { '/': { bytes: 'ghsA'.concat('invalid-cbor'), }, } - assert.strictEqual(extractPieceInfoFromContextID(contextID, { logDebugMessage }), null) - assert.ok(debugMessages.some((msg) => msg.includes('Failed to decode ContextID'))) + assert.strictEqual( + extractPieceInfoFromContextID(contextID, { logDebugMessage }), + null, + ) + assert.ok( + debugMessages.some((msg) => msg.includes('Failed to decode ContextID')), + ) }) it('should successfully extract pieceCid and pieceSize from valid input', () => { // Create a mock CID for testing - const mockCid = CID.parse('baga6ea4seaqlwzed5tgjtyhrugjziutzthx2wrympvsuqhfngwdwqzvosuchmja') + const mockCid = CID.parse( + 'baga6ea4seaqlwzed5tgjtyhrugjziutzthx2wrympvsuqhfngwdwqzvosuchmja', + ) const validContextID = createValidContextID(validPieceSize, mockCid) - const result = extractPieceInfoFromContextID(validContextID, { logDebugMessage }) + const result = extractPieceInfoFromContextID(validContextID, { + logDebugMessage, + }) assert.ok(result !== null) assert.strictEqual(result.pieceSize, validPieceSize) @@ -830,12 +920,26 @@ describe('extractPieceCidFromContextID', () => { }) it('should process the provided valid context example correctly', () => { - const result = extractPieceInfoFromContextID(validContextIdExample, { logDebugMessage }) + const result = extractPieceInfoFromContextID(validContextIdExample, { + logDebugMessage, + }) - assert.notStrictEqual(result, null, 'Should not return null for provided valid context example') + assert.notStrictEqual( + result, + null, + 'Should not return null for provided valid context example', + ) assert.ok(result !== null) - assert.strictEqual(typeof result.pieceSize, 'number', 'Should extract a numeric pieceSize') - assert.strictEqual(result.pieceCid.constructor.name, 'CID', 'Should extract a CID object') + assert.strictEqual( + typeof result.pieceSize, + 'number', + 'Should extract a numeric pieceSize', + ) + assert.strictEqual( + result.pieceCid.constructor.name, + 'CID', + 'Should extract a CID object', + ) assert.strictEqual( debugMessages.length, 0, @@ -843,13 +947,19 @@ describe('extractPieceCidFromContextID', () => { ) }) const TEST_PIECE_CIDS = [ - CID.parse('baga6ea4seaqpyzrxp423g6akmu3i2dnd7ymgf37z7m3nwhkbntt3stbocbroqdq'), - CID.parse('baga6ea4seaqlwzed5tgjtyhrugjziutzthx2wrympvsuqhfngwdwqzvosuchmja'), + CID.parse( + 'baga6ea4seaqpyzrxp423g6akmu3i2dnd7ymgf37z7m3nwhkbntt3stbocbroqdq', + ), + CID.parse( + 'baga6ea4seaqlwzed5tgjtyhrugjziutzthx2wrympvsuqhfngwdwqzvosuchmja', + ), ] for (const pieceCid of TEST_PIECE_CIDS) { it('should handle multiple successful extractions', () => { const validContextID = createValidContextID(validPieceSize, pieceCid) - const result = extractPieceInfoFromContextID(validContextID, { logDebugMessage }) + const result = extractPieceInfoFromContextID(validContextID, { + logDebugMessage, + }) assert.notStrictEqual(result, null) assert.ok(result !== null) @@ -867,13 +977,18 @@ describe('extractPieceCidFromContextID', () => { describe('processEntries', () => { // Use a real DAG-JSON CID that will naturally have codec 0x0129 (297) // CIDs that start with 'bagu' are DAG-JSON encoded - const dagJsonCid = 'baguqeeraa5mjufqdwuwrrrqboctnn3vhdlq63rj3hce2igpzbmae7sazkfea' + const dagJsonCid = + 'baguqeeraa5mjufqdwuwrrrqboctnn3vhdlq63rj3hce2igpzbmae7sazkfea' // Use a real DAG-CBOR CID that will naturally have codec 0x71 (113) // CIDs that start with 'bafy' are DAG-CBOR encoded - const dagCborCid = 'bafyreibpxkmu65ezxy7rynxotbghfz3ktiapjisntepd67hghfn4hde3na' + const dagCborCid = + 'bafyreibpxkmu65ezxy7rynxotbghfz3ktiapjisntepd67hghfn4hde3na' const testData = 'test data for multihash' // Create a proper multihash from this digest - const mh = multihash.create(0x12, crypto.createHash('sha256').update(testData).digest()) + const mh = multihash.create( + 0x12, + crypto.createHash('sha256').update(testData).digest(), + ) const entryBytes = Buffer.from(mh.bytes).toString('base64') const dagJsonChunk = { Entries: [ @@ -906,7 +1021,10 @@ describe('processEntries', () => { // Error handling tests it('throws an error when entries array is empty', () => { - assert.throws(() => processEntries(dagCborCid, { Entries: [] }), /No entries found/) + assert.throws( + () => processEntries(dagCborCid, { Entries: [] }), + /No entries found/, + ) }) it('throws an error when Entries field is missing', () => { @@ -920,9 +1038,13 @@ describe('processEntries', () => { it('throws an error for unsupported codec', () => { // Use a CID with an unsupported codec - const unsupportedCid = 'bafkreigrnnl64xuevvkhknbhrcqzbdvvmqnchp7ae2a4ulninsjoc5svoq' + const unsupportedCid = + 'bafkreigrnnl64xuevvkhknbhrcqzbdvvmqnchp7ae2a4ulninsjoc5svoq' - assert.throws(() => processEntries(unsupportedCid, dagJsonChunk), /Unsupported codec/) + assert.throws( + () => processEntries(unsupportedCid, dagJsonChunk), + /Unsupported codec/, + ) }) // Data integrity test using real multihash operations @@ -934,7 +1056,11 @@ describe('processEntries', () => { const expectedCid = CID.create(1, 0x55, mh).toString() // They should match - assert.strictEqual(result, expectedCid, 'CID should match the one created directly') + assert.strictEqual( + result, + expectedCid, + 'CID should match the one created directly', + ) }) // Test with entries from CBOR encoding/decoding @@ -946,7 +1072,11 @@ describe('processEntries', () => { const expectedCid = CID.create(1, 0x55, mh).toString() // They should match - assert.strictEqual(result, expectedCid, 'CID should match the one created directly') + assert.strictEqual( + result, + expectedCid, + 'CID should match the one created directly', + ) }) // Error case tests with real data @@ -962,7 +1092,10 @@ describe('processEntries', () => { } // We expect an error when processing this malformed data - assert.throws(() => processEntries(dagJsonCid, malformedChunk), /Incorrect length/) + assert.throws( + () => processEntries(dagJsonCid, malformedChunk), + /Incorrect length/, + ) }) it('handles invalid multihash in DAG-CBOR gracefully', () => { @@ -971,19 +1104,24 @@ describe('processEntries', () => { } // We expect an error when processing this invalid multihash - assert.throws(() => processEntries(dagCborCid, invalidChunk), /Incorrect length/) + assert.throws( + () => processEntries(dagCborCid, invalidChunk), + /Incorrect length/, + ) }) }) describe('fetchCid', () => { // Use a real DAG-JSON CID that will naturally have codec 0x0129 (297) // CIDs that start with 'bagu' are DAG-JSON encoded - const dagJsonCid = 'baguqeerayzpbdctxk4iyps45uldgibsvy6zro33vpfbehggivhcxcq5suaia' + const dagJsonCid = + 'baguqeerayzpbdctxk4iyps45uldgibsvy6zro33vpfbehggivhcxcq5suaia' // Sample JSON response const testResponse = { test: 'value' } // Use a real DAG-CBOR CID that will naturally have codec 0x71 (113) // CIDs that start with 'bafy' are DAG-CBOR encoded - const dagCborCid = 'bafyreictdikh363qfxsmjp63i6kup6aukjqfpd4r6wbhbiz2ctuji4bofm' + const dagCborCid = + 'bafyreictdikh363qfxsmjp63i6kup6aukjqfpd4r6wbhbiz2ctuji4bofm' it('uses DAG-JSON codec (0x0129) to parse response as JSON', async () => { // Mock fetch to return JSON @@ -1001,7 +1139,9 @@ describe('fetchCid', () => { const parsedCid = CID.parse(dagJsonCid) assert.strictEqual(parsedCid.code, 297) - const result = await fetchCid('http://example.com', dagJsonCid, { fetchFn: mockFetch }) + const result = await fetchCid('http://example.com', dagJsonCid, { + fetchFn: mockFetch, + }) // Verify we got the JSON response assert.deepStrictEqual(result, testResponse) @@ -1024,7 +1164,9 @@ describe('fetchCid', () => { const parsedCid = CID.parse(dagCborCid) assert.strictEqual(parsedCid.code, 113) - const result = await fetchCid('http://example.com', dagCborCid, { fetchFn: mockFetch }) + const result = await fetchCid('http://example.com', dagCborCid, { + fetchFn: mockFetch, + }) // Verify we got the decoded CBOR data assert.deepStrictEqual(result, testResponse) @@ -1038,12 +1180,15 @@ describe('fetchCid', () => { // Use a CID with a codec that is neither DAG-JSON (0x0129) nor DAG-CBOR (0x71) // This is a raw codec (0x55) CID - const unknownCodecCid = 'bafkreigrnnl64xuevvkhknbhrcqzbdvvmqnchp7ae2a4ulninsjoc5svoq' + const unknownCodecCid = + 'bafkreigrnnl64xuevvkhknbhrcqzbdvvmqnchp7ae2a4ulninsjoc5svoq' const parsedCid = CID.parse(unknownCodecCid) assert.strictEqual(parsedCid.code, 85) const errorMessage = 'Unknown codec 85' try { - await fetchCid('http://example.com', unknownCodecCid, { fetchFn: mockFetch }) + await fetchCid('http://example.com', unknownCodecCid, { + fetchFn: mockFetch, + }) assert.fail('fetchCid should have thrown an error') } catch (error) { assert(error instanceof Error, 'Error should be an instance of Error') @@ -1057,13 +1202,17 @@ describe('fetchCid', () => { // Use a real Curio provider and known DAG-CBOR CID const curioProviderUrl = 'https://f03303347-market.duckdns.org/ipni-provider/12D3KooWJ91c6xQshrNe7QAXPFAaeRrHWq2UrgXGPf8UmMZMwyZ5' - const dagCborCid = 'baguqeeracgnw2ecmhaa6qkb3irrgjjk5zt5fes7wwwpb4aymoaogzyvvbrma' + const dagCborCid = + 'baguqeeracgnw2ecmhaa6qkb3irrgjjk5zt5fes7wwwpb4aymoaogzyvvbrma' /** @type {unknown} */ let result = await pRetry(() => fetchCid(curioProviderUrl, dagCborCid)) // Verify the result has the expected structure for DAG-CBOR entries assert(result, 'Expected a non-null result') - assert(typeof result === 'object' && result !== null, 'Result should be an object') + assert( + typeof result === 'object' && result !== null, + 'Result should be an object', + ) /** @type {Record} */ const resultObj = /** @type {Record} */ (result) @@ -1082,8 +1231,8 @@ describe('fetchCid', () => { /** @type {unknown} */ result = await pRetry(() => fetchCid(curioProviderUrl, entriesCid)) - /** @type {{ Entries: unknown[]; }} */ - const entriesChunk = /** @type {{ Entries: unknown[]; }} */ (result) + /** @type {{ Entries: unknown[] }} */ + const entriesChunk = /** @type {{ Entries: unknown[] }} */ (result) const payloadCid = processEntries(entriesCid, entriesChunk) console.log(payloadCid) assert.deepStrictEqual( diff --git a/indexer/test/helpers/http-server.js b/indexer/test/helpers/http-server.js index 8f617af..991764b 100644 --- a/indexer/test/helpers/http-server.js +++ b/indexer/test/helpers/http-server.js @@ -1,9 +1,7 @@ import { once } from 'node:events' import http from 'node:http' -/** - * @param {http.RequestListener} handler - */ +/** @param {http.RequestListener} handler */ export async function givenHttpServer(handler) { const server = http.createServer((req, res) => { // Wrap the handler() call in an async function block to ensure synchronously thrown errors @@ -21,7 +19,9 @@ export async function givenHttpServer(handler) { server.listen(0, '127.0.0.1') server.unref() await once(server, 'listening') - const serverPort = /** @type {import('node:net').AddressInfo} */ (server.address()).port + const serverPort = /** @type {import('node:net').AddressInfo} */ ( + server.address() + ).port const serverUrl = `http://127.0.0.1:${serverPort}/` return { server, serverPort, serverUrl } } diff --git a/indexer/test/helpers/test-data.js b/indexer/test/helpers/test-data.js index 2f27d12..e06a773 100644 --- a/indexer/test/helpers/test-data.js +++ b/indexer/test/helpers/test-data.js @@ -4,4 +4,5 @@ export const FRISBII_ADDRESS = 'https://frisbii.fly.dev' // This CID may change when Frisbii is redeployed. You can find the CIDs of the advertised data in this repo: https://github.com/CheckerNetwork/frisbii-on-fly/blob/178c3949619d5b6e9c761d4a5343dbe9c93f457c/README.md // The advertisement CID itselve can be retrieved by querying the provider ID (FRISBII_ID): https://cid.contact/providers/12D3KooWC8gXxg9LoJ9h3hy3jzBkEAxamyHEQJKtRmAuBuvoMzpr // The LastAdvertisement field is the CID of the advertisement (FRISBII_AD_CID). -export const FRISBII_AD_CID = 'baguqeerafqzjc6vyefzivmcvcex77eylhiipvkaa3wcmn6vxulihillwfloq' +export const FRISBII_AD_CID = + 'baguqeerafqzjc6vyefzivmcvcex77eylhiipvkaa3wcmn6vxulihillwfloq' diff --git a/package-lock.json b/package-lock.json index 374c413..634129e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "repository" ], "devDependencies": { + "@checkernetwork/prettier-config": "^1.0.0", "@types/debug": "^4.1.12", "@types/node": "^22.13.17", "eslint": "^9.23.0", @@ -50,6 +51,17 @@ "standard": "^17.1.2" } }, + "node_modules/@checkernetwork/prettier-config": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@checkernetwork/prettier-config/-/prettier-config-1.0.0.tgz", + "integrity": "sha512-fOhwon55d/m35rtx1s/sKWBnJ8Wta0+wuvKs0/qSjM0qCmUxQ2K2+/bBRC4HufFgeqtTTHZjK2goM4sFpx1Cgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-plugin-jsdoc": "^1.3.2", + "prettier-plugin-packagejson": "^2.5.10" + } + }, "node_modules/@emnapi/core": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.0.tgz", @@ -1290,6 +1302,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/ms": { "version": "0.7.34", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", @@ -1354,6 +1376,13 @@ "@types/node": "*" } }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.29.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.29.0.tgz", @@ -2142,6 +2171,13 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/binary-searching": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/binary-searching/-/binary-searching-2.0.5.tgz", + "integrity": "sha512-v4N2l3RxL+m4zDxyxz3Ne2aTmiPn8ZUpKFpdPtO+ItW1NcTCXA7JeHG5GMBSvoKSkQZ9ycS+EouDVxYB9ufKWA==", + "dev": true, + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2270,6 +2306,17 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/cjs-module-lexer": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", @@ -2302,6 +2349,16 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2402,6 +2459,20 @@ } } }, + "node_modules/decode-named-character-reference": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz", + "integrity": "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2459,6 +2530,43 @@ "node": ">=6" } }, + "node_modules/detect-indent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.1.tgz", + "integrity": "sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/detect-newline": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-4.0.1.tgz", + "integrity": "sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -3744,6 +3852,16 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/git-hooks-list": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-3.2.0.tgz", + "integrity": "sha512-ZHG9a1gEhUMX1TvGrLdyWb9kDopCBbTnI8z4JgRMYxsijWipgjSEYoPWqBuIB0DnRnvqlQSEeVmzpeuPm7NdFQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/fisker/git-hooks-list?sponsor=1" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -4315,6 +4433,19 @@ "node": ">=8" } }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -4706,6 +4837,45 @@ "node": ">= 0.4" } }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -4716,6 +4886,469 @@ "node": ">= 8" } }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -5448,6 +6081,43 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-plugin-jsdoc": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/prettier-plugin-jsdoc/-/prettier-plugin-jsdoc-1.3.2.tgz", + "integrity": "sha512-LNi9eq0TjyZn/PUNf/SYQxxUvGg5FLK4alEbi3i/S+2JbMyTu790c/puFueXzx09KP44oWCJ+TaHRyM/a0rKJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-searching": "^2.0.5", + "comment-parser": "^1.4.0", + "mdast-util-from-markdown": "^2.0.0" + }, + "engines": { + "node": ">=14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "prettier": "^3.0.0" + } + }, + "node_modules/prettier-plugin-packagejson": { + "version": "2.5.10", + "resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.10.tgz", + "integrity": "sha512-LUxATI5YsImIVSaaLJlJ3aE6wTD+nvots18U3GuQMJpUyClChaZlQrqx3dBnbhF20OnKWZyx8EgyZypQtBDtgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "sort-package-json": "2.15.1", + "synckit": "0.9.2" + }, + "peerDependencies": { + "prettier": ">= 1.16.0" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, "node_modules/process-warning": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.1.tgz", @@ -6009,6 +6679,59 @@ "atomic-sleep": "^1.0.0" } }, + "node_modules/sort-object-keys": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.3.tgz", + "integrity": "sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sort-package-json": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-2.15.1.tgz", + "integrity": "sha512-9x9+o8krTT2saA9liI4BljNjwAbvUnWf11Wq+i/iZt8nl2UGYnf3TH5uBydE7VALmP7AGwlfszuEeL8BDyb0YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-indent": "^7.0.1", + "detect-newline": "^4.0.0", + "get-stdin": "^9.0.0", + "git-hooks-list": "^3.0.0", + "is-plain-obj": "^4.1.0", + "semver": "^7.6.0", + "sort-object-keys": "^1.1.3", + "tinyglobby": "^0.2.9" + }, + "bin": { + "sort-package-json": "cli.js" + } + }, + "node_modules/sort-package-json/node_modules/get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sort-package-json/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -6475,6 +7198,36 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/synckit": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", + "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/synckit/node_modules/@pkgr/core": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.2.tgz", + "integrity": "sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -6738,6 +7491,20 @@ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "license": "MIT" }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unrs-resolver": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.3.3.tgz", diff --git a/package.json b/package.json index b32ba9b..3830d35 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,16 @@ { "name": "@filecoin-station/piece-indexer-monorepo", - "private": true, "version": "0.1.0", + "private": true, + "homepage": "https://github.com/filecoin-station/piece-indexer#readme", + "bugs": { + "url": "https://github.com/filecoin-station/piece-indexer/issues" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/filecoin-station/piece-indexer.git" + }, + "license": "(Apache-2.0 AND MIT)", "type": "module", "workspaces": [ "api", @@ -11,20 +20,13 @@ "scripts": { "lint": "eslint && prettier --check .", "lint:fix": "eslint --fix && prettier --write .", + "test": "npm run lint && npm run test:types && npm run test:unit", "test:types": "tsc -p .", - "test:unit": "npm test --workspaces --if-present", - "test": "npm run lint && npm run test:types && npm run test:unit" - }, - "repository": { - "type": "git", - "url": "git+ssh://git@github.com/filecoin-station/piece-indexer.git" + "test:unit": "npm test --workspaces --if-present" }, - "license": "(Apache-2.0 AND MIT)", - "bugs": { - "url": "https://github.com/filecoin-station/piece-indexer/issues" - }, - "homepage": "https://github.com/filecoin-station/piece-indexer#readme", + "prettier": "@checkernetwork/prettier-config", "devDependencies": { + "@checkernetwork/prettier-config": "^1.0.0", "@types/debug": "^4.1.12", "@types/node": "^22.13.17", "eslint": "^9.23.0", diff --git a/repository/lib/redis-repository.js b/repository/lib/redis-repository.js index e037f54..1676210 100644 --- a/repository/lib/redis-repository.js +++ b/repository/lib/redis-repository.js @@ -1,11 +1,9 @@ -/** @import { WalkerState } from './typings.d.ts' */ +/** @import {WalkerState} from './typings.d.ts' */ export class RedisRepository { #redis - /** - * @param {import('ioredis').Redis} redis - */ + /** @param {import('ioredis').Redis} redis */ constructor(redis) { this.#redis = redis } @@ -34,7 +32,10 @@ export class RedisRepository { * @param {string[]} payloadCids */ async addPiecePayloadBlocks(providerId, pieceCid, ...payloadCids) { - await this.#redis.sadd(`piece-payload:${providerId}:${pieceCid}`, ...payloadCids) + await this.#redis.sadd( + `piece-payload:${providerId}:${pieceCid}`, + ...payloadCids, + ) } /** @@ -43,13 +44,13 @@ export class RedisRepository { * @returns {Promise} */ async getPiecePayloadBlocks(providerId, pieceCid) { - const payloadCids = await this.#redis.smembers(`piece-payload:${providerId}:${pieceCid}`) + const payloadCids = await this.#redis.smembers( + `piece-payload:${providerId}:${pieceCid}`, + ) return payloadCids } - /** - * @param {string} providerId - */ + /** @param {string} providerId */ async countPiecesIndexed(providerId) { const keyStream = this.#redis.scanStream({ match: `piece-payload:${providerId}:*`, diff --git a/repository/lib/typings.d.ts b/repository/lib/typings.d.ts index e429146..35ed20a 100644 --- a/repository/lib/typings.d.ts +++ b/repository/lib/typings.d.ts @@ -1,29 +1,10 @@ /** -lastAdCID --> [ ] -\ - ↓ | - ... | entries announced after we started the current walk - ↓ | - [ ] -/ - ↓ - head --> [ ] -\ - ↓ | - ... | entries visited in this walk - ↓ | - [ ] -/ - ↓ - tail --> [ ] -\ - ↓ | - ... | entries NOT visited yet - ↓ | - [ ] -/ - ↓ - lastHead --> [ ] -\ - ↓ | - ... | entries visited in the previous walks - ↓ | - [ ] -/ - ↓ - (null) + * LastAdCID --> [ ] -\ + * ↓ | ... | entries announced after we started the current walk ↓ | [ ] -/ ↓ + * head --> [ ] -\ + * ↓ | ... | entries visited in this walk ↓ | [ ] -/ ↓ tail --> [ ] -\ + * ↓ | ... | entries NOT visited yet ↓ | [ ] -/ ↓ lastHead --> [ ] -\ + * ↓ | ... | entries visited in the previous walks ↓ | [ ] -/ ↓ (null) */ export interface WalkerState { head?: string diff --git a/repository/package.json b/repository/package.json index ed0bbd4..99488af 100644 --- a/repository/package.json +++ b/repository/package.json @@ -1,9 +1,9 @@ { "name": "@filecoin-station/spark-piece-indexer-repository", - "type": "module", "version": "1.0.0", - "main": "lib/redis-repository.js", "private": true, + "type": "module", + "main": "lib/redis-repository.js", "scripts": { "lint": "standard", "test": "node --test --test-reporter=spec" diff --git a/repository/test/redis-repository.test.js b/repository/test/redis-repository.test.js index 48a1b1a..b27d118 100644 --- a/repository/test/redis-repository.test.js +++ b/repository/test/redis-repository.test.js @@ -3,7 +3,7 @@ import assert from 'node:assert' import { after, before, beforeEach, describe, it } from 'node:test' import { RedisRepository } from '../lib/redis-repository.js' -/** @import { WalkerState } from '../lib/typings.d.ts' */ +/** @import {WalkerState} from '../lib/typings.d.ts' */ describe('data schema for REST API', () => { /** @type {Redis} */