diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 9493b0b..0000000 --- a/.eslintignore +++ /dev/null @@ -1,9 +0,0 @@ -src/**/*.js -src/**/*.d.ts -test/**/*.js -test/**/*.d.ts -bin/**/*.js -bin/**/*.d.ts -scripts/**/*.js -scripts/**/*.d.ts -protos/* diff --git a/.eslintrc.yml b/.eslintrc.yml deleted file mode 100644 index d5d3ad3..0000000 --- a/.eslintrc.yml +++ /dev/null @@ -1,72 +0,0 @@ -env: - browser: true - es2021: true -extends: - - 'eslint:recommended' - - 'plugin:@typescript-eslint/recommended' -parser: '@typescript-eslint/parser' -parserOptions: - ecmaVersion: 12 - sourceType: module -plugins: - - '@typescript-eslint' -rules: - linebreak-style: - - error - - unix - quotes: - - error - - single - - - avoidEscape: true - semi: - - error - - always - comma-dangle: - - error - - always-multiline - curly: - - error - - all - dot-location: - - error - - property - dot-notation: - - error - eqeqeq: - - error - - always - no-constructor-return: - - error - no-implicit-globals: - - error - space-infix-ops: - - error - no-duplicate-imports: - - error - no-var: - - error - prefer-const: - - error - prefer-template: - - error - sort-imports: - - error - - - ignoreDeclarationSort: true - arrow-spacing: - - error - - - before: true - after: true - comma-spacing: - - error - - - before: false - after: true - no-multiple-empty-lines: - - error - no-trailing-spaces: - - error - no-tabs: - - error diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 8f0321b..65623ea 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -27,6 +27,9 @@ jobs: - name: Install node_modules run: npm ci + - name: Lint + run: npm run lint + - name: Test run: npm test diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 6346ed4..2d83ba8 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -24,5 +24,8 @@ jobs: - name: Install node_modules run: npm install + - name: Run lint + run: npm run lint + - name: Run tests run: npm test diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..77b5c4f --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,60 @@ +// @ts-check + +import eslint from '@eslint/js'; +import { defineConfig } from 'eslint/config'; +import tseslint from 'typescript-eslint'; + +export default defineConfig( + eslint.configs.recommended, + tseslint.configs.strictTypeChecked, + tseslint.configs.stylisticTypeChecked, + { + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + }, + rules: { + '@typescript-eslint/array-type': ['error', { default: 'generic' }], + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/prefer-literal-enum-member': 'off', + '@typescript-eslint/no-invalid-void-type': 'off', + '@typescript-eslint/require-await': 'off', + '@typescript-eslint/no-confusing-void-expression': [ + 'error', + { ignoreArrowShorthand: true }, + ], + '@typescript-eslint/restrict-template-expressions': [ + 'error', + { allowNumber: true, allowNullish: true }, + ], + '@typescript-eslint/no-unsafe-enum-comparison': 'off', + '@typescript-eslint/method-signature-style': ['error', 'property'], + '@typescript-eslint/explicit-module-boundary-types': 'error', + '@typescript-eslint/strict-boolean-expressions': [ + 'error', + { + allowNullableBoolean: true, + allowNullableNumber: true, + allowNullableString: true, + }, + ], + }, + }, + { + ignores: [ + // ignore config files + 'eslint.config.mjs', + '.prettierrc.js', + // ignore scripts + 'certs/generate-trust-root.js', + 'certs/generate-zk-params.js', + // ignore tsc compiled files + '{src,test}/**/*.js', + '{src,test}/**/*.d.ts', + // ignore compiled protobuf files + 'protos/**', + ], + }, +); diff --git a/package-lock.json b/package-lock.json index 5670ec7..d55b979 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "zod": "^3.20.2" }, "devDependencies": { + "@eslint/js": "^9.36.0", "@types/debug": "^4.1.7", "@types/long": "^4.0.1", "@types/micro": "^7.3.6", @@ -35,12 +36,11 @@ "@types/node": "^20.19.9", "@types/uuid": "^8.3.0", "@types/ws": "^8.2.2", - "@typescript-eslint/eslint-plugin": "^5.10.1", - "@typescript-eslint/parser": "^5.10.1", - "eslint": "^8.7.0", + "eslint": "^9.36.0", "mocha": "^9.2.0", "protobufjs-cli": "^1.1.1", - "typescript": "^5.1.0" + "typescript": "^5.1.0", + "typescript-eslint": "^8.44.1" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -65,39 +65,83 @@ } }, "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.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", "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.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "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/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", "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.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "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": "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.5.2", - "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", @@ -105,33 +149,102 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint/js": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", - "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", + "version": "9.36.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz", + "integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==", "dev": true, + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "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.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" } }, "node_modules/@humanwhocodes/module-importer": { @@ -147,11 +260,19 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@indutny/parallel-prettier": { "version": "3.0.0", @@ -362,11 +483,19 @@ "@types/ms": "*" } }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", - "dev": true + "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/linkify-it": { "version": "3.0.2", @@ -437,12 +566,6 @@ "undici-types": "~6.21.0" } }, - "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", - "dev": true - }, "node_modules/@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", @@ -458,192 +581,57 @@ "@types/node": "*" } }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.60.1.tgz", - "integrity": "sha512-KSWsVvsJsLJv3c4e73y/Bzt7OpqMCADUO846bHcuWYSYM19bldbAeDv7dYyV0jwkbMfJ2XdlzwjhXtuD7OY6bw==", + "node_modules/@typescript-eslint/project-service": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.44.1.tgz", + "integrity": "sha512-ycSa60eGg8GWAkVsKV4E6Nz33h+HjTXbsDT4FILyL8Obk5/mx4tbvCNsLf9zret3ipSumAOG89UcCs/KRaKYrA==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.60.1", - "@typescript-eslint/type-utils": "5.60.1", - "@typescript-eslint/utils": "5.60.1", - "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.60.1.tgz", - "integrity": "sha512-pHWlc3alg2oSMGwsU/Is8hbm3XFbcrb6P5wIxcQW9NsYBfnrubl/GhVVD/Jm/t8HXhA2WncoIRfBtnCgRGV96Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.60.1", - "@typescript-eslint/types": "5.60.1", - "@typescript-eslint/typescript-estree": "5.60.1", + "@typescript-eslint/tsconfig-utils": "^8.44.1", + "@typescript-eslint/types": "^8.44.1", "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.60.1.tgz", - "integrity": "sha512-Dn/LnN7fEoRD+KspEOV0xDMynEmR3iSHdgNsarlXNLGGtcUok8L4N71dxUgt3YvlO8si7E+BJ5Fe3wb5yUw7DQ==", + "node_modules/@typescript-eslint/project-service/node_modules/@typescript-eslint/types": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.44.1.tgz", + "integrity": "sha512-Lk7uj7y9uQUOEguiDIDLYLJOrYHQa7oBiURYVFqIpGxclAFQ78f6VUOM8lI2XEuNOKNB7XuvM2+2cMXAoq4ALQ==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.60.1", - "@typescript-eslint/visitor-keys": "5.60.1" - }, + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.60.1.tgz", - "integrity": "sha512-vN6UztYqIu05nu7JqwQGzQKUJctzs3/Hg7E2Yx8rz9J+4LgtIDFWjjl1gm3pycH0P3mHAcEUBd23LVgfrsTR8A==", + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.44.1.tgz", + "integrity": "sha512-B5OyACouEjuIvof3o86lRMvyDsFwZm+4fBOqFHccIctYgBjqR3qT39FBYGN87khcgf0ExpdCBeGKpKRhSFTjKQ==", "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.60.1", - "@typescript-eslint/utils": "5.60.1", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.60.1.tgz", - "integrity": "sha512-zDcDx5fccU8BA0IDZc71bAtYIcG9PowaOwaD8rjYbqwK7dpe/UMQl3inJ4UtUK42nOCT41jTSCwg76E62JpMcg==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.60.1.tgz", - "integrity": "sha512-hkX70J9+2M2ZT6fhti5Q2FoU9zb+GeZK2SLP1WZlvUDqdMbEKhexZODD1WodNRyO8eS+4nScvT0dts8IdaBzfw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.60.1", - "@typescript-eslint/visitor-keys": "5.60.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.60.1.tgz", - "integrity": "sha512-tiJ7FFdFQOWssFa3gqb94Ilexyw0JVxj6vBzaSpfN/8IhoKkDuSAenUKvsSHw2A/TMpJb26izIszTXaqygkvpQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.60.1", - "@typescript-eslint/types": "5.60.1", - "@typescript-eslint/typescript-estree": "5.60.1", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.60.1.tgz", - "integrity": "sha512-xEYIxKcultP6E/RMKqube11pGjXH1DCo60mQoWhVYyKfLkwbIVVjYxmOenNMxILx0TjCujPTjjnTIVzm09TXIw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.60.1", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@ungap/promise-all-settled": { @@ -653,10 +641,11 @@ "dev": true }, "node_modules/acorn": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", - "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -678,6 +667,7 @@ "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", @@ -744,15 +734,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -814,12 +795,13 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "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.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -868,6 +850,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1048,10 +1031,11 @@ "license": "MIT" }, "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", @@ -1124,30 +1108,6 @@ "node": ">=0.3.1" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/duplexify": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", @@ -1279,95 +1239,99 @@ } }, "node_modules/eslint": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", - "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", + "version": "9.36.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.36.0.tgz", + "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.43.0", - "@humanwhocodes/config-array": "^0.11.10", + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.1", + "@eslint/core": "^0.15.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.36.0", + "@eslint/plugin-kit": "^0.3.5", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.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.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", - "esquery": "^1.4.2", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.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.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -1375,22 +1339,45 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=4.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "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.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" }, @@ -1440,6 +1427,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" }, @@ -1452,6 +1440,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -1484,19 +1473,21 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "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.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -1518,7 +1509,8 @@ "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-levenshtein": { "version": "2.0.6", @@ -1536,22 +1528,24 @@ } }, "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.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "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" }, @@ -1585,23 +1579,25 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "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.1.0", - "rimraf": "^3.0.2" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "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/fs.realpath": { "version": "1.0.0", @@ -1692,47 +1688,13 @@ } }, "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "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" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globals/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1744,17 +1706,12 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, "node_modules/graphemer": { "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/growl": { "version": "1.10.5", @@ -1837,10 +1794,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" @@ -1951,19 +1909,11 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", @@ -2090,17 +2040,35 @@ "node": ">=8" } }, + "node_modules/json-buffer": { + "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, + "license": "MIT" + }, "node_modules/json-schema-traverse": { "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", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" }, + "node_modules/keyv": { + "version": "4.5.4", + "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" + } + }, "node_modules/klaw": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", @@ -2184,18 +2152,6 @@ "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/markdown-it": { "version": "12.3.2", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", @@ -2266,12 +2222,13 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "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.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -2452,12 +2409,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, "node_modules/node-gyp-build": { "version": "4.8.2", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", @@ -2615,6 +2566,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" }, @@ -2644,15 +2596,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2821,10 +2765,11 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2927,6 +2872,7 @@ "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" } @@ -3029,13 +2975,11 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3062,6 +3006,7 @@ "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" }, @@ -3074,6 +3019,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" } @@ -3084,15 +3030,6 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "license": "ISC" }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -3174,12 +3111,6 @@ "node": ">=8" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -3260,6 +3191,7 @@ "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" }, @@ -3275,26 +3207,24 @@ "node": ">=0.6" } }, + "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/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -3331,6 +3261,262 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.44.1.tgz", + "integrity": "sha512-0ws8uWGrUVTjEeN2OM4K1pLKHK/4NiNP/vz6ns+LjT/6sqpaYzIVFajZb1fj/IDwpsrrHb3Jy0Qm5u9CPcKaeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.44.1", + "@typescript-eslint/parser": "8.44.1", + "@typescript-eslint/typescript-estree": "8.44.1", + "@typescript-eslint/utils": "8.44.1" + }, + "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 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.44.1.tgz", + "integrity": "sha512-molgphGqOBT7t4YKCSkbasmu1tb1MgrZ2szGzHbclF7PNmOkSTQVHy+2jXOSnxvR3+Xe1yySHFZoqMpz3TfQsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.44.1", + "@typescript-eslint/type-utils": "8.44.1", + "@typescript-eslint/utils": "8.44.1", + "@typescript-eslint/visitor-keys": "8.44.1", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.44.1", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.44.1.tgz", + "integrity": "sha512-EHrrEsyhOhxYt8MTg4zTF+DJMuNBzWwgvvOYNj/zm1vnaD/IC5zCXFehZv94Piqa2cRFfXrTFxIvO95L7Qc/cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.44.1", + "@typescript-eslint/types": "8.44.1", + "@typescript-eslint/typescript-estree": "8.44.1", + "@typescript-eslint/visitor-keys": "8.44.1", + "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": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.44.1.tgz", + "integrity": "sha512-NdhWHgmynpSvyhchGLXh+w12OMT308Gm25JoRIyTZqEbApiBiQHD/8xgb6LqCWCFcxFtWwaVdFsLPQI3jvhywg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.44.1", + "@typescript-eslint/visitor-keys": "8.44.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.44.1.tgz", + "integrity": "sha512-KdEerZqHWXsRNKjF9NYswNISnFzXfXNDfPxoTh7tqohU/PRIbwTmsjGK6V9/RTYWau7NZvfo52lgVk+sJh0K3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.44.1", + "@typescript-eslint/typescript-estree": "8.44.1", + "@typescript-eslint/utils": "8.44.1", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.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 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.44.1.tgz", + "integrity": "sha512-Lk7uj7y9uQUOEguiDIDLYLJOrYHQa7oBiURYVFqIpGxclAFQ78f6VUOM8lI2XEuNOKNB7XuvM2+2cMXAoq4ALQ==", + "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/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.44.1.tgz", + "integrity": "sha512-qnQJ+mVa7szevdEyvfItbO5Vo+GfZ4/GZWWDRRLjrxYPkhM+6zYB2vRYwCsoJLzqFCdZT4mEqyJoyzkunsZ96A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.44.1", + "@typescript-eslint/tsconfig-utils": "8.44.1", + "@typescript-eslint/types": "8.44.1", + "@typescript-eslint/visitor-keys": "8.44.1", + "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.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.44.1.tgz", + "integrity": "sha512-DpX5Fp6edTlocMCwA+mHY8Mra+pPjRZ0TfHkXI8QFelIKcbADQz1LUPNtzOFUriBB2UYqw4Pi9+xV4w9ZczHFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.44.1", + "@typescript-eslint/types": "8.44.1", + "@typescript-eslint/typescript-estree": "8.44.1" + }, + "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 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.44.1.tgz", + "integrity": "sha512-576+u0QD+Jp3tZzvfRfxon0EA2lzcDt3lhUbsC6Lgzy9x2VR4E+JUiNyGHi5T8vk0TV+fpJ5GLG1JsJuWCaKhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.44.1", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/typescript-eslint/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/typescript-eslint/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/uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -3393,6 +3579,7 @@ "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" } @@ -3528,7 +3715,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "devOptional": true + "optional": true }, "node_modules/yargs": { "version": "16.2.0", diff --git a/package.json b/package.json index a032a1b..e73b895 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,9 @@ "build": "npm run build:protobuf && npm run build:protobuf-ts && npm run build:tsc", "format": "pprettier --write '**/*.ts'", "mocha": "mocha test/**/*-test.js", - "lint": "eslint --cache src test && pprettier --check '**/*.ts'", + "lint:eslint": "eslint .", + "lint:prettier": "pprettier --check '**/*.ts'", + "lint": "npm run lint:eslint && npm run lint:prettier", "test": "npm run mocha && npm run lint", "prepare": "npm run build" }, @@ -60,6 +62,7 @@ "zod": "^3.20.2" }, "devDependencies": { + "@eslint/js": "^9.36.0", "@types/debug": "^4.1.7", "@types/long": "^4.0.1", "@types/micro": "^7.3.6", @@ -68,11 +71,10 @@ "@types/node": "^20.19.9", "@types/uuid": "^8.3.0", "@types/ws": "^8.2.2", - "@typescript-eslint/eslint-plugin": "^5.10.1", - "@typescript-eslint/parser": "^5.10.1", - "eslint": "^8.7.0", + "eslint": "^9.36.0", "mocha": "^9.2.0", "protobufjs-cli": "^1.1.1", - "typescript": "^5.1.0" + "typescript": "^5.1.0", + "typescript-eslint": "^8.44.1" } } diff --git a/src/api/group.ts b/src/api/group.ts index 0226986..7820789 100644 --- a/src/api/group.ts +++ b/src/api/group.ts @@ -63,7 +63,7 @@ export class Group extends GroupData { this.secretParams = secretParams; const cipher = new ClientZkGroupCipher(secretParams); - this.title = decryptBlob(cipher, groupState.title)?.title ?? ''; + this.title = decryptBlob(cipher, groupState.title).title ?? ''; this.privPublicParams = this.secretParams.getPublicParams(); diff --git a/src/api/primary-device.ts b/src/api/primary-device.ts index dad06bf..e3cae64 100644 --- a/src/api/primary-device.ts +++ b/src/api/primary-device.ts @@ -270,7 +270,7 @@ enum SyncState { type SyncEntry = { state: SyncState; onComplete: Promise; - complete(): void; + complete: () => void; }; type DecryptResult = Readonly<{ @@ -417,7 +417,7 @@ class IdentityStore extends IdentityKeyStore { } async getIdentity(name: ProtocolAddress): Promise { - return this.knownIdentities.get(addressToString(name)) || null; + return this.knownIdentities.get(addressToString(name)) ?? null; } // Not part of IdentityKeyStore API @@ -432,7 +432,7 @@ class IdentityStore extends IdentityKeyStore { } export class SessionStore extends SessionStoreBase { - private readonly sessions: Map = new Map(); + private readonly sessions = new Map(); async saveSession( name: ProtocolAddress, @@ -442,12 +442,12 @@ export class SessionStore extends SessionStoreBase { } async getSession(name: ProtocolAddress): Promise { - return this.sessions.get(addressToString(name)) || null; + return this.sessions.get(addressToString(name)) ?? null; } async getExistingSessions( - addresses: ProtocolAddress[], - ): Promise { + addresses: Array, + ): Promise> { return addresses.map((name) => { const existing = this.sessions.get(addressToString(name)); if (!existing) { @@ -459,21 +459,25 @@ export class SessionStore extends SessionStoreBase { } export class SenderKeyStore extends SenderKeyStoreBase { - private readonly keys: Map = new Map(); + private readonly keys = new Map(); async saveSenderKey( sender: ProtocolAddress, distributionId: Uuid, record: SenderKeyRecord, ): Promise { - this.keys.set(`${sender.serviceId}.${distributionId}`, record); + const serviceId = sender.serviceId(); + assert(serviceId != null, 'Missing serviceId for sender'); + this.keys.set(`${serviceId.toString()}.${distributionId}`, record); } async getSenderKey( sender: ProtocolAddress, distributionId: Uuid, ): Promise { - const key = this.keys.get(`${sender.serviceId}.${distributionId}`); - return key || null; + const serviceId = sender.serviceId(); + assert(serviceId != null, 'Missing serviceId for sender'); + const key = this.keys.get(`${serviceId.toString()}.${distributionId}`); + return key ?? null; } } @@ -619,7 +623,7 @@ export class PrimaryDevice { signedPreKey.getPublicKey().serialize(), ); const signedPreKeyId = - this.signedPreKeys.get(serviceIdKind)?.getNextId() || 1; + this.signedPreKeys.get(serviceIdKind)?.getNextId() ?? 1; const signedPreKeyRecord = SignedPreKeyRecord.new( signedPreKeyId, Date.now(), @@ -634,7 +638,7 @@ export class PrimaryDevice { } const lastResortKeyId = - this.kyberPreKeys.get(serviceIdKind)?.getNextId() || 1; + this.kyberPreKeys.get(serviceIdKind)?.getNextId() ?? 1; const lastResortKeyRecord = this.generateKyberPreKey( lastResortKeyId, serviceIdKind, @@ -668,7 +672,7 @@ export class PrimaryDevice { private async *getPreKeyIterator( device: Device, serviceIdKind: ServiceIdKind, - ): AsyncIterator { + ): AsyncIterator { const preKeyStore = this.preKeys.get(serviceIdKind); assert.ok(preKeyStore, 'Missing preKey store'); @@ -677,6 +681,7 @@ export class PrimaryDevice { return; } + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition while (true) { const preKey = PrivateKey.generate(); const publicKey = preKey.getPublicKey(); @@ -710,7 +715,7 @@ export class PrimaryDevice { private async *getKyberPreKeyIterator( device: Device, serviceIdKind: ServiceIdKind, - ): AsyncIterator { + ): AsyncIterator { const kyberPreKeyStore = this.kyberPreKeys.get(serviceIdKind); assert.ok(kyberPreKeyStore, 'Missing kyberPreKeyStore store'); @@ -719,6 +724,7 @@ export class PrimaryDevice { return; } + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition while (true) { const keyId = kyberPreKeyStore.getNextId(); const record = this.generateKyberPreKey(keyId, serviceIdKind); @@ -799,7 +805,7 @@ export class PrimaryDevice { ): Promise> { const records = storage.getAllGroupRecords(); - return await Promise.all( + return Promise.all( records.map(async ({ record }) => { const { groupV2 } = record; assert.ok(groupV2, 'Not a group v2 record!'); @@ -911,7 +917,7 @@ export class PrimaryDevice { groupState: serverGroup.state, }); - if (sendUpdateTo?.length) { + if (sendUpdateTo.length) { const groupV2 = { ...updatedGroup.toContext(), groupChange: Proto.GroupChange.encode( @@ -1075,6 +1081,7 @@ export class PrimaryDevice { false, ); if (!updated) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions throw new Error(`setStorageState: failed to update, ${error}`); } @@ -1124,7 +1131,7 @@ export class PrimaryDevice { content, envelopeType: unsealedType, } = await this.lock(async () => { - return await this.decrypt(source, serviceIdKind, envelopeType, encrypted); + return this.decrypt(source, serviceIdKind, envelopeType, encrypted); }); let handled = true; @@ -1137,7 +1144,7 @@ export class PrimaryDevice { ServiceIdKind.ACI, 'Got sync message on PNI', ); - await this.handleResendRequest( + this.handleResendRequest( unsealedSource, serviceIdKind, unsealedType, @@ -1236,7 +1243,7 @@ export class PrimaryDevice { }, pniSignatureMessage, }; - return await this.encryptContent(target, content, encryptOptions); + return this.encryptContent(target, content, encryptOptions); } public async encryptSyncSent( @@ -1260,7 +1267,7 @@ export class PrimaryDevice { }, }, }; - return await this.encryptContent(target, content, options); + return this.encryptContent(target, content, options); } public async encryptSyncRead( @@ -1278,7 +1285,7 @@ export class PrimaryDevice { }), }, }; - return await this.encryptContent(target, content, options); + return this.encryptContent(target, content, options); } public async sendFetchStorage(options: FetchStorageOptions): Promise { @@ -1333,7 +1340,7 @@ export class PrimaryDevice { ), }, }; - return await this.encryptContent(target, content, options); + return this.encryptContent(target, content, options); } public async sendReceipt( @@ -1498,7 +1505,7 @@ export class PrimaryDevice { ); if (!options?.skipSkdmSend) { - this.sendRaw( + void this.sendRaw( target, { senderKeyDistributionMessage: skdm.serialize(), @@ -1541,11 +1548,11 @@ export class PrimaryDevice { throw new Error('Unsupported envelope type'); } - const serviceIdKind = envelope.destinationServiceIdBinary?.length + const serviceIdKind = envelope.destinationServiceIdBinary.length ? this.device.getServiceIdBinaryKind(envelope.destinationServiceIdBinary) : ServiceIdKind.ACI; - return await this.handleEnvelope( + return this.handleEnvelope( source, serviceIdKind, envelopeType, @@ -1646,8 +1653,8 @@ export class PrimaryDevice { ): Promise { const encoded = Buffer.from(Proto.Content.encode(content).finish()); - return await this.lock(async () => { - return await this.encrypt(target, encoded, options); + return this.lock(async () => { + return this.encrypt(target, encoded, options); }); } @@ -2040,7 +2047,10 @@ export class PrimaryDevice { senderKeys, encrypted, ); - } else if (envelopeType === EnvelopeType.SealedSender) { + } else if ( + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + envelopeType === EnvelopeType.SealedSender + ) { assert(source === undefined, 'Sealed sender must have no source'); const usmc = await SignalClient.sealedSenderDecryptToUsmc( @@ -2091,6 +2101,7 @@ export class PrimaryDevice { return result; } else { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions throw new Error(`Unsupported envelope type: ${envelopeType}`); } @@ -2159,7 +2170,7 @@ export class PrimaryDevice { const version = decryptedManifest.version.toNumber(); const items = await Promise.all( - (decryptedManifest.identifiers || []).map(async ({ type, raw: key }) => { + (decryptedManifest.identifiers ?? []).map(async ({ type, raw: key }) => { assert( type !== null && type !== undefined, 'Missing manifestRecord.keys.type', diff --git a/src/api/server.ts b/src/api/server.ts index a9f5682..f5c804b 100644 --- a/src/api/server.ts +++ b/src/api/server.ts @@ -103,7 +103,7 @@ export type CreatePrimaryDeviceOptions = Readonly<{ }>; export type PendingProvision = { - complete(response: PendingProvisionResponse): Promise; + complete: (response: PendingProvisionResponse) => Promise; }; export type PendingProvisionResponse = Readonly<{ @@ -127,9 +127,11 @@ const CERTS_DIR = path.join(__dirname, '..', '..', 'certs'); const CERT = fs.readFileSync(path.join(CERTS_DIR, 'full-cert.pem')); const KEY = fs.readFileSync(path.join(CERTS_DIR, 'key.pem')); +// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const TRUST_ROOT: TrustRoot = JSON.parse( fs.readFileSync(path.join(CERTS_DIR, 'trust-root.json')).toString(), ); +// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const ZK_PARAMS: ZKParams = JSON.parse( fs.readFileSync(path.join(CERTS_DIR, 'zk-params.json')).toString(), ); @@ -177,7 +179,7 @@ export class Server extends BaseServer { https: { key: KEY, cert: CERT, - ...(config.https || {}), + ...(config.https ?? {}), }, }; @@ -222,18 +224,19 @@ export class Server extends BaseServer { updates2Path: this.config.updates2Path, }); - const server = https.createServer(this.config.https || {}, (req, res) => { - run(req, res, httpHandler); + const server = https.createServer(this.config.https, (req, res) => { + void run(req, res, httpHandler); }); const wss = new WebSocket.Server({ server, + // eslint-disable-next-line @typescript-eslint/no-misused-promises verifyClient: async (info, callback) => { const { url } = info.req; assert(url, 'verifyClient: expected a URL on incoming request'); - const query = parseURL(url, true).query || {}; + const { query } = parseURL(url, true); - if (!query.login && !query.password) { + if (query.login == null && query.password == null) { debug('verifyClient: Allowing connection with no credentials'); callback(true); return; @@ -241,7 +244,7 @@ export class Server extends BaseServer { // Note: when a device has been unlinked, it will use '' as its password if ( - !query.login || + query.login == null || Array.isArray(query.login) || typeof query.password !== 'string' || Array.isArray(query.password) @@ -265,9 +268,9 @@ export class Server extends BaseServer { wss.on('connection', (ws, request) => { const conn = new WSConnection(request, ws, this); - conn.start().catch((error) => { + conn.start().catch((error: unknown) => { ws.close(); - debug('Websocket handling error', error.stack); + debug('Websocket handling error', error); }); }); @@ -281,7 +284,7 @@ export class Server extends BaseServer { this.https = server; - return await new Promise((resolve) => { + return new Promise((resolve) => { server.listen(port, host, () => resolve()); }); } @@ -302,7 +305,7 @@ export class Server extends BaseServer { // public async waitForProvision(): Promise { - return await this.provisionQueue.shift(); + return this.provisionQueue.shift(); } private async waitForStorageManifest( @@ -346,8 +349,8 @@ export class Server extends BaseServer { }: CreatePrimaryDeviceOptions): Promise { const number = await this.generateNumber(); - const registrationId = await generateRegistrationId(); - const pniRegistrationId = await generateRegistrationId(); + const registrationId = generateRegistrationId(); + const pniRegistrationId = generateRegistrationId(); const devicePassword = password ?? generateDevicePassword(); const device = await this.registerDevice({ number, @@ -417,8 +420,8 @@ export class Server extends BaseServer { } public async createSecondaryDevice(primary: PrimaryDevice): Promise { - const registrationId = await generateRegistrationId(); - const pniRegistrationId = await generateRegistrationId(); + const registrationId = generateRegistrationId(); + const pniRegistrationId = generateRegistrationId(); const device = await this.registerDevice({ primary: primary.device, @@ -550,7 +553,7 @@ export class Server extends BaseServer { await this.provisionQueue.pushAndWait({ complete: async (response) => { await responseQueue.pushAndWait(response); - return await resultQueue.shift(); + return resultQueue.shift(); }, }); @@ -560,10 +563,10 @@ export class Server extends BaseServer { primaryDevice, } = await responseQueue.shift(); - const query = parseURL(provisionURL, true).query || {}; + const { query } = parseURL(provisionURL, true); assert.strictEqual(query.uuid, id, 'id mismatch'); - if (!query.pub_key || Array.isArray(query.pub_key)) { + if (query.pub_key == null || Array.isArray(query.pub_key)) { throw new Error('Expected `pub_key` in provision URL'); } @@ -627,10 +630,9 @@ export class Server extends BaseServer { encrypted: Buffer, timestamp: number, ): Promise { - assert( - source || envelopeType === EnvelopeType.SealedSender, - 'No source for non-sealed sender envelope', - ); + if (envelopeType !== EnvelopeType.SealedSender) { + assert(source, 'No source for non-sealed sender envelope'); + } debug('got message for %s.%d', target.aci, target.deviceId); @@ -654,7 +656,7 @@ export class Server extends BaseServer { default: throw new Error(`Unsupported envelope type: ${envelopeType}`); } - this.send( + void this.send( target, Buffer.from( Proto.Envelope.encode({ @@ -889,7 +891,7 @@ export class Server extends BaseServer { await fsPromises.writeFile(finalPath, reencrypted.blob); - this.onNewBackupMediaObject(backupId, { + void this.onNewBackupMediaObject(backupId, { cdn: 3, mediaId: item.mediaId, objectLength: reencrypted.blob.length, diff --git a/src/api/storage-state.ts b/src/api/storage-state.ts index a8eef7d..8266f06 100644 --- a/src/api/storage-state.ts +++ b/src/api/storage-state.ts @@ -89,7 +89,7 @@ class StorageStateItem { return false; } - const masterKey = this.record?.groupV2?.masterKey; + const masterKey = this.record.groupV2?.masterKey; if (!masterKey) { return false; } @@ -103,7 +103,7 @@ class StorageStateItem { } if (serviceIdKind === ServiceIdKind.ACI) { - const existingAci = this.record?.contact?.aciBinary; + const existingAci = this.record.contact?.aciBinary; if (!existingAci?.length) { return false; } @@ -111,7 +111,7 @@ class StorageStateItem { return Buffer.compare(existingAci, device.aciRawUuid) === 0; } - const existingPni = this.record?.contact?.pniBinary; + const existingPni = this.record.contact?.pniBinary; if (!existingPni?.length) { return false; } @@ -239,7 +239,7 @@ export class StorageState { const account = this.getAccountRecord(); assert(account, 'No account record found'); - return (account.pinnedConversations || []).some((convo) => { + return (account.pinnedConversations ?? []).some((convo) => { if (!convo.groupMasterKey) { return false; } @@ -343,8 +343,8 @@ export class StorageState { const account = this.getAccountRecord(); assert(account, 'No account record found'); - return (account.pinnedConversations || []).some((convo) => { - const existing = convo?.contact?.serviceIdBinary; + return (account.pinnedConversations ?? []).some((convo) => { + const existing = convo.contact?.serviceIdBinary; return existing && Buffer.compare(existing, device.aciRawUuid) === 0; }); } @@ -389,7 +389,7 @@ export class StorageState { } public hasKey(storageKey: Buffer): boolean { - return this.hasRecord(({ key }) => key?.equals(storageKey)); + return this.hasRecord(({ key }) => key.equals(storageKey)); } // @@ -533,10 +533,10 @@ export class StorageState { const { pinnedConversations } = account; - const newPinnedConversations = pinnedConversations?.slice() || []; + const newPinnedConversations = pinnedConversations?.slice() ?? []; const existingIndex = newPinnedConversations.findIndex((convo) => { - const existing = convo?.contact?.serviceIdBinary; + const existing = convo.contact?.serviceIdBinary; return ( existing && Buffer.compare(existing, deviceServiceIdBinary) === 0 ); @@ -568,7 +568,7 @@ export class StorageState { const { pinnedConversations } = account; - const newPinnedConversations = pinnedConversations?.slice() || []; + const newPinnedConversations = pinnedConversations?.slice() ?? []; const existingIndex = newPinnedConversations.findIndex((convo) => { if (!convo.groupMasterKey) { diff --git a/src/crypto.ts b/src/crypto.ts index 32ad28b..32b8c8c 100644 --- a/src/crypto.ts +++ b/src/crypto.ts @@ -159,7 +159,7 @@ export function generateSenderCertificate( senderE164: sender.number, senderUuid: sender.aci, senderDevice: sender.deviceId, - expires: Long.fromNumber(sender.expires || NEVER_EXPIRES), + expires: Long.fromNumber(sender.expires ?? NEVER_EXPIRES), identityKey: sender.identityKey.serialize(), signer: serverCert.certificate, }).finish(), @@ -206,7 +206,7 @@ export function deriveStorageKey(masterKey: Buffer): Buffer { function deriveStorageManifestKey(storageKey: Buffer, version: Long): Buffer { const hash = crypto.createHmac('sha256', storageKey); - hash.update(`Manifest_${version}`); + hash.update(`Manifest_${version.toString()}`); return hash.digest(); } @@ -242,9 +242,9 @@ export function deriveStorageItemKey({ } function decryptAESGCM(ciphertext: Buffer, key: Buffer): Buffer { - const iv = ciphertext.slice(0, AESGCM_IV_SIZE); - const tag = ciphertext.slice(ciphertext.length - AUTH_TAG_SIZE); - const rest = ciphertext.slice(iv.length, ciphertext.length - tag.length); + const iv = ciphertext.subarray(0, AESGCM_IV_SIZE); + const tag = ciphertext.subarray(ciphertext.length - AUTH_TAG_SIZE); + const rest = ciphertext.subarray(iv.length, ciphertext.length - tag.length); const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv); @@ -281,6 +281,7 @@ export function decryptStorageManifest( decryptAESGCM(Buffer.from(manifest.value), manifestKey), ); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, @typescript-eslint/strict-boolean-expressions if (!decoded.version) { throw new Error('Missing manifestRecord.version'); } diff --git a/src/data/certificates.ts b/src/data/certificates.ts index cd998fd..cc4f10a 100644 --- a/src/data/certificates.ts +++ b/src/data/certificates.ts @@ -25,7 +25,9 @@ async function loadJSONProperty( property: string, ): Promise { const raw = await fs.readFile(path.join(CERTS_DIR, file)); + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const obj = JSON.parse(raw.toString()); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment const value = obj[property]; assert(typeof value === 'string', `Expected string at: ${file}/${property}`); diff --git a/src/data/device.ts b/src/data/device.ts index 0bb93bf..e49a748 100644 --- a/src/data/device.ts +++ b/src/data/device.ts @@ -51,8 +51,8 @@ export type DeviceKeys = Readonly<{ lastResortKey?: KyberPreKey; signedPreKey?: SignedPreKey; - preKeyIterator?: AsyncIterator; - kyberPreKeyIterator?: AsyncIterator; + preKeyIterator?: AsyncIterator; + kyberPreKeyIterator?: AsyncIterator; }>; export type SingleUseKey = Readonly<{ @@ -69,8 +69,8 @@ type InternalDeviceKeys = Readonly<{ lastResortKey: KyberPreKey; preKeys: Array; kyberPreKeys: Array; - preKeyIterator?: AsyncIterator; - kyberPreKeyIterator?: AsyncIterator; + preKeyIterator?: AsyncIterator; + kyberPreKeyIterator?: AsyncIterator; }>; // Technically, it is infinite. @@ -232,21 +232,17 @@ export class Device { const { value } = await keys.preKeyIterator.next(); preKey = value; } - if (!preKey) { - preKey = keys.preKeys.shift(); - } + preKey ??= keys.preKeys.shift(); let pqPreKey: KyberPreKey | undefined; if (keys.kyberPreKeyIterator) { const { value } = await keys.kyberPreKeyIterator.next(); pqPreKey = value; } - if (!pqPreKey) { - pqPreKey = keys.kyberPreKeys.shift(); - } - if (!pqPreKey) { - pqPreKey = keys.lastResortKey; - } + pqPreKey ??= keys.kyberPreKeys.shift(); + pqPreKey ??= keys.lastResortKey; + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, @typescript-eslint/strict-boolean-expressions if (!pqPreKey) { throw new Error( 'popSingleUseKey: Missing pqPreKey; checked iterator/array/lastResort', diff --git a/src/data/group.ts b/src/data/group.ts index e6accf2..4a146b9 100644 --- a/src/data/group.ts +++ b/src/data/group.ts @@ -26,7 +26,7 @@ export abstract class Group { public get state(): Readonly { const { groupChanges } = this.changes; assert(groupChanges, 'Missing group changes in the group state'); - const state = groupChanges[groupChanges.length - 1].groupState; + const state = groupChanges.at(-1)?.groupState; assert(state, 'Group must have the last state'); return state; } diff --git a/src/server/base.ts b/src/server/base.ts index 592a8ee..c2c0a15 100644 --- a/src/server/base.ts +++ b/src/server/base.ts @@ -205,11 +205,11 @@ export type IsSendRateLimitedOptions = Readonly<{ export { type ModifyGroupResult }; interface WebSocket { - sendMessage(message: Buffer | 'empty'): Promise; + sendMessage: (message: Buffer | 'empty') => Promise; } interface SerializableCredential { - serialize(): Uint8Array; + serialize: () => Uint8Array; } type AuthEntry = Readonly<{ @@ -225,8 +225,8 @@ type StorageAuthEntry = Readonly<{ type MessageQueueEntry = { readonly message: Buffer; - resolve(): void; - reject(error: Error): void; + resolve: () => void; + reject: (error: Error) => void; }; export type CallLinkEntry = Readonly<{ @@ -369,7 +369,7 @@ export abstract class Server { } const result = this.https.address(); - if (!result || typeof result !== 'object') { + if (result == null || typeof result !== 'object') { throw new Error('Invalid .address() result'); } return result; @@ -511,7 +511,7 @@ export abstract class Server { } entry.delete(provisioningCode); - const [primary] = this.devices.get(number) || []; + const [primary] = this.devices.get(number) ?? []; assert(primary !== undefined, 'Missing primary device when provisioning'); const device = await this.registerDevice({ @@ -622,11 +622,11 @@ export abstract class Server { // // Remote config // - public setRemoteConfig(key: string, value: RemoteConfigValueType) { + public setRemoteConfig(key: string, value: RemoteConfigValueType): void { this.remoteConfig.set(key, value); } - public getRemoteConfig() { + public getRemoteConfig(): Map { return this.remoteConfig; } @@ -844,6 +844,7 @@ export abstract class Server { ); // At least one send should succeed, if not - queue + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (success) { return; } @@ -998,7 +999,7 @@ export abstract class Server { await this.clearStorageItems(device); } - const inserts = (insertItem || []).map(async (item) => { + const inserts = (insertItem ?? []).map(async (item) => { assert(item.key instanceof Uint8Array, 'insertItem.key must be a Buffer'); assert( item.value instanceof Uint8Array, @@ -1012,7 +1013,7 @@ export abstract class Server { }); await Promise.all(inserts); - const deletes = (deleteKey || []).map(async (key) => { + const deletes = (deleteKey ?? []).map(async (key) => { return this.deleteStorageItem(device, Buffer.from(key)); }); await Promise.all(deletes); @@ -1260,7 +1261,7 @@ export abstract class Server { ); } - public hasCallLink(roomId: string) { + public hasCallLink(roomId: string): boolean { return this.callLinksByRoomId.has(roomId); } @@ -1355,7 +1356,8 @@ export abstract class Server { const device = list[deviceId - 1]; - debug('removeDevice %j.%j (%j)', device.aci, deviceId, number); + debug('removeDevice %j.%j (%j)', device?.aci, deviceId, number); + assert(device != null, `Missing device for deviceId ${deviceId}`); const copy = [...list]; copy.splice(deviceId - 1, 1); @@ -1379,7 +1381,7 @@ export abstract class Server { if (primary.deviceId !== PRIMARY_DEVICE_ID) { return undefined; } - return await this.getDevice(primary.number, deviceId); + return this.getDevice(primary.number, deviceId); } public async getAllDevicesByServiceId( @@ -1390,7 +1392,7 @@ export abstract class Server { return []; } - return this.devices.get(primary.number) || []; + return this.devices.get(primary.number) ?? []; } public async getSenderCertificate( @@ -1810,7 +1812,7 @@ export abstract class Server { 'base64url', ); - const validatingKey = this.backupKeyById.get(backupId) || newPublicKey; + const validatingKey = this.backupKeyById.get(backupId) ?? newPublicKey; if (!validatingKey) { throw new Error('No backup public key to validate against'); } diff --git a/src/server/group.ts b/src/server/group.ts index 9d0ad28..725fd89 100644 --- a/src/server/group.ts +++ b/src/server/group.ts @@ -170,7 +170,7 @@ export class ServerGroup extends Group { const { userId, role } = member; assert.ok(userId, 'Missing addPendingMembers.added.member.userId'); - assert.ok(role, 'Missing addPendingMembers.added.member.role'); + assert.ok(role != null, 'Missing addPendingMembers.added.member.role'); this.verifyAccess( 'pendingMembers', diff --git a/src/server/http.ts b/src/server/http.ts index b4e2290..e3f4374 100644 --- a/src/server/http.ts +++ b/src/server/http.ts @@ -90,7 +90,7 @@ export const createHandler = ( ); if (!thePath) { - send(res, 400, { error: 'Missing path' }); + void send(res, 400, { error: 'Missing path' }); return; } @@ -127,7 +127,7 @@ export const createHandler = ( ); if (!thePath) { - send(res, 400, { error: 'Missing path' }); + void send(res, 400, { error: 'Missing path' }); return; } @@ -156,6 +156,8 @@ export const createHandler = ( const getCdn3Attachment = get('/cdn3/:folder/*', async (req, res) => { assert(cdn3Path, 'cdn3Path must be set'); + assert(req.params.folder != null, 'Missing folder param'); + assert(req.params._ != null, 'Missing extra params'); if (req.params.folder === 'backups') { const { username, password, error } = parsePassword(req); @@ -166,16 +168,16 @@ export const createHandler = ( req.url, error, ); - send(res, 401, { error }); + void send(res, 401, { error }); return; } if (!username || !password) { - send(res, 401, { error: 'Missing username and/or password' }); + void send(res, 401, { error: 'Missing username and/or password' }); return; } const authorized = await server.authorizeBackupCDN(username, password); if (!authorized) { - send(res, 403, { error: 'Invalid password' }); + void send(res, 403, { error: 'Invalid password' }); return; } } @@ -214,6 +216,7 @@ export const createHandler = ( const getStickerPack = get( '/stickers/:pack/manifest.proto', async (req, res) => { + assert(req.params.pack != null, 'Missing pack param'); const { pack } = req.params; const result = await server.fetchStickerPack(pack); if (!result) { @@ -224,6 +227,8 @@ export const createHandler = ( ); const getSticker = get('/stickers/:pack/full/:sticker', async (req, res) => { + assert(req.params.pack != null, 'Missing pack param'); + assert(req.params.sticker != null, 'Missing sticker param'); const { pack, sticker } = req.params; const result = await server.fetchSticker(pack, parseInt(sticker, 10)); if (!result) { @@ -244,7 +249,7 @@ export const createHandler = ( function toCallLinkResponse(callLink: CallLinkEntry) { return { name: callLink.encryptedName, - restrictions: String(callLink.restrictions), + restrictions: callLink.restrictions, revoked: callLink.revoked, expiration: Math.floor(callLink.expiration / 1000), // unix }; @@ -270,7 +275,7 @@ export const createHandler = ( return send(res, 400, { error: 'Missing room ID' }); } - const body = await json(req); + const body: unknown = await json(req); let callLink: CallLinkEntry; if (!server.hasCallLink(roomId)) { @@ -305,14 +310,14 @@ export const createHandler = ( const { username, password, error } = parsePassword(req); if (error) { debug('%s %s auth failed, error %j', req.method, req.url, error); - send(res, 401, { error }); + void send(res, 401, { error }); return; } const device = await server.auth(username ?? '', password ?? ''); if (!device) { debug('%s %s auth failed, need re-provisioning', req.method, req.url); - send(res, 401, { error: 'Need re-provisioning' }); + void send(res, 401, { error: 'Need re-provisioning' }); return; } @@ -332,11 +337,11 @@ export const createHandler = ( const { error, username, password } = parsePassword(req); if (error) { - send(res, 400, { error }); + void send(res, 400, { error }); return undefined; } if (!username || !password) { - send(res, 400, { error: 'Invalid authorization header' }); + void send(res, 400, { error: 'Invalid authorization header' }); return undefined; } @@ -353,10 +358,11 @@ export const createHandler = ( aciCiphertext = auth.getUuidCiphertext(); const maybePni = auth.getPniCiphertext(); + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions assert(maybePni, 'Auth credentials must have PNI'); pniCiphertext = maybePni; - } catch (_) { - send(res, 403, { error: 'Invalid credentials' }); + } catch { + void send(res, 403, { error: 'Invalid credentials' }); return undefined; } @@ -380,7 +386,7 @@ export const createHandler = ( const group = await server.getGroup(auth.publicParams); if (!group) { - send(res, 404, { error: 'Group not found' }); + void send(res, 404, { error: 'Group not found' }); return undefined; } @@ -394,18 +400,18 @@ export const createHandler = ( const { error, username, password } = parsePassword(req); if (error) { - send(res, 400, { error }); + void send(res, 400, { error }); return undefined; } if (!username || !password) { - send(res, 400, { error: 'Invalid authorization header' }); + void send(res, 400, { error: 'Invalid authorization header' }); return undefined; } const device = await server.storageAuth(username, password); if (!device) { debug('%s %s storage auth failed', req.method, req.url); - send(res, 403, { error: 'Invalid authorization' }); + void send(res, 403, { error: 'Invalid authorization' }); return undefined; } @@ -490,6 +496,7 @@ export const createHandler = ( return send(res, 403, { error: 'Not a member of this group' }); } + assert(req.params.since != null, 'Missing since param'); const since = parseInt(req.params.since, 10); if (since < (member.joinedAtVersion ?? 0)) { return send(res, 403, { error: '`since` is before joinedAtVersion' }); @@ -582,11 +589,11 @@ export const createHandler = ( } const groupData = Proto.Group.decode(Buffer.from(await buffer(req))); - if (!groupData.title) { + if (!groupData.title.length) { return send(res, 400, { error: 'Missing group title' }); } if ( - !groupData.publicKey || + !groupData.publicKey.length || !auth.publicParams.equals(groupData.publicKey) ) { return send(res, 400, { error: 'Invalid group public key' }); @@ -656,7 +663,8 @@ export const createHandler = ( }); if (modifyResult.conflict) { - return send(res, 409, { error: 'Conflict' }); + await send(res, 409, { error: 'Conflict' }); + return; } return { @@ -726,6 +734,7 @@ export const createHandler = ( return; } + assert(req.params.after != null, 'Missing after param'); const after = Long.fromString(req.params.after); const manifest = await server.getStorageManifest(device); if (!manifest?.version?.gt(after)) { @@ -772,7 +781,7 @@ export const createHandler = ( Buffer.from(await buffer(req)), ); - const keys = (readOperation.readKey || []).map((key) => Buffer.from(key)); + const keys = readOperation.readKey.map((key) => Buffer.from(key)); const items = await server.getStorageItems(device, keys); if (!items) { @@ -854,6 +863,7 @@ export const createHandler = ( res.once('finish', () => { debug('response %s %s', req.method, req.url, res.statusCode); }); + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return routes(req, res); } catch (error) { assert(error instanceof Error); diff --git a/src/server/ws/connection.ts b/src/server/ws/connection.ts index 7d4e890..d29073e 100644 --- a/src/server/ws/connection.ts +++ b/src/server/ws/connection.ts @@ -98,7 +98,7 @@ export class Connection extends Service { let credential: Buffer | undefined; if (params.request) { const request = new ProfileKeyCredentialRequest( - Buffer.from(params.request as string, 'hex'), + Buffer.from(params.request, 'hex'), ); if (credentialType === 'expiringProfileKey') { credential = await this.server.issueExpiringProfileKeyCredential( @@ -195,7 +195,7 @@ export class Connection extends Service { if (!body) { return [400, { error: 'Missing body' }]; } - if (!query.ts) { + if (query.ts == null) { return [400, { error: 'Missing ts' }]; } @@ -417,7 +417,7 @@ export class Connection extends Service { const body = DeviceKeysSchema.parse(JSON.parse(rawBody.toString())); try { await server.updateDeviceKeys(this.getDevice(), serviceIdKind, { - preKeys: body.preKeys?.map(decodePreKey), + preKeys: body.preKeys.map(decodePreKey), kyberPreKeys: body.pqPreKeys?.map(decodeKyberPreKey), lastResortKey: body.pqLastResortPreKey ? decodeKyberPreKey(body.pqLastResortPreKey) @@ -453,8 +453,8 @@ export class Connection extends Service { ); this.router.get('/v2/keys/:serviceId/:deviceId', async (params) => { - const serviceId = params.serviceId as ServiceIdString; - const deviceId = parseInt(params.deviceId || '', 10) as DeviceId; + const serviceId = params.serviceId as ServiceIdString | undefined; + const deviceId = parseInt(params.deviceId ?? '', 10) as DeviceId; if (!serviceId || deviceId.toString() !== params.deviceId) { return [400, { error: 'Invalid request parameters' }]; } @@ -469,7 +469,7 @@ export class Connection extends Service { }); this.router.get('/v2/keys/:serviceId(/\\*)', async (params) => { - const serviceId = params.serviceId as ServiceIdString; + const serviceId = params.serviceId as ServiceIdString | undefined; if (!serviceId) { return [400, { error: 'Invalid request parameters' }]; } @@ -479,7 +479,9 @@ export class Connection extends Service { return [404, { error: 'Account not found' }]; } - const serviceIdKind = devices[0].getServiceIdKind(serviceId); + const device = devices[0]; + assert(device != null, `Missing first device for serviceId ${serviceId}`); + const serviceIdKind = device.getServiceIdKind(serviceId); return [200, await getDevicesKeysResult(serviceIdKind, devices)]; }); @@ -733,7 +735,7 @@ export class Connection extends Service { 200, await this.server.listBackupMedia( BackupHeadersSchema.parse(headers), - { cursor: cursor ? String(cursor) : undefined, limit }, + { cursor: cursor != null ? String(cursor) : undefined, limit }, ), ]; }, @@ -1009,7 +1011,7 @@ export class Connection extends Service { } if (path === '/v1/websocket/') { - return await this.handleNormal(this.request); + return this.handleNormal(this.request); } else { debug('websocket connection has unexpected URL %s', url); } diff --git a/src/server/ws/router.ts b/src/server/ws/router.ts index 38e3605..d00d06f 100644 --- a/src/server/ws/router.ts +++ b/src/server/ws/router.ts @@ -10,6 +10,7 @@ import { WSRequest, WSResponse } from './service'; import { JsonValue, PartialDeep } from 'type-fest'; import URLPattern from 'url-pattern'; import { assertJsonValue } from '../../util'; +import assert from 'assert'; const debug = createDebug('mock:ws:router'); @@ -66,7 +67,7 @@ export class Router { const headers: Record = {}; for (const pair of request.headers ?? []) { const [field, value = ''] = pair.split(/\s*:\s*/, 2); - + assert(field != null, 'Missing field name for header'); headers[field.toLowerCase()] = value; } @@ -79,6 +80,7 @@ export class Router { request.path, ); + // eslint-disable-next-line @typescript-eslint/no-deprecated const { pathname, query } = parseURL(request.path ?? ''); for (const { method, pattern, handler } of this.routes) { @@ -86,14 +88,14 @@ export class Router { continue; } - const params = pattern.match(pathname ?? ''); - if (!params) { + const params: unknown = pattern.match(pathname ?? ''); + if (params == null) { continue; } const decodedParams: Record = {}; for (const [key, value] of Object.entries(params)) { - decodedParams[String(key)] = decodeURIComponent(String(value)); + decodedParams[key] = decodeURIComponent(String(value)); } response = await handler( diff --git a/src/server/ws/service.ts b/src/server/ws/service.ts index f323052..5db27ca 100644 --- a/src/server/ws/service.ts +++ b/src/server/ws/service.ts @@ -21,12 +21,13 @@ interface RequestOptions { } export abstract class Service { - private readonly requests: Map void> = new Map(); + private readonly requests = new Map void>(); private lastSentId = 0; constructor(protected readonly ws: WebSocket) { this.ws = ws; + // eslint-disable-next-line @typescript-eslint/no-misused-promises this.ws.on('message', async (message) => { try { await this.onMessage(message); @@ -57,7 +58,7 @@ export abstract class Service { this.ws.send(packet); - return await new Promise((resolve) => this.requests.set(id, resolve)); + return new Promise((resolve) => this.requests.set(id, resolve)); } private async onMessage(raw: WebSocket.Data): Promise { @@ -79,7 +80,7 @@ export abstract class Service { const id = parseInt(response.id.toString(), 10); if (isNaN(id)) { - throw new Error(`Invalid response.id: ${response.id}`); + throw new Error(`Invalid response.id: ${response.id.toString()}`); } const resolve = this.requests.get(id); diff --git a/src/util.ts b/src/util.ts index 1d800e9..8349b21 100644 --- a/src/util.ts +++ b/src/util.ts @@ -52,20 +52,21 @@ export function parseAuthHeader( } const [basic, base64] = header.split(/\s+/g, 2); - if (basic.toLowerCase() !== 'basic') { + if (basic?.toLowerCase() !== 'basic') { return { error: `Unsupported authorization type ${basic}` }; } - let username: string; - let password: string; + let decoded: string; try { - const decoded = Buffer.from(base64, 'base64').toString(); - [username, password] = decoded.split(':', 2); + assert(base64 != null, 'Missing base64 for basic authorization'); + decoded = Buffer.from(base64, 'base64').toString(); } catch (error) { assert(error instanceof Error); return { error: error.message }; } + const [username, password = ''] = decoded.split(':', 2); + if (!username) { return { error: 'Missing username' }; } @@ -86,7 +87,7 @@ export class PromiseQueue { this.defaultTimeout = config.timeout; } - public get size() { + public get size(): number { return this.entries.length; } @@ -102,7 +103,7 @@ export class PromiseQueue { } // Not waiting for `.shift()` - queue. - return await new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { let timer: NodeJS.Timeout | undefined; const entry = { @@ -158,7 +159,7 @@ export class PromiseQueue { return entry.value; } - return await new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { let timer: NodeJS.Timeout | undefined; const resolveEntry = (value: T) => { @@ -235,7 +236,7 @@ export function fromURLSafeBase64(base64: string): Buffer { } export function assertJsonValue(root: unknown): asserts root is JsonValue { - const issues: string[] = []; + const issues: Array = []; function visit(node: unknown, path: ReadonlyArray) { if ( @@ -282,7 +283,7 @@ export function serviceIdKindFromQuery( export async function getDevicesKeysResult( serviceIdKind: ServiceIdKind, devices: ReadonlyArray, -) { +): Promise { const [primary] = devices; assert(primary !== undefined, 'Empty device list'); diff --git a/test/util-test.ts b/test/util-test.ts index 1c80e8c..6528cd8 100644 --- a/test/util-test.ts +++ b/test/util-test.ts @@ -148,7 +148,9 @@ describe('util', () => { invalid(() => 'hi', /value: \[Function \(anonymous\)\]/); invalid(Buffer.from('hi'), /value: /); invalid(new Uint8Array([68, 69]), /value: Uint8Array\(2\) \[ 68, 69 \]/); + // eslint-disable-next-line @typescript-eslint/no-extraneous-class invalid(class Foo {}, /value: \[class Foo\]/); + // eslint-disable-next-line @typescript-eslint/no-extraneous-class invalid(new (class Foo {})(), /value: Foo {}/); invalid( Long.fromNumber(42), diff --git a/tsconfig.json b/tsconfig.json index d2bd341..5a09023 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,8 @@ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ - + "noUncheckedIndexedAccess": true, + /* Additional Checks */ "noUnusedLocals": true, /* Report errors on unused locals. */ "noImplicitOverride": true,