From 0159a99ae0401cf06c6eeb60faef333d83a6cda8 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 13 Sep 2024 00:20:58 +0200 Subject: [PATCH 01/18] fix: Linting for Node.js --- eslint.config.mjs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index a474506..0806d48 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,6 +1,7 @@ import js from '@eslint/js'; import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; import tseslint from 'typescript-eslint'; +import globals from 'globals'; export default [ js.configs.recommended, @@ -10,8 +11,8 @@ export default [ ignores: ['dist/**/*'], languageOptions: { globals: { - browser: true, - node: true, + ...globals.browser, + ...globals.node, }, }, }, From 26e65c83abb193161d71e2d781b8cadb691c96f4 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 13 Sep 2024 00:21:10 +0200 Subject: [PATCH 02/18] fix: Remove docs/ dir from published package --- .npmignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.npmignore b/.npmignore index 27ca747..edf3213 100644 --- a/.npmignore +++ b/.npmignore @@ -5,7 +5,7 @@ coverage test node_modules package -scripts +docs CODE_OF_CONDUCT.md SECURITY.md @@ -17,6 +17,7 @@ SECURITY.md tsconfig.json eslint.config.mjs jest.config.js +.prettierignore .DS_Store src \ No newline at end of file From dd9608e30fab38ff006ab2a76e8070e2208cec01 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 13 Sep 2024 00:21:25 +0200 Subject: [PATCH 03/18] fix: Run build only before publishing --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dce2656..689368f 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "test": "jest --forceExit --coverage --detectOpenHandles", "lint": "eslint ./src/**/*.ts ./test/**/*.spec.ts", "release": "npm version patch && git push --tags", - "prepare": "npm run build", + "prepublishOnly": "npm run build", "size": "size-limit", "analyze": "size-limit --why" }, From 5f30512d26f8080996370ff5cc4e29ed09447534 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 13 Sep 2024 00:31:40 +0200 Subject: [PATCH 04/18] chore: Remove old way of building + fix iife builds by adding namespace --- package-lock.json | 3977 ++++++++++++++++++--------------------------- package.json | 8 +- scripts/build.js | 92 -- tsup.config.ts | 13 + 4 files changed, 1564 insertions(+), 2526 deletions(-) delete mode 100644 scripts/build.js create mode 100644 tsup.config.ts diff --git a/package-lock.json b/package-lock.json index 7a4e19d..61b169a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -682,2168 +682,1715 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", "cpu": [ - "ppc64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "aix" + "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], + "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==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, "engines": { - "node": ">=12" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=12" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/config-array": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/js": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.8.0.tgz", + "integrity": "sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "license": "Apache-2.0", "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "license": "Apache-2.0", "engines": { - "node": ">=12" + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", "engines": { - "node": ">=12" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, "engines": { "node": ">=12" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } + "license": "MIT" }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "ansi-regex": "^6.0.1" + }, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" + "dependencies": { + "sprintf-js": "~1.0.2" } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", - "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", - "cpu": [ - "arm64" - ], + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], + "dependencies": { + "p-locate": "^4.1.0" + }, "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "p-try": "^2.0.0" + }, "engines": { - "node": ">=12" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "p-limit": "^2.2.0" + }, "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">=12" + "node": ">=8" } }, - "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==", + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "node": ">=8" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", - "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", - "dev": true, - "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.4", - "debug": "^4.3.1", - "minimatch": "^3.1.2" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/@eslint/js": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.8.0.tgz", - "integrity": "sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==", + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "dev": true, "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", - "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" }, "engines": { - "node": ">=12" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "jest-get-type": "^29.6.3" }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "dev": true, "license": "MIT", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" }, "engines": { - "node": ">=12" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", "dev": true, "license": "MIT", "dependencies": { - "sprintf-js": "~1.0.2" + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { - "node": ">=8" + "node": ">=6.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6.0.0" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6.0.0" } }, - "node_modules/@jest/console": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jest/core": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "node": ">= 8" } }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 8" } }, - "node_modules/@jest/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "license": "MIT", "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 8" } }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3" - }, + "optional": true, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=14" } }, - "node_modules/@jest/fake-timers": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", - "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" } }, - "node_modules/@jest/globals": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", - "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "node_modules/@rollup/plugin-commonjs": { + "version": "21.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.1.0.tgz", + "integrity": "sha512-6ZtHx3VHIp2ReNNDxHjuUml6ur+WcQ28N1yHgCQwsbNkQg2suhxGMDQGJOn/KuDxKtd1xuZP5xSTwBA4GQ8hbA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" + "@rollup/pluginutils": "^3.1.0", + "commondir": "^1.0.1", + "estree-walker": "^2.0.1", + "glob": "^7.1.6", + "is-reference": "^1.2.1", + "magic-string": "^0.25.7", + "resolve": "^1.17.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^2.38.3" } }, - "node_modules/@jest/reporters": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", - "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "node_modules/@rollup/plugin-node-resolve": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz", + "integrity": "sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.19.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.0.0" }, "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "rollup": "^2.42.0" } }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@sinclair/typebox": "^0.27.8" + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" } }, - "node_modules/@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", "dev": true, "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } + "peer": true }, - "node_modules/@jest/test-result": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", + "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", - "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@jest/transform": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "type-detect": "4.0.8" } }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "@sinonjs/commons": "^3.0.0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "node_modules/@size-limit/esbuild": { + "version": "11.1.4", + "resolved": "https://registry.npmjs.org/@size-limit/esbuild/-/esbuild-11.1.4.tgz", + "integrity": "sha512-Nxh+Fw4Z7sFjRLeT7GDZIy297VXyJrMvG20UDSWP31QgglriEBDkW9U77T7W6js5FaEr89bYVrGzpHfmE1CLFw==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" + "esbuild": "^0.21.3", + "nanoid": "^5.0.7" }, "engines": { - "node": ">=6.0.0" + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "size-limit": "11.1.4" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@size-limit/esbuild/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.0.0" + "node": ">=12" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "node_modules/@size-limit/esbuild/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, + "hasInstallScript": true, "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, "engines": { - "node": ">=6.0.0" + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "node_modules/@size-limit/file": { + "version": "11.1.4", + "resolved": "https://registry.npmjs.org/@size-limit/file/-/file-11.1.4.tgz", + "integrity": "sha512-QxnGj9cxhCEuqMAV01gqonXIKcc+caZqFHZpV51oL2ZJNGSPP9Q/yyf+7HbVe00faOFd1dZZwMwzZmX7HQ9LbA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "size-limit": "11.1.4" + } }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "node_modules/@size-limit/preset-small-lib": { + "version": "11.1.4", + "resolved": "https://registry.npmjs.org/@size-limit/preset-small-lib/-/preset-small-lib-11.1.4.tgz", + "integrity": "sha512-wELW374esv+2Nlzf7g+qW4Af9L69duLoO9F52f0sGk/nzb6et7u8gLRvweWrBfm3itUrqHCpGSSVabTsIU8kNw==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@size-limit/esbuild": "11.1.4", + "@size-limit/file": "11.1.4", + "size-limit": "11.1.4" }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" + "peerDependencies": { + "size-limit": "11.1.4" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@swc/core": { + "version": "1.7.26", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.26.tgz", + "integrity": "sha512-f5uYFf+TmMQyYIoxkn/evWhNGuUzC730dFwAKGwBVHHVoPyak1/GvJUm6i1SKl+2Hrj9oN0i3WSoWWZ4pgI8lw==", "dev": true, - "license": "MIT", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.12" }, "engines": { - "node": ">= 8" + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.7.26", + "@swc/core-darwin-x64": "1.7.26", + "@swc/core-linux-arm-gnueabihf": "1.7.26", + "@swc/core-linux-arm64-gnu": "1.7.26", + "@swc/core-linux-arm64-musl": "1.7.26", + "@swc/core-linux-x64-gnu": "1.7.26", + "@swc/core-linux-x64-musl": "1.7.26", + "@swc/core-win32-arm64-msvc": "1.7.26", + "@swc/core-win32-ia32-msvc": "1.7.26", + "@swc/core-win32-x64-msvc": "1.7.26" + }, + "peerDependencies": { + "@swc/helpers": "*" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@swc/core-darwin-arm64": { + "version": "1.7.26", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.26.tgz", + "integrity": "sha512-FF3CRYTg6a7ZVW4yT9mesxoVVZTrcSWtmZhxKCYJX9brH4CS/7PRPjAKNk6kzWgWuRoglP7hkjQcd6EpMcZEAw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "license": "Apache-2.0 AND MIT", "optional": true, + "os": [ + "darwin" + ], + "peer": true, "engines": { - "node": ">=14" + "node": ">=10" } }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } + "license": "Apache-2.0", + "optional": true, + "peer": true }, - "node_modules/@rollup/plugin-commonjs": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.1.0.tgz", - "integrity": "sha512-6ZtHx3VHIp2ReNNDxHjuUml6ur+WcQ28N1yHgCQwsbNkQg2suhxGMDQGJOn/KuDxKtd1xuZP5xSTwBA4GQ8hbA==", + "node_modules/@swc/helpers": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.13.tgz", + "integrity": "sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true, "peer": true, "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^2.38.3" + "tslib": "^2.4.0" } }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz", - "integrity": "sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==", + "node_modules/@swc/types": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.12.tgz", + "integrity": "sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true, "peer": true, "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "deepmerge": "^4.2.2", - "is-builtin-module": "^3.1.0", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^2.42.0" + "@swc/counter": "^0.1.3" } }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } + "optional": true, + "peer": true }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true, "license": "MIT", + "optional": true, "peer": true }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", - "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==", - "cpu": [ - "arm" - ], + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "android" - ] + "peer": true }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz", - "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==", - "cpu": [ - "arm64" - ], + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "android" - ] + "peer": true }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", - "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", - "cpu": [ - "arm64" - ], + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz", - "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==", - "cpu": [ - "x64" - ], + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] + "dependencies": { + "@babel/types": "^7.0.0" + } }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz", - "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==", - "cpu": [ - "arm" - ], + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz", - "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==", - "cpu": [ - "arm" - ], + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@babel/types": "^7.20.7" + } }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz", - "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==", - "cpu": [ - "arm64" - ], + "node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "peer": true }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz", - "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==", - "cpu": [ - "arm64" - ], + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@types/node": "*" + } }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz", - "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==", - "cpu": [ - "ppc64" - ], + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "license": "MIT" }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz", - "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==", - "cpu": [ - "riscv64" - ], + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz", - "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==", - "cpu": [ - "s390x" - ], + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@types/istanbul-lib-report": "*" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", - "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", - "cpu": [ - "x64" - ], + "node_modules/@types/jest": { + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", - "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", - "cpu": [ - "x64" - ], + "node_modules/@types/node": { + "version": "20.14.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz", + "integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "undici-types": "~5.26.4" + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", - "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", - "cpu": [ - "arm64" - ], + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "peer": true, + "dependencies": { + "@types/node": "*" + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", - "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", - "cpu": [ - "ia32" - ], + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "license": "MIT" }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", - "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", - "cpu": [ - "x64" - ], + "node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "@types/yargs-parser": "*" + } }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true, "license": "MIT" }, - "node_modules/@sindresorhus/merge-streams": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", - "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.1.tgz", + "integrity": "sha512-5g3Y7GDFsJAnY4Yhvk8sZtFfV6YNF2caLzjrRPUBzewjPCaj0yokePB4LJSobyCzGMzjZZYFbwuzbfDHlimXbQ==", "dev": true, "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.0.1", + "@typescript-eslint/type-utils": "8.0.1", + "@typescript-eslint/utils": "8.0.1", + "@typescript-eslint/visitor-keys": "8.0.1", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "node_modules/@typescript-eslint/parser": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.0.1.tgz", + "integrity": "sha512-5IgYJ9EO/12pOUwiBKFkpU7rS3IU21mtXzB81TNwq2xEybcmAZrE9qwDtsb5uQd9aVO9o0fdabFyAmKveXyujg==", "dev": true, - "license": "BSD-3-Clause", + "license": "BSD-2-Clause", "dependencies": { - "type-detect": "4.0.8" + "@typescript-eslint/scope-manager": "8.0.1", + "@typescript-eslint/types": "8.0.1", + "@typescript-eslint/typescript-estree": "8.0.1", + "@typescript-eslint/visitor-keys": "8.0.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" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.1.tgz", + "integrity": "sha512-NpixInP5dm7uukMiRyiHjRKkom5RIFA4dfiHvalanD2cF0CLUuQqxfg8PtEUo9yqJI2bBhF+pcSafqnG3UBnRQ==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "@sinonjs/commons": "^3.0.0" + "@typescript-eslint/types": "8.0.1", + "@typescript-eslint/visitor-keys": "8.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@size-limit/esbuild": { - "version": "11.1.4", - "resolved": "https://registry.npmjs.org/@size-limit/esbuild/-/esbuild-11.1.4.tgz", - "integrity": "sha512-Nxh+Fw4Z7sFjRLeT7GDZIy297VXyJrMvG20UDSWP31QgglriEBDkW9U77T7W6js5FaEr89bYVrGzpHfmE1CLFw==", + "node_modules/@typescript-eslint/type-utils": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.0.1.tgz", + "integrity": "sha512-+/UT25MWvXeDX9YaHv1IS6KI1fiuTto43WprE7pgSMswHbn1Jm9GEM4Txp+X74ifOWV8emu2AWcbLhpJAvD5Ng==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "nanoid": "^5.0.7" + "@typescript-eslint/typescript-estree": "8.0.1", + "@typescript-eslint/utils": "8.0.1", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "size-limit": "11.1.4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@size-limit/file": { - "version": "11.1.4", - "resolved": "https://registry.npmjs.org/@size-limit/file/-/file-11.1.4.tgz", - "integrity": "sha512-QxnGj9cxhCEuqMAV01gqonXIKcc+caZqFHZpV51oL2ZJNGSPP9Q/yyf+7HbVe00faOFd1dZZwMwzZmX7HQ9LbA==", + "node_modules/@typescript-eslint/types": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.1.tgz", + "integrity": "sha512-PpqTVT3yCA/bIgJ12czBuE3iBlM3g4inRSC5J0QOdQFAn07TYrYEQBBKgXH1lQpglup+Zy6c1fxuwTk4MTNKIw==", "dev": true, "license": "MIT", "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "size-limit": "11.1.4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@size-limit/preset-small-lib": { - "version": "11.1.4", - "resolved": "https://registry.npmjs.org/@size-limit/preset-small-lib/-/preset-small-lib-11.1.4.tgz", - "integrity": "sha512-wELW374esv+2Nlzf7g+qW4Af9L69duLoO9F52f0sGk/nzb6et7u8gLRvweWrBfm3itUrqHCpGSSVabTsIU8kNw==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.1.tgz", + "integrity": "sha512-8V9hriRvZQXPWU3bbiUV4Epo7EvgM6RTs+sUmxp5G//dBGy402S7Fx0W0QkB2fb4obCF8SInoUzvTYtc3bkb5w==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "@size-limit/esbuild": "11.1.4", - "@size-limit/file": "11.1.4", - "size-limit": "11.1.4" + "@typescript-eslint/types": "8.0.1", + "@typescript-eslint/visitor-keys": "8.0.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, - "peerDependencies": { - "size-limit": "11.1.4" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "balanced-match": "^1.0.0" } }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.0.0" + "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" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.20.7" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "node_modules/@typescript-eslint/utils": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.1.tgz", + "integrity": "sha512-CBFR0G0sCt0+fzfnKaciu9IBsKvEKYwN9UZ+eeogK1fYHg4Qxk1yf/wLQkLXlq8wbU2dFlgAesxt8Gi76E8RTA==", "dev": true, "license": "MIT", - "peer": true + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.0.1", + "@typescript-eslint/types": "8.0.1", + "@typescript-eslint/typescript-estree": "8.0.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" + } }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.1.tgz", + "integrity": "sha512-W5E+o0UfUcK5EgchLZsyVWqARmsM7v54/qEq6PY3YI5arkgmCzHiuk0zKSJJbm71V0xdRna4BGomkCTXz2/LkQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" + "@typescript-eslint/types": "8.0.1", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" } }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@types/jest": { - "version": "29.5.12", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", - "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", + "node_modules/acorn-walk": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" } }, - "node_modules/@types/node": { - "version": "20.14.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz", - "integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==", + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@types/node": "*" + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/yargs": { - "version": "17.0.32", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", - "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.1.tgz", - "integrity": "sha512-5g3Y7GDFsJAnY4Yhvk8sZtFfV6YNF2caLzjrRPUBzewjPCaj0yokePB4LJSobyCzGMzjZZYFbwuzbfDHlimXbQ==", + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.0.1", - "@typescript-eslint/type-utils": "8.0.1", - "@typescript-eslint/utils": "8.0.1", - "@typescript-eslint/visitor-keys": "8.0.1", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typescript-eslint/parser": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.0.1.tgz", - "integrity": "sha512-5IgYJ9EO/12pOUwiBKFkpU7rS3IU21mtXzB81TNwq2xEybcmAZrE9qwDtsb5uQd9aVO9o0fdabFyAmKveXyujg==", + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/scope-manager": "8.0.1", - "@typescript-eslint/types": "8.0.1", - "@typescript-eslint/typescript-estree": "8.0.1", - "@typescript-eslint/visitor-keys": "8.0.1", - "debug": "^4.3.4" - }, + "license": "MIT", "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" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=8" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.1.tgz", - "integrity": "sha512-NpixInP5dm7uukMiRyiHjRKkom5RIFA4dfiHvalanD2cF0CLUuQqxfg8PtEUo9yqJI2bBhF+pcSafqnG3UBnRQ==", + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.0.1", - "@typescript-eslint/visitor-keys": "8.0.1" + "color-convert": "^2.0.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.0.1.tgz", - "integrity": "sha512-+/UT25MWvXeDX9YaHv1IS6KI1fiuTto43WprE7pgSMswHbn1Jm9GEM4Txp+X74ifOWV8emu2AWcbLhpJAvD5Ng==", + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", "dependencies": { - "@typescript-eslint/typescript-estree": "8.0.1", - "@typescript-eslint/utils": "8.0.1", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">= 8" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.1.tgz", - "integrity": "sha512-PpqTVT3yCA/bIgJ12czBuE3iBlM3g4inRSC5J0QOdQFAn07TYrYEQBBKgXH1lQpglup+Zy6c1fxuwTk4MTNKIw==", + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true, "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } + "optional": true, + "peer": true }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.1.tgz", - "integrity": "sha512-8V9hriRvZQXPWU3bbiUV4Epo7EvgM6RTs+sUmxp5G//dBGy402S7Fx0W0QkB2fb4obCF8SInoUzvTYtc3bkb5w==", + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "8.0.1", - "@typescript-eslint/visitor-keys": "8.0.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } + "license": "Python-2.0" }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" + "engines": { + "node": ">=8" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dev": true, "license": "MIT", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", "slash": "^3.0.0" }, "engines": { - "node": ">=10" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.8.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, - "license": "ISC", + "license": "BSD-3-Clause", "dependencies": { - "brace-expansion": "^2.0.1" + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.1.tgz", - "integrity": "sha512-CBFR0G0sCt0+fzfnKaciu9IBsKvEKYwN9UZ+eeogK1fYHg4Qxk1yf/wLQkLXlq8wbU2dFlgAesxt8Gi76E8RTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.0.1", - "@typescript-eslint/types": "8.0.1", - "@typescript-eslint/typescript-estree": "8.0.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" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.1.tgz", - "integrity": "sha512-W5E+o0UfUcK5EgchLZsyVWqARmsM7v54/qEq6PY3YI5arkgmCzHiuk0zKSJJbm71V0xdRna4BGomkCTXz2/LkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.0.1", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", - "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, - "license": "MIT" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true, - "license": "MIT" - }, - "node_modules/babel-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" + "node": ">=8" } }, "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { @@ -3523,9 +3070,9 @@ } }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -3533,32 +3080,33 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.23.1", + "@esbuild/android-arm": "0.23.1", + "@esbuild/android-arm64": "0.23.1", + "@esbuild/android-x64": "0.23.1", + "@esbuild/darwin-arm64": "0.23.1", + "@esbuild/darwin-x64": "0.23.1", + "@esbuild/freebsd-arm64": "0.23.1", + "@esbuild/freebsd-x64": "0.23.1", + "@esbuild/linux-arm": "0.23.1", + "@esbuild/linux-arm64": "0.23.1", + "@esbuild/linux-ia32": "0.23.1", + "@esbuild/linux-loong64": "0.23.1", + "@esbuild/linux-mips64el": "0.23.1", + "@esbuild/linux-ppc64": "0.23.1", + "@esbuild/linux-riscv64": "0.23.1", + "@esbuild/linux-s390x": "0.23.1", + "@esbuild/linux-x64": "0.23.1", + "@esbuild/netbsd-x64": "0.23.1", + "@esbuild/openbsd-arm64": "0.23.1", + "@esbuild/openbsd-x64": "0.23.1", + "@esbuild/sunos-x64": "0.23.1", + "@esbuild/win32-arm64": "0.23.1", + "@esbuild/win32-ia32": "0.23.1", + "@esbuild/win32-x64": "0.23.1" } }, "node_modules/escalade": { @@ -5563,9 +5111,9 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "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": { @@ -6559,906 +6107,475 @@ "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/sucrase": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "^10.3.10", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/sucrase/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/sucrase/node_modules/glob": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.2.tgz", - "integrity": "sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sucrase/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/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/synckit": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", - "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/ts-jest": { - "version": "29.2.4", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.4.tgz", - "integrity": "sha512-3d6tgDyhCI29HlpwIq87sNuI+3Q6GLTTCeYRHCs7vDz+/3GCMwEtV9jezLyl4ZtnBgx00I7hm8PCP8cTksMGrw==", - "dev": true, - "license": "MIT", - "dependencies": { - "bs-logger": "0.x", - "ejs": "^3.1.10", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", - "json5": "^2.2.3", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "^7.5.3", - "yargs-parser": "^21.0.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/transform": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true, - "license": "0BSD" - }, - "node_modules/tsup": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.2.4.tgz", - "integrity": "sha512-akpCPePnBnC/CXgRrcy72ZSntgIEUa1jN0oJbbvpALWKNOz1B7aM+UVDWGRGIO/T/PZugAESWDJUAb5FD48o8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "bundle-require": "^5.0.0", - "cac": "^6.7.14", - "chokidar": "^3.6.0", - "consola": "^3.2.3", - "debug": "^4.3.5", - "esbuild": "^0.23.0", - "execa": "^5.1.1", - "globby": "^11.1.0", - "joycon": "^3.1.1", - "picocolors": "^1.0.1", - "postcss-load-config": "^6.0.1", - "resolve-from": "^5.0.0", - "rollup": "^4.19.0", - "source-map": "0.8.0-beta.0", - "sucrase": "^3.35.0", - "tree-kill": "^1.2.2" - }, - "bin": { - "tsup": "dist/cli-default.js", - "tsup-node": "dist/cli-node.js" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@microsoft/api-extractor": "^7.36.0", - "@swc/core": "^1", - "postcss": "^8.4.12", - "typescript": ">=4.5.0" - }, - "peerDependenciesMeta": { - "@microsoft/api-extractor": { - "optional": true - }, - "@swc/core": { - "optional": true - }, - "postcss": { - "optional": true - }, - "typescript": { - "optional": true - } + "engines": { + "node": ">=8" } }, - "node_modules/tsup/node_modules/@esbuild/aix-ppc64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", - "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", - "cpu": [ - "ppc64" - ], + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "aix" - ], + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/tsup/node_modules/@esbuild/android-arm": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", - "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", - "cpu": [ - "arm" - ], + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/tsup/node_modules/@esbuild/android-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", - "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", - "cpu": [ - "arm64" - ], + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/tsup/node_modules/@esbuild/android-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", - "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", - "cpu": [ - "x64" - ], + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": ">=6" } }, - "node_modules/tsup/node_modules/@esbuild/darwin-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", - "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", - "cpu": [ - "arm64" - ], + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">=18" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tsup/node_modules/@esbuild/darwin-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", - "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", - "cpu": [ - "x64" - ], + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, "engines": { - "node": ">=18" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/tsup/node_modules/@esbuild/freebsd-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", - "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", - "cpu": [ - "arm64" - ], + "node_modules/sucrase/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.2.tgz", + "integrity": "sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, "engines": { - "node": ">=18" + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/tsup/node_modules/@esbuild/freebsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", - "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", - "cpu": [ - "x64" - ], + "node_modules/sucrase/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, "engines": { - "node": ">=18" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/tsup/node_modules/@esbuild/linux-arm": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", - "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", - "cpu": [ - "arm" - ], + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/tsup/node_modules/@esbuild/linux-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", - "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", - "cpu": [ - "arm64" - ], + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tsup/node_modules/@esbuild/linux-ia32": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", - "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", - "cpu": [ - "ia32" - ], + "node_modules/synckit": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" } }, - "node_modules/tsup/node_modules/@esbuild/linux-loong64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", - "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", - "cpu": [ - "loong64" - ], + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/tsup/node_modules/@esbuild/linux-mips64el": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", - "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", - "cpu": [ - "mips64el" - ], + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "any-promise": "^1.0.0" } }, - "node_modules/tsup/node_modules/@esbuild/linux-ppc64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", - "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", - "cpu": [ - "ppc64" - ], + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, "engines": { - "node": ">=18" + "node": ">=0.8" } }, - "node_modules/tsup/node_modules/@esbuild/linux-riscv64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", - "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", - "cpu": [ - "riscv64" - ], + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=4" } }, - "node_modules/tsup/node_modules/@esbuild/linux-s390x": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", - "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", - "cpu": [ - "s390x" - ], + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "is-number": "^7.0.0" + }, "engines": { - "node": ">=18" + "node": ">=8.0" } }, - "node_modules/tsup/node_modules/@esbuild/linux-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", - "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", - "cpu": [ - "x64" - ], + "node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "punycode": "^2.1.0" } }, - "node_modules/tsup/node_modules/@esbuild/netbsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", - "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", - "cpu": [ - "x64" - ], + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" + "bin": { + "tree-kill": "cli.js" } }, - "node_modules/tsup/node_modules/@esbuild/openbsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", - "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", - "cpu": [ - "x64" - ], + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], "engines": { - "node": ">=18" + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" } }, - "node_modules/tsup/node_modules/@esbuild/sunos-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", - "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", - "cpu": [ - "x64" - ], + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } + "license": "Apache-2.0" }, - "node_modules/tsup/node_modules/@esbuild/win32-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", - "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", - "cpu": [ - "arm64" - ], + "node_modules/ts-jest": { + "version": "29.2.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.4.tgz", + "integrity": "sha512-3d6tgDyhCI29HlpwIq87sNuI+3Q6GLTTCeYRHCs7vDz+/3GCMwEtV9jezLyl4ZtnBgx00I7hm8PCP8cTksMGrw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "bs-logger": "0.x", + "ejs": "^3.1.10", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, "engines": { - "node": ">=18" + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } } }, - "node_modules/tsup/node_modules/@esbuild/win32-ia32": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", - "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", - "cpu": [ - "ia32" - ], + "node_modules/ts-jest/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, "engines": { - "node": ">=18" + "node": ">=10" } }, - "node_modules/tsup/node_modules/@esbuild/win32-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", - "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", - "cpu": [ - "x64" - ], + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "peer": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } } }, - "node_modules/tsup/node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "dev": true, - "license": "MIT" + "license": "0BSD" }, - "node_modules/tsup/node_modules/esbuild": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", - "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", + "node_modules/tsup": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.2.4.tgz", + "integrity": "sha512-akpCPePnBnC/CXgRrcy72ZSntgIEUa1jN0oJbbvpALWKNOz1B7aM+UVDWGRGIO/T/PZugAESWDJUAb5FD48o8Q==", "dev": true, - "hasInstallScript": true, "license": "MIT", + "dependencies": { + "bundle-require": "^5.0.0", + "cac": "^6.7.14", + "chokidar": "^3.6.0", + "consola": "^3.2.3", + "debug": "^4.3.5", + "esbuild": "^0.23.0", + "execa": "^5.1.1", + "globby": "^11.1.0", + "joycon": "^3.1.1", + "picocolors": "^1.0.1", + "postcss-load-config": "^6.0.1", + "resolve-from": "^5.0.0", + "rollup": "^4.19.0", + "source-map": "0.8.0-beta.0", + "sucrase": "^3.35.0", + "tree-kill": "^1.2.2" + }, "bin": { - "esbuild": "bin/esbuild" + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" }, "engines": { "node": ">=18" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.23.0", - "@esbuild/android-arm": "0.23.0", - "@esbuild/android-arm64": "0.23.0", - "@esbuild/android-x64": "0.23.0", - "@esbuild/darwin-arm64": "0.23.0", - "@esbuild/darwin-x64": "0.23.0", - "@esbuild/freebsd-arm64": "0.23.0", - "@esbuild/freebsd-x64": "0.23.0", - "@esbuild/linux-arm": "0.23.0", - "@esbuild/linux-arm64": "0.23.0", - "@esbuild/linux-ia32": "0.23.0", - "@esbuild/linux-loong64": "0.23.0", - "@esbuild/linux-mips64el": "0.23.0", - "@esbuild/linux-ppc64": "0.23.0", - "@esbuild/linux-riscv64": "0.23.0", - "@esbuild/linux-s390x": "0.23.0", - "@esbuild/linux-x64": "0.23.0", - "@esbuild/netbsd-x64": "0.23.0", - "@esbuild/openbsd-arm64": "0.23.0", - "@esbuild/openbsd-x64": "0.23.0", - "@esbuild/sunos-x64": "0.23.0", - "@esbuild/win32-arm64": "0.23.0", - "@esbuild/win32-ia32": "0.23.0", - "@esbuild/win32-x64": "0.23.0" + "peerDependencies": { + "@microsoft/api-extractor": "^7.36.0", + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } } }, + "node_modules/tsup/node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true, + "license": "MIT" + }, "node_modules/tsup/node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", diff --git a/package.json b/package.json index 689368f..fd0368e 100644 --- a/package.json +++ b/package.json @@ -26,10 +26,10 @@ "node": ">=18" }, "scripts": { - "start": "tsup src/index.ts --watch", - "build": "node ./scripts/build.js", - "build:browser": "tsup src/index.ts --dts --format esm,iife --sourcemap --env.NODE_ENV production --minify --dts-resolve", - "build:node": "tsup src/index.ts --dts --format cjs --sourcemap --env.NODE_ENV production --minify", + "build": "npm run build:node && npm run build:browser && npm run build:cleanup", + "build:browser": "tsup --format esm,iife --out-dir dist/browser --env.NODE_ENV production", + "build:node": "tsup --format cjs --out-dir dist/node --env.NODE_ENV production", + "build:cleanup": "rm -f dist/browser/index.d.mts dist/node/index.d.ts && mv dist/browser/index.d.ts dist/index.d.ts", "types-check": "tsc --noEmit", "test": "jest --forceExit --coverage --detectOpenHandles", "lint": "eslint ./src/**/*.ts ./test/**/*.spec.ts", diff --git a/scripts/build.js b/scripts/build.js deleted file mode 100644 index deb4850..0000000 --- a/scripts/build.js +++ /dev/null @@ -1,92 +0,0 @@ -// Credit: https://blog.unterholzer.dev/cross-compatible-typescript-libraries/ -const proc = require('child_process'); -const fs = require('fs'); -const path = require('path'); - -const moveFile = (from, to, filename) => { - from = from.split('/'); - to = to.split('/'); - - if (filename) { - from.push(filename); - to.push(filename); - } - - fs.renameSync(path.resolve(...from), path.resolve(...to)); -}; - -const removeTempDirs = () => { - try { - fs.rmSync(path.resolve('dist-node'), { recursive: true }); - } catch (error) {} - - try { - fs.rmSync(path.resolve('dist-browser'), { recursive: true }); - } catch (error) {} -}; - -// Remove all dirs initially -try { - fs.rmSync(path.resolve('dist'), { recursive: true }); -} catch (error) {} - -removeTempDirs(); - -console.log('Building browser version...'); - -// running browser build -// building automatically removes any existing 'dist' folder -proc.execSync('npm run build:browser'); - -// copying into temporary folder -// so it doesn't get overwritten by next build step -moveFile('dist', 'dist-browser'); - -console.log('Building node version...'); - -// running node build -// building automatically removes any existing 'dist' folder -proc.execSync('npm run build:node'); - -// create temporary folder 'dist-node' where we move our built node files -fs.mkdirSync(path.resolve('dist-node')); - -console.log('Creating common types...'); - -console.log('Handle node...'); - -// Ok, now it's going to be weird -// Let me explain... -// Each build (browser and node) contains its own typings -// but this does not make sense, as both typings are exactly the same -// that's why we are disposing one set of typings (node's typings) -// and only use the typings generated along with the browser build -// therefore a lot of weird copying and moving is done here...sorry... - -// moving all node files into folder 'dist-node' -// reason: we want to get rid of all typings -moveFile('dist', 'dist-node', 'index.js'); -moveFile('dist', 'dist-node', 'index.js.map'); - -// finally we delete the folder with all node-typings -fs.rmSync(path.resolve('dist'), { recursive: true }); -// now we can move 'dist-node' to 'dist/node' again -fs.mkdirSync(path.resolve('dist')); - -moveFile('dist-node', 'dist/node'); - -console.log('Handle browser...'); - -// for our browser version, we create a new folder -fs.mkdirSync(path.resolve('dist', 'browser')); - -// Move important files into 'dist/browser' folder -moveFile('dist-browser', 'dist/browser', 'index.mjs'); -moveFile('dist-browser', 'dist/browser', 'index.mjs.map'); -moveFile('dist-browser', 'dist/browser', 'index.global.js'); -moveFile('dist-browser', 'dist/browser', 'index.global.js.map'); -moveFile('dist-browser', 'dist', 'index.d.ts'); - -removeTempDirs(); - -console.log('Build finished!'); diff --git a/tsup.config.ts b/tsup.config.ts new file mode 100644 index 0000000..5ef3242 --- /dev/null +++ b/tsup.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + name: 'fetchff', + globalName: 'fetchff', + entry: ['src/index.ts'], + target: 'esnext', + dts: true, + clean: true, + sourcemap: true, + minify: true, + splitting: false, +}); From 18b99a3df258cc4a699c6b1b14e13dd36ff5ed0f Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 13 Sep 2024 00:40:03 +0200 Subject: [PATCH 05/18] fix: urls in endpoints should be required in TypeScript interface --- src/types/api-handler.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/types/api-handler.ts b/src/types/api-handler.ts index bce1140..0341501 100644 --- a/src/types/api-handler.ts +++ b/src/types/api-handler.ts @@ -68,9 +68,11 @@ type DefaultEndpoints = { [K in keyof EndpointsCfg]: EndpointDefaults; }; +type RequestConfigUrlRequired = Omit & { url: string }; + export type EndpointsConfig = Record< keyof EndpointsMethods | string, - RequestConfig + RequestConfigUrlRequired >; type EndpointsConfigPart = [ From 765ac3fe8010bf2d0ca19f242586fc2bc53c60a4 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 13 Sep 2024 00:40:28 +0200 Subject: [PATCH 06/18] fix: Set minimum target to es2017 --- tsup.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsup.config.ts b/tsup.config.ts index 5ef3242..5384ee5 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -4,7 +4,7 @@ export default defineConfig({ name: 'fetchff', globalName: 'fetchff', entry: ['src/index.ts'], - target: 'esnext', + target: 'es2017', dts: true, clean: true, sourcemap: true, From cd76b0154a4127b8ede459a5f955a0ed45d0f565 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 13 Sep 2024 02:03:49 +0200 Subject: [PATCH 07/18] chore: Remove old promise-any dev dependency & activate strict typings --- package-lock.json | 195 +++++++++++++++---------------- package.json | 9 +- src/api-handler.ts | 10 +- src/interceptor-manager.ts | 4 +- src/queue-manager.ts | 2 +- src/request-handler.ts | 44 ++++--- src/types/queue-manager.ts | 2 +- src/types/request-handler.ts | 4 +- src/utils.ts | 2 +- test/hash.spec.ts | 4 +- test/interceptor-manager.spec.ts | 35 ++++-- test/request-handler.spec.ts | 19 +-- test/utils.spec.ts | 2 +- tsconfig.json | 2 +- 14 files changed, 175 insertions(+), 159 deletions(-) diff --git a/package-lock.json b/package-lock.json index 61b169a..c02b6af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,20 +11,19 @@ "devDependencies": { "@size-limit/preset-small-lib": "11.1.4", "@types/jest": "29.5.12", - "eslint": "9.8.0", + "eslint": "9.10.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-prettier": "5.2.1", "fetch-mock": "11.0.0", "jest": "29.7.0", "prettier": "3.3.3", - "promise-any": "0.2.0", "rollup-plugin-bundle-imports": "1.5.1", "size-limit": "11.1.4", "ts-jest": "29.2.4", - "tslib": "2.6.3", + "tslib": "2.7.0", "tsup": "8.2.4", - "typescript": "5.5.4", - "typescript-eslint": "8.0.1" + "typescript": "5.6.2", + "typescript-eslint": "8.5.0" }, "engines": { "node": ">=18" @@ -726,9 +725,9 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", - "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -765,9 +764,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.8.0.tgz", - "integrity": "sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==", + "version": "9.10.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.10.0.tgz", + "integrity": "sha512-fuXtbiP5GWIn8Fz+LWoOMVf/Jxm+aajZYkhi6CuEm4SxymFM+eUWzbO9qXT+L0iCkL5+KGYMCSGxo686H19S1g==", "dev": true, "license": "MIT", "engines": { @@ -784,6 +783,19 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/plugin-kit": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.1.0.tgz", + "integrity": "sha512-autAXT203ixhqei9xt+qkYOvY8l6LAFIdT2UXc/RPNeUVfqRF1BV94GTJyVPFKT8nFM6MyVJhjLj9E8JWvf5zQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -1941,17 +1953,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.1.tgz", - "integrity": "sha512-5g3Y7GDFsJAnY4Yhvk8sZtFfV6YNF2caLzjrRPUBzewjPCaj0yokePB4LJSobyCzGMzjZZYFbwuzbfDHlimXbQ==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.5.0.tgz", + "integrity": "sha512-lHS5hvz33iUFQKuPFGheAB84LwcJ60G8vKnEhnfcK1l8kGVLro2SFYW6K0/tj8FUhRJ0VHyg1oAfg50QGbPPHw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.0.1", - "@typescript-eslint/type-utils": "8.0.1", - "@typescript-eslint/utils": "8.0.1", - "@typescript-eslint/visitor-keys": "8.0.1", + "@typescript-eslint/scope-manager": "8.5.0", + "@typescript-eslint/type-utils": "8.5.0", + "@typescript-eslint/utils": "8.5.0", + "@typescript-eslint/visitor-keys": "8.5.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1975,16 +1987,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.0.1.tgz", - "integrity": "sha512-5IgYJ9EO/12pOUwiBKFkpU7rS3IU21mtXzB81TNwq2xEybcmAZrE9qwDtsb5uQd9aVO9o0fdabFyAmKveXyujg==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.5.0.tgz", + "integrity": "sha512-gF77eNv0Xz2UJg/NbpWJ0kqAm35UMsvZf1GHj8D9MRFTj/V3tAciIWXfmPLsAAF/vUlpWPvUDyH1jjsr0cMVWw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.0.1", - "@typescript-eslint/types": "8.0.1", - "@typescript-eslint/typescript-estree": "8.0.1", - "@typescript-eslint/visitor-keys": "8.0.1", + "@typescript-eslint/scope-manager": "8.5.0", + "@typescript-eslint/types": "8.5.0", + "@typescript-eslint/typescript-estree": "8.5.0", + "@typescript-eslint/visitor-keys": "8.5.0", "debug": "^4.3.4" }, "engines": { @@ -2004,14 +2016,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.1.tgz", - "integrity": "sha512-NpixInP5dm7uukMiRyiHjRKkom5RIFA4dfiHvalanD2cF0CLUuQqxfg8PtEUo9yqJI2bBhF+pcSafqnG3UBnRQ==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.5.0.tgz", + "integrity": "sha512-06JOQ9Qgj33yvBEx6tpC8ecP9o860rsR22hWMEd12WcTRrfaFgHr2RB/CA/B+7BMhHkXT4chg2MyboGdFGawYg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.0.1", - "@typescript-eslint/visitor-keys": "8.0.1" + "@typescript-eslint/types": "8.5.0", + "@typescript-eslint/visitor-keys": "8.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2022,14 +2034,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.0.1.tgz", - "integrity": "sha512-+/UT25MWvXeDX9YaHv1IS6KI1fiuTto43WprE7pgSMswHbn1Jm9GEM4Txp+X74ifOWV8emu2AWcbLhpJAvD5Ng==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.5.0.tgz", + "integrity": "sha512-N1K8Ix+lUM+cIDhL2uekVn/ZD7TZW+9/rwz8DclQpcQ9rk4sIL5CAlBC0CugWKREmDjBzI/kQqU4wkg46jWLYA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.0.1", - "@typescript-eslint/utils": "8.0.1", + "@typescript-eslint/typescript-estree": "8.5.0", + "@typescript-eslint/utils": "8.5.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -2047,9 +2059,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.1.tgz", - "integrity": "sha512-PpqTVT3yCA/bIgJ12czBuE3iBlM3g4inRSC5J0QOdQFAn07TYrYEQBBKgXH1lQpglup+Zy6c1fxuwTk4MTNKIw==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.5.0.tgz", + "integrity": "sha512-qjkormnQS5wF9pjSi6q60bKUHH44j2APxfh9TQRXK8wbYVeDYYdYJGIROL87LGZZ2gz3Rbmjc736qyL8deVtdw==", "dev": true, "license": "MIT", "engines": { @@ -2061,16 +2073,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.1.tgz", - "integrity": "sha512-8V9hriRvZQXPWU3bbiUV4Epo7EvgM6RTs+sUmxp5G//dBGy402S7Fx0W0QkB2fb4obCF8SInoUzvTYtc3bkb5w==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.5.0.tgz", + "integrity": "sha512-vEG2Sf9P8BPQ+d0pxdfndw3xIXaoSjliG0/Ejk7UggByZPKXmJmw3GW5jV2gHNQNawBUyfahoSiCFVov0Ruf7Q==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.0.1", - "@typescript-eslint/visitor-keys": "8.0.1", + "@typescript-eslint/types": "8.5.0", + "@typescript-eslint/visitor-keys": "8.5.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", @@ -2099,27 +2111,6 @@ "balanced-match": "^1.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -2150,16 +2141,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.1.tgz", - "integrity": "sha512-CBFR0G0sCt0+fzfnKaciu9IBsKvEKYwN9UZ+eeogK1fYHg4Qxk1yf/wLQkLXlq8wbU2dFlgAesxt8Gi76E8RTA==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.5.0.tgz", + "integrity": "sha512-6yyGYVL0e+VzGYp60wvkBHiqDWOpT63pdMV2CVG4LVDd5uR6q1qQN/7LafBZtAtNIn/mqXjsSeS5ggv/P0iECw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.0.1", - "@typescript-eslint/types": "8.0.1", - "@typescript-eslint/typescript-estree": "8.0.1" + "@typescript-eslint/scope-manager": "8.5.0", + "@typescript-eslint/types": "8.5.0", + "@typescript-eslint/typescript-estree": "8.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2173,13 +2164,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.1.tgz", - "integrity": "sha512-W5E+o0UfUcK5EgchLZsyVWqARmsM7v54/qEq6PY3YI5arkgmCzHiuk0zKSJJbm71V0xdRna4BGomkCTXz2/LkQ==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.5.0.tgz", + "integrity": "sha512-yTPqMnbAZJNy2Xq2XU8AdtOW9tJIr+UQb64aXB9f3B1498Zx9JorVgFJcZpEc9UBuCCrdzKID2RGAMkYcDtZOw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.0.1", + "@typescript-eslint/types": "8.5.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -3133,17 +3124,18 @@ } }, "node_modules/eslint": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.8.0.tgz", - "integrity": "sha512-K8qnZ/QJzT2dLKdZJVX6W4XOwBzutMYmt0lqUS+JdXgd+HTYFlonFgkJ8s44d/zMPPCnOOk0kMWCApCPhiOy9A==", + "version": "9.10.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.10.0.tgz", + "integrity": "sha512-Y4D0IgtBZfOcOUAIQTSXBKoNGfY0REGqHJG6+Q81vNippW5YlKjHFj4soMxamKK1NXHUWuBZTLdU3Km+L/pcHw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.17.1", + "@eslint/config-array": "^0.18.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.8.0", + "@eslint/js": "9.10.0", + "@eslint/plugin-kit": "^0.1.0", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", @@ -3166,7 +3158,6 @@ "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", "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", @@ -3182,6 +3173,14 @@ }, "funding": { "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-config-prettier": { @@ -5670,16 +5669,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/promise-any": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/promise-any/-/promise-any-0.2.0.tgz", - "integrity": "sha512-w+vpHI6XKtg/b+2vYhR2WwUkhLYEjJPpdFyJjDd3UUnYSqX0XvPzfr/tK02qOOwV5i4QwkvIvx2h5tIIvitJvQ==", - "dev": true, - "license": "Unlicense", - "engines": { - "node": ">=5.0.0" - } - }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -6511,9 +6500,9 @@ } }, "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", "dev": true, "license": "0BSD" }, @@ -6680,9 +6669,9 @@ } }, "node_modules/typescript": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -6694,15 +6683,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.0.1.tgz", - "integrity": "sha512-V3Y+MdfhawxEjE16dWpb7/IOgeXnLwAEEkS7v8oDqNcR1oYlqWhGH/iHqHdKVdpWme1VPZ0SoywXAkCqawj2eQ==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.5.0.tgz", + "integrity": "sha512-uD+XxEoSIvqtm4KE97etm32Tn5MfaZWgWfMMREStLxR6JzvHkc2Tkj7zhTEK5XmtpTmKHNnG8Sot6qDfhHtR1Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.0.1", - "@typescript-eslint/parser": "8.0.1", - "@typescript-eslint/utils": "8.0.1" + "@typescript-eslint/eslint-plugin": "8.5.0", + "@typescript-eslint/parser": "8.5.0", + "@typescript-eslint/utils": "8.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" diff --git a/package.json b/package.json index fd0368e..97edecd 100644 --- a/package.json +++ b/package.json @@ -57,19 +57,18 @@ "devDependencies": { "@size-limit/preset-small-lib": "11.1.4", "@types/jest": "29.5.12", - "eslint": "9.8.0", + "eslint": "9.10.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-prettier": "5.2.1", "fetch-mock": "11.0.0", "jest": "29.7.0", "prettier": "3.3.3", - "promise-any": "0.2.0", "rollup-plugin-bundle-imports": "1.5.1", "size-limit": "11.1.4", "ts-jest": "29.2.4", - "tslib": "2.6.3", + "tslib": "2.7.0", "tsup": "8.2.4", - "typescript": "5.5.4", - "typescript-eslint": "8.0.1" + "typescript": "5.6.2", + "typescript-eslint": "8.5.0" } } diff --git a/src/api-handler.ts b/src/api-handler.ts index 46391d0..0339b4a 100644 --- a/src/api-handler.ts +++ b/src/api-handler.ts @@ -130,13 +130,15 @@ function createApiFetcher< * * @param {*} prop Caller */ - function get(prop: string | symbol) { + function get(prop: string) { if (prop in apiHandler) { - return apiHandler[prop]; + return apiHandler[ + prop as unknown as keyof ApiHandlerMethods + ]; } // Prevent handler from triggering non-existent endpoints - if (!endpoints[prop as string]) { + if (!endpoints[prop]) { return handleNonImplemented.bind(null, prop); } @@ -152,7 +154,7 @@ function createApiFetcher< }; return new Proxy(apiHandler, { - get: (_target, prop) => get(prop), + get: (_target, prop: string) => get(prop), }) as ApiHandlerReturnType; } diff --git a/src/interceptor-manager.ts b/src/interceptor-manager.ts index c645935..230ae93 100644 --- a/src/interceptor-manager.ts +++ b/src/interceptor-manager.ts @@ -12,7 +12,7 @@ import type { */ export async function interceptRequest( config: RequestHandlerConfig, - interceptors: RequestInterceptor | RequestInterceptor[], + interceptors?: RequestInterceptor | RequestInterceptor[], ): Promise { if (!interceptors) { return config; @@ -39,7 +39,7 @@ export async function interceptRequest( */ export async function interceptResponse( response: FetchResponse, - interceptors: ResponseInterceptor | ResponseInterceptor[], + interceptors?: ResponseInterceptor | ResponseInterceptor[], ): Promise> { if (!interceptors) { return response; diff --git a/src/queue-manager.ts b/src/queue-manager.ts index 0e7a479..8a87697 100644 --- a/src/queue-manager.ts +++ b/src/queue-manager.ts @@ -22,7 +22,7 @@ export async function withLock( key: object, fn: () => Promise, ): Promise { - let release: () => void; + let release: () => void = () => {}; const lock = new Promise((resolve) => (release = resolve)); // Wait for existing locks to be released diff --git a/src/request-handler.ts b/src/request-handler.ts index 68c9ed2..f91ed3c 100644 --- a/src/request-handler.ts +++ b/src/request-handler.ts @@ -68,11 +68,11 @@ export class RequestHandler { public constructor({ fetcher = null, - timeout = null, - strategy = null, - flattenResponse = null, defaultResponse = {}, logger = null, + strategy, + flattenResponse, + timeout, ...config }: RequestHandlerConfig) { this.fetcher = fetcher; @@ -130,7 +130,7 @@ export class RequestHandler { const dynamicUrl = replaceUrlPathParams( url, - config.urlPathParams || this.config.urlPathParams, + config.urlPathParams || this.config.urlPathParams || null, ); // The explicitly passed "params" @@ -249,7 +249,7 @@ export class RequestHandler { */ protected async outputErrorResponse( error: ResponseError, - response: FetchResponse, + response: FetchResponse | null, requestConfig: RequestConfig, ): Promise { const isRequestCancelled = this.isRequestCancelled(error); @@ -305,9 +305,9 @@ export class RequestHandler { public async request( url: string, data: QueryParamsOrBody = null, - config: RequestConfig = null, + config: RequestConfig | null = null, ): Promise> { - let response: FetchResponse = null; + let response: FetchResponse | null = null; const _config = config || {}; const _requestConfig = this.buildConfig(url, data, _config); @@ -335,10 +335,10 @@ export class RequestHandler { } = { ...this.retry, ...(_requestConfig?.retry || {}), - }; + } as Required; let attempt = 0; - let waitTime = delay; + let waitTime: number = delay; while (attempt <= retries) { try { @@ -375,7 +375,7 @@ export class RequestHandler { )) as FetchResponse; } else { response = (await globalThis.fetch( - requestConfig.url, + requestConfig.url as string, requestConfig as RequestInit, )) as FetchResponse; @@ -401,11 +401,13 @@ export class RequestHandler { return this.outputResponse(response, requestConfig) as ResponseData & FetchResponse; - } catch (error) { + } catch (err) { + const error = err as ResponseError; + if ( attempt === retries || !(await shouldRetry(error, attempt)) || - !retryOn?.includes(error?.response?.status || error?.status) + !retryOn?.includes(error?.response?.status || null) ) { this.processError(error, _requestConfig); @@ -546,9 +548,9 @@ export class RequestHandler { * @returns {ResponseData | FetchResponse} Response data */ protected outputResponse( - response: FetchResponse, + response: FetchResponse | null, requestConfig: RequestConfig, - error = null, + error: ResponseError | null = null, ): ResponseData | FetchResponse { const defaultResponse = typeof requestConfig.defaultResponse !== 'undefined' @@ -571,10 +573,16 @@ export class RequestHandler { } // Clean up the error object - if (error !== null) { - delete error?.response; - delete error?.request; - delete error?.config; + if (error?.response) { + delete error.response; + } + + if (error?.request) { + delete error.request; + } + + if (error?.config) { + delete (error as any).config; } let data = response?.data; diff --git a/src/types/queue-manager.ts b/src/types/queue-manager.ts index b6107e4..fe4535f 100644 --- a/src/types/queue-manager.ts +++ b/src/types/queue-manager.ts @@ -4,6 +4,6 @@ export type RequestsQueue = WeakMap; export interface QueueItem { controller: AbortController; - timeoutId?: NodeJS.Timeout; + timeoutId?: NodeJS.Timeout | null; timestamp: number; } diff --git a/src/types/request-handler.ts b/src/types/request-handler.ts index ed45ba4..0a36447 100644 --- a/src/types/request-handler.ts +++ b/src/types/request-handler.ts @@ -45,7 +45,7 @@ export interface HeadersObject { export interface ExtendedResponse extends Omit { data: T; - error: ResponseError; + error: ResponseError | null; headers: HeadersObject & HeadersInit; config: ExtendedRequestConfig; request?: ExtendedRequestConfig; @@ -105,7 +105,7 @@ export interface RetryOptions { * 504, // Gateway Timeout * ] */ - retryOn: number[]; + retryOn: (number | null)[]; /** * A function to determine whether to retry based on the error and attempt number. diff --git a/src/utils.ts b/src/utils.ts index c49802a..762910c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -25,7 +25,7 @@ export function appendQueryParams(url: string, params: QueryParams): string { } // This is exact copy of what JQ used to do. It works much better than URLSearchParams - const s = []; + const s: string[] = []; const add = function (k: string, v: any) { v = typeof v === 'function' ? v() : v; v = v === null ? '' : v === undefined ? '' : v; diff --git a/test/hash.spec.ts b/test/hash.spec.ts index 28d845c..3d5f613 100644 --- a/test/hash.spec.ts +++ b/test/hash.spec.ts @@ -80,8 +80,8 @@ describe('hashFromConfig function', () => { }); describe('hashFromConfig with cache', () => { - let hashCacheGetSpy; - let hashCacheSetSpy; + let hashCacheGetSpy: unknown; + let hashCacheSetSpy: unknown; beforeEach(() => { // Reset spies before each test diff --git a/test/interceptor-manager.spec.ts b/test/interceptor-manager.spec.ts index 5465597..5c3ad8a 100644 --- a/test/interceptor-manager.spec.ts +++ b/test/interceptor-manager.spec.ts @@ -1,12 +1,23 @@ import { ExtendedResponse } from '../src'; +import type { + FetchResponse, + RequestHandlerConfig, +} from '../src/types/request-handler'; import { interceptRequest, interceptResponse, } from '../src/interceptor-manager'; +import type { + RequestInterceptor, + ResponseInterceptor, +} from '../src/types/interceptor-manager'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type ResponseData = any; describe('Interceptor Functions', () => { - let requestInterceptors = []; - let responseInterceptors = []; + let requestInterceptors: RequestInterceptor[] = []; + let responseInterceptors: ResponseInterceptor[] = []; beforeEach(() => { requestInterceptors = []; @@ -15,12 +26,12 @@ describe('Interceptor Functions', () => { it('should apply request interceptors in order', async () => { // Define request interceptors - const requestInterceptor1 = async (config: RequestInit) => { + const requestInterceptor1 = async (config: RequestHandlerConfig) => { config.headers = { ...config.headers, Authorization: 'Bearer token' }; return config; }; - const requestInterceptor2 = async (config: RequestInit) => { + const requestInterceptor2 = async (config: RequestHandlerConfig) => { config.headers = { ...config.headers, 'Custom-Header': 'HeaderValue' }; return config; }; @@ -48,18 +59,22 @@ describe('Interceptor Functions', () => { it('should apply response interceptors in order', async () => { // Define response interceptors - const responseInterceptor1 = async (response: Response) => { + const responseInterceptor1 = async ( + response: FetchResponse, + ) => { const data = await response.json(); return new Response(JSON.stringify({ ...data, modified: true }), { status: response.status, - }); + }) as FetchResponse; }; - const responseInterceptor2 = async (response: Response) => { + const responseInterceptor2 = async ( + response: FetchResponse, + ) => { const data = await response.json(); return new Response(JSON.stringify({ ...data, furtherModified: true }), { status: response.status, - }); + }) as FetchResponse; }; // Register response interceptors directly @@ -103,7 +118,9 @@ describe('Interceptor Functions', () => { it('should handle response errors', async () => { // Define a response interceptor that throws an error on non-OK response - const responseInterceptor = async (response: Response) => { + const responseInterceptor = async ( + response: FetchResponse, + ) => { if (!response.ok) { throw new Error('Response Error'); } diff --git a/test/request-handler.spec.ts b/test/request-handler.spec.ts index 3fbc434..061e74c 100644 --- a/test/request-handler.spec.ts +++ b/test/request-handler.spec.ts @@ -1,5 +1,4 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import PromiseAny from 'promise-any'; import { RequestHandler } from '../src/request-handler'; import fetchMock from 'fetch-mock'; import { fetchf, FetchResponse } from '../src'; @@ -54,13 +53,13 @@ describe('Request Handler', () => { }); describe('buildConfig() with native fetch()', () => { - let requestHandler: RequestHandler = null; + let requestHandler: RequestHandler | null = null; beforeAll(() => { requestHandler = new RequestHandler({}); }); - const buildConfig = (method, url, data, config) => + const buildConfig = (method: string, url: string, data: any, config: any) => (requestHandler as any).buildConfig(url, data, { ...config, method, @@ -343,7 +342,7 @@ describe('Request Handler', () => { expect(typeof request.then).toBe('function'); - const response = await PromiseAny([request, timeout]); + const response = await Promise.any([request, timeout]); expect(response).toBe('timeout'); }); @@ -493,7 +492,7 @@ describe('Request Handler', () => { typeof delayInvocation >; - mockDelayInvocation.mockResolvedValue(undefined); + mockDelayInvocation.mockResolvedValue(false); try { await requestHandler.request('/endpoint'); @@ -572,7 +571,7 @@ describe('Request Handler', () => { typeof delayInvocation >; - mockDelayInvocation.mockResolvedValue(undefined); + mockDelayInvocation.mockResolvedValue(false); try { await requestHandler.request('/endpoint'); @@ -814,7 +813,7 @@ describe('Request Handler', () => { expect(typeof request.then).toBe('function'); - const response = await PromiseAny([request, timeout]); + const response = await Promise.any([request, timeout]); expect(response).toBe('timeout'); }); @@ -1056,11 +1055,13 @@ describe('Request Handler', () => { // Test when headers is null or undefined it('should return an empty object if headers are null or undefined', () => { - const response = { headers: null } as FetchResponse; + const response = { headers: null } as unknown as FetchResponse; const result = requestHandler.processHeaders(response); expect(result).toEqual({}); - const responseUndefined = { headers: undefined } as FetchResponse; + const responseUndefined = { + headers: undefined, + } as unknown as FetchResponse; const resultUndefined = requestHandler.processHeaders(responseUndefined); expect(resultUndefined).toEqual({}); }); diff --git a/test/utils.spec.ts b/test/utils.spec.ts index c1ef9e4..6aa05b2 100644 --- a/test/utils.spec.ts +++ b/test/utils.spec.ts @@ -331,7 +331,7 @@ describe('Utils', () => { it('should return the same url if empty array is propagated', () => { const url = 'https://api.example.com/resource'; - const params = []; + const params: [] = []; const result = appendQueryParams(url, params); expect(result).toBe(url); diff --git a/tsconfig.json b/tsconfig.json index b455261..9f851c1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,7 +8,7 @@ "declaration": true, "sourceMap": true, "rootDir": "./", - "strict": false, + "strict": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "noUnusedLocals": true, From cb2f167f323e56cf5e0ad0c7bf6a2c1a3a8c047e Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 13 Sep 2024 04:30:02 +0200 Subject: [PATCH 08/18] feat: Reduce bundle size, extract parser & utils, and fix typings --- src/api-handler.ts | 5 +- src/const.ts | 2 + src/request-handler.ts | 275 ++++++++++------------------------- src/response-parser.ts | 59 ++++++++ src/types/request-handler.ts | 6 +- src/utils.ts | 75 +++++++++- test/request-handler.spec.ts | 184 +---------------------- test/request-parser.spec.ts | 122 ++++++++++++++++ test/utils.spec.ts | 43 ++++++ 9 files changed, 383 insertions(+), 388 deletions(-) create mode 100644 src/const.ts create mode 100644 src/response-parser.ts create mode 100644 test/request-parser.spec.ts diff --git a/src/api-handler.ts b/src/api-handler.ts index 0339b4a..68ebb0f 100644 --- a/src/api-handler.ts +++ b/src/api-handler.ts @@ -110,13 +110,12 @@ function createApiFetcher< ): Promise> { // Use global per-endpoint settings const endpointConfig = endpoints[endpointName as string]; - const endpointSettings = { ...endpointConfig }; const responseData = await requestHandler.request( - endpointSettings.url, + endpointConfig.url, data, { - ...endpointSettings, + ...(endpointConfig || {}), ...requestConfig, urlPathParams, }, diff --git a/src/const.ts b/src/const.ts new file mode 100644 index 0000000..0eab220 --- /dev/null +++ b/src/const.ts @@ -0,0 +1,2 @@ +export const APPLICATION_JSON = 'application/json'; +export const CONTENT_TYPE = 'Content-Type'; diff --git a/src/request-handler.ts b/src/request-handler.ts index f91ed3c..b89d194 100644 --- a/src/request-handler.ts +++ b/src/request-handler.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import type { - ErrorHandlingStrategy, RequestHandlerConfig, RequestConfig, FetcherInstance, @@ -8,7 +7,6 @@ import type { RetryOptions, FetchResponse, ResponseError, - HeadersObject, } from './types/request-handler'; import type { APIResponse, @@ -23,10 +21,13 @@ import { isJSONSerializable, replaceUrlPathParams, delayInvocation, + flattenData, + processHeaders, + deleteProperty, } from './utils'; import { addRequest, removeRequest } from './queue-manager'; - -const APPLICATION_JSON = 'application/json'; +import { APPLICATION_JSON, CONTENT_TYPE } from './const'; +import { parseResponseData } from './response-parser'; /** * Generic Request Handler @@ -35,70 +36,50 @@ const APPLICATION_JSON = 'application/json'; */ export class RequestHandler { public requestInstance: FetcherInstance; - public baseURL: string = ''; - public timeout: number = 30000; - public strategy: ErrorHandlingStrategy = 'reject'; - public method: Method | string = 'get'; - public flattenResponse: boolean = false; - public defaultResponse: any = null; - protected fetcher: FetcherInstance; - protected logger: any; - protected retry: RetryOptions = { - retries: 0, - delay: 1000, - maxDelay: 30000, - resetTimeout: true, - backoff: 1.5, - - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status - retryOn: [ - 408, // Request Timeout - 409, // Conflict - 425, // Too Early - 429, // Too Many Requests - 500, // Internal Server Error - 502, // Bad Gateway - 503, // Service Unavailable - 504, // Gateway Timeout - ], - - shouldRetry: async () => true, - }; public config: RequestHandlerConfig = {}; - public constructor({ - fetcher = null, - defaultResponse = {}, - logger = null, - strategy, - flattenResponse, - timeout, - ...config - }: RequestHandlerConfig) { - this.fetcher = fetcher; - this.timeout = - timeout !== null && timeout !== undefined ? timeout : this.timeout; - this.strategy = strategy || this.strategy; - this.flattenResponse = flattenResponse || this.flattenResponse; - this.defaultResponse = defaultResponse; - this.logger = logger || null; - this.baseURL = config.baseURL || config.apiUrl || ''; - this.method = config.method || this.method; + public constructor(config: RequestHandlerConfig) { this.config = { + method: 'GET', + strategy: 'reject', + timeout: 30000, rejectCancelled: false, dedupeTime: 1000, + withCredentials: false, + flattenResponse: false, + defaultResponse: null, + logger: null, + fetcher: null, + baseURL: config.apiUrl || '', + retry: { + retries: 0, + delay: 1000, + maxDelay: 30000, + resetTimeout: true, + backoff: 1.5, + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status + retryOn: [ + 408, // Request Timeout + 409, // Conflict + 425, // Too Early + 429, // Too Many Requests + 500, // Internal Server Error + 502, // Bad Gateway + 503, // Service Unavailable + 504, // Gateway Timeout + ], + + shouldRetry: async () => true, + }, ...config, }; - this.retry = { - ...this.retry, - ...(config.retry || {}), - }; this.requestInstance = this.isCustomFetcher() - ? (fetcher as any).create({ + ? (this.config.fetcher as any).create({ ...config, - baseURL: this.baseURL, - timeout: this.timeout, + baseURL: this.config.baseURL, + timeout: this.config.timeout, }) : null; } @@ -125,7 +106,9 @@ export class RequestHandler { data: QueryParamsOrBody, config: RequestConfig, ): RequestConfig { - const method = (config.method || this.method).toUpperCase() as Method; + const method = ( + config.method || (this.config.method as string) + ).toUpperCase() as Method; const isGetAlikeMethod = method === 'GET' || method === 'HEAD'; const dynamicUrl = replaceUrlPathParams( @@ -167,20 +150,24 @@ export class RequestHandler { } // Native fetch - const credentials = - config.withCredentials || this.config.withCredentials - ? 'include' - : config.credentials; + const isWithCredentials = + typeof config.withCredentials !== 'undefined' + ? config.withCredentials + : this.config.withCredentials; - delete config.data; - delete config.withCredentials; + const credentials = isWithCredentials + ? 'include' + : config.credentials || undefined; + + deleteProperty(config, 'data'); + deleteProperty(config, 'withCredentials'); const urlPath = explicitParams || shouldTreatDataAsParams ? appendQueryParams(dynamicUrl, explicitParams || (data as QueryParams)) : dynamicUrl; const isFullUrl = urlPath.includes('://'); - const baseURL = isFullUrl ? '' : config.baseURL || this.baseURL; + const baseURL = isFullUrl ? '' : config.baseURL || this.config.baseURL; // Automatically stringify request body, if possible and when not dealing with strings if ( @@ -203,8 +190,9 @@ export class RequestHandler { // Add sensible defaults headers: { Accept: APPLICATION_JSON + ', text/plain, */*', - 'Content-Type': APPLICATION_JSON + ';charset=utf-8', - ...(config.headers || this.config.headers || {}), + [CONTENT_TYPE]: APPLICATION_JSON + ';charset=utf-8', + ...(this.config.headers || {}), + ...(config.headers || {}), }, }; } @@ -224,8 +212,8 @@ export class RequestHandler { return; } - if (this.logger?.warn) { - this.logger.warn('API ERROR', error); + if (this.config.logger?.warn) { + this.config.logger.warn('API ERROR', error); } // Invoke per request "onError" interceptor @@ -253,7 +241,8 @@ export class RequestHandler { requestConfig: RequestConfig, ): Promise { const isRequestCancelled = this.isRequestCancelled(error); - const errorHandlingStrategy = requestConfig.strategy || this.strategy; + const errorHandlingStrategy = + requestConfig.strategy || this.config.strategy; const rejectCancelled = typeof requestConfig.rejectCancelled !== 'undefined' ? requestConfig.rejectCancelled @@ -290,7 +279,7 @@ export class RequestHandler { * @returns {boolean} True if it's a custom fetcher */ protected isCustomFetcher(): boolean { - return this.fetcher !== null; + return this.config.fetcher !== null; } /** @@ -314,7 +303,7 @@ export class RequestHandler { const timeout = typeof _requestConfig.timeout !== 'undefined' ? _requestConfig.timeout - : this.timeout; + : (this.config.timeout as number); const isCancellable = typeof _requestConfig.cancellable !== 'undefined' ? _requestConfig.cancellable @@ -333,7 +322,7 @@ export class RequestHandler { maxDelay, resetTimeout, } = { - ...this.retry, + ...this.config.retry, ...(_requestConfig?.retry || {}), } as Required; @@ -374,14 +363,14 @@ export class RequestHandler { requestConfig, )) as FetchResponse; } else { - response = (await globalThis.fetch( + response = (await fetch( requestConfig.url as string, requestConfig as RequestInit, )) as FetchResponse; // Add more information to response object response.config = requestConfig; - response.data = await this.parseData(response); + response.data = await parseResponseData(response); // Check if the response status is not outside the range 200-299 and if so, output error if (!response.ok) { @@ -403,11 +392,12 @@ export class RequestHandler { FetchResponse; } catch (err) { const error = err as ResponseError; + const status = error?.response?.status || (error as any)?.status || 0; if ( attempt === retries || !(await shouldRetry(error, attempt)) || - !retryOn?.includes(error?.response?.status || null) + !retryOn?.includes(status) ) { this.processError(error, _requestConfig); @@ -416,8 +406,8 @@ export class RequestHandler { return this.outputErrorResponse(error, response, _requestConfig); } - if (this.logger?.warn) { - this.logger.warn( + if (this.config.logger?.warn) { + this.config.logger.warn( `Attempt ${attempt + 1} failed. Retrying in ${waitTime}ms...`, ); } @@ -434,111 +424,6 @@ export class RequestHandler { FetchResponse; } - /** - * Parses the response data based on the Content-Type header. - * - * @param response - The Response object to parse. - * @returns A Promise that resolves to the parsed data. - */ - public async parseData( - response: FetchResponse, - ): Promise { - // Bail early when body is empty - if (!response?.body) { - return null; - } - - const contentType = String( - (response as Response).headers?.get('Content-Type') || '', - ).split(';')[0]; // Correctly handle charset - - let data; - - try { - if ( - contentType.includes(APPLICATION_JSON) || - contentType.includes('+json') - ) { - data = await response.json(); // Parse JSON response - } else if (contentType.includes('multipart/form-data')) { - data = await response.formData(); // Parse as FormData - } else if (contentType.includes('application/octet-stream')) { - data = await response.blob(); // Parse as blob - } else if (contentType.includes('application/x-www-form-urlencoded')) { - data = await response.formData(); // Handle URL-encoded forms - } else if (contentType.includes('text/')) { - data = await response.text(); // Parse as text - } else { - try { - const responseClone = response.clone(); - - // Handle edge case of no content type being provided... We assume JSON here. - data = await responseClone.json(); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - } catch (_e) { - // Handle streams - data = await response.text(); - } - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - } catch (_error) { - // Parsing failed, fallback to null - data = null; - } - - return data; - } - - public processHeaders( - response: FetchResponse, - ): HeadersObject { - const headers = response.headers; - - if (!headers) { - return {}; - } - - const headersObject: HeadersObject = {}; - - // Handle Headers object with entries() method - if (headers instanceof Headers) { - headers.forEach((value, key) => { - headersObject[key] = value; - }); - } else if (typeof headers === 'object' && headers !== null) { - // Handle plain object - for (const [key, value] of Object.entries(headers)) { - // Normalize keys to lowercase as per RFC 2616 4.2 - // https://datatracker.ietf.org/doc/html/rfc2616#section-4.2 - headersObject[key.toLowerCase()] = value; - } - } - - return headersObject; - } - - /** - * Recursively flattens the data object if it meets specific criteria. - * - * The method checks if the provided `data` is an object with exactly one property named `data`. - * If so, it recursively flattens the `data` property. Otherwise, it returns the `data` as-is. - * - * @param {any} data - The data to be flattened. Can be of any type, including objects, arrays, or primitives. - * @returns {any} - The flattened data if the criteria are met; otherwise, the original `data`. - */ - protected flattenData(data: any): any { - if ( - data && - typeof data === 'object' && - typeof data.data !== 'undefined' && - Object.keys(data).length === 1 - ) { - return this.flattenData(data.data); - } - - return data; - } - /** * Output response * @@ -555,11 +440,11 @@ export class RequestHandler { const defaultResponse = typeof requestConfig.defaultResponse !== 'undefined' ? requestConfig.defaultResponse - : this.defaultResponse; + : this.config.defaultResponse; const flattenResponse = typeof requestConfig.flattenResponse !== 'undefined' ? requestConfig.flattenResponse - : this.flattenResponse; + : this.config.flattenResponse; if (!response) { return flattenResponse @@ -573,17 +458,9 @@ export class RequestHandler { } // Clean up the error object - if (error?.response) { - delete error.response; - } - - if (error?.request) { - delete error.request; - } - - if (error?.config) { - delete (error as any).config; - } + deleteProperty(error, 'response'); + deleteProperty(error, 'request'); + deleteProperty(error, 'config'); let data = response?.data; @@ -598,7 +475,7 @@ export class RequestHandler { // Return flattened response immediately if (flattenResponse) { - return this.flattenData(data); + return flattenData(data); } const isCustomFetcher = this.isCustomFetcher(); @@ -627,7 +504,7 @@ export class RequestHandler { // Extend with extra information error, data, - headers: this.processHeaders(response), + headers: processHeaders(response.headers), config: requestConfig, }; } diff --git a/src/response-parser.ts b/src/response-parser.ts new file mode 100644 index 0000000..4d7694d --- /dev/null +++ b/src/response-parser.ts @@ -0,0 +1,59 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { APPLICATION_JSON, CONTENT_TYPE } from './const'; +import type { APIResponse } from './types/api-handler'; +import type { FetchResponse } from './types/request-handler'; + +/** + * Parses the response data based on the Content-Type header. + * + * @param response - The Response object to parse. + * @returns A Promise that resolves to the parsed data. + */ +export async function parseResponseData( + response: FetchResponse, +): Promise { + // Bail early when body is empty + if (!response?.body) { + return null; + } + + const contentType = String( + (response as Response).headers?.get(CONTENT_TYPE) || '', + ).split(';')[0]; // Correctly handle charset + + let data; + + try { + if ( + contentType.includes(APPLICATION_JSON) || + contentType.includes('+json') + ) { + data = await response.json(); // Parse JSON response + } else if (contentType.includes('multipart/form-data')) { + data = await response.formData(); // Parse as FormData + } else if (contentType.includes('application/octet-stream')) { + data = await response.blob(); // Parse as blob + } else if (contentType.includes('application/x-www-form-urlencoded')) { + data = await response.formData(); // Handle URL-encoded forms + } else if (contentType.includes('text/')) { + data = await response.text(); // Parse as text + } else { + try { + const responseClone = response.clone(); + + // Handle edge case of no content type being provided... We assume JSON here. + data = await responseClone.json(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (_e) { + // Handle streams + data = await response.text(); + } + } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (_error) { + // Parsing failed, fallback to null + data = null; + } + + return data; +} diff --git a/src/types/request-handler.ts b/src/types/request-handler.ts index 0a36447..38d7db7 100644 --- a/src/types/request-handler.ts +++ b/src/types/request-handler.ts @@ -105,7 +105,7 @@ export interface RetryOptions { * 504, // Gateway Timeout * ] */ - retryOn: (number | null)[]; + retryOn?: number[]; /** * A function to determine whether to retry based on the error and attempt number. @@ -135,7 +135,7 @@ interface ExtendedRequestConfig extends Omit { /** * A default response to return if the request fails and the strategy is set to `'defaultResponse'`. */ - defaultResponse?: unknown; + defaultResponse?: any; /** * If `true`, flattens the response object, extracting the data directly instead of keeping it nested. @@ -240,7 +240,7 @@ interface ExtendedRequestConfig extends Omit { interface BaseRequestHandlerConfig extends RequestConfig { fetcher?: FetcherInstance; apiUrl?: string; - logger?: unknown; + logger?: any; } export type RequestConfig = ExtendedRequestConfig; diff --git a/src/utils.ts b/src/utils.ts index 762910c..3f8875a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { QueryParams, UrlPathParams } from './types'; +import type { HeadersObject, QueryParams, UrlPathParams } from './types'; /** * Appends query parameters to a given URL. @@ -161,3 +161,76 @@ export async function delayInvocation(ms: number): Promise { }, ms), ); } + +/** + * Recursively flattens the data object if it meets specific criteria. + * + * The method checks if the provided `data` is an object with exactly one property named `data`. + * If so, it recursively flattens the `data` property. Otherwise, it returns the `data` as-is. + * + * @param {any} data - The data to be flattened. Can be of any type, including objects, arrays, or primitives. + * @returns {any} - The flattened data if the criteria are met; otherwise, the original `data`. + */ +export function flattenData(data: any): any { + if ( + data && + typeof data === 'object' && + typeof data.data !== 'undefined' && + Object.keys(data).length === 1 + ) { + return flattenData(data.data); + } + + return data; +} + +/** + * Processes headers and returns them as a normalized object. + * + * Handles both `Headers` instances and plain objects. Normalizes header keys to lowercase + * as per RFC 2616 section 4.2. + * + * @param headers - The headers to process. Can be an instance of `Headers`, a plain object, + * or `null`. If `null`, an empty object is returned. + * @returns {HeadersObject} - A normalized headers object with lowercase keys. + */ +export function processHeaders( + headers?: (HeadersObject & HeadersInit) | null | Headers, +): HeadersObject { + if (!headers) { + return {}; + } + + const headersObject: HeadersObject = {}; + + // Handle Headers object with entries() method + if (headers instanceof Headers) { + headers.forEach((value, key) => { + headersObject[key] = value; + }); + } else if (typeof headers === 'object' && headers !== null) { + // Handle plain object + for (const [key, value] of Object.entries(headers)) { + // Normalize keys to lowercase as per RFC 2616 4.2 + // https://datatracker.ietf.org/doc/html/rfc2616#section-4.2 + headersObject[key.toLowerCase()] = value; + } + } + + return headersObject; +} + +/** + * Deletes a property from an object if it exists. + * + * @param obj - The object from which to delete the property. + * @param property - The property to delete from the object. + */ +export function deleteProperty>( + obj: T | null, + property: keyof T, +): void { + if (obj && property in obj) { + delete obj[property]; + } +} diff --git a/test/request-handler.spec.ts b/test/request-handler.spec.ts index 061e74c..856ed29 100644 --- a/test/request-handler.spec.ts +++ b/test/request-handler.spec.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { RequestHandler } from '../src/request-handler'; import fetchMock from 'fetch-mock'; -import { fetchf, FetchResponse } from '../src'; +import { fetchf } from '../src'; import { interceptRequest, interceptResponse, @@ -915,6 +915,7 @@ describe('Request Handler', () => { cancellable: true, rejectCancelled: false, flattenResponse: true, + defaultResponse: {}, }); const secondRequest = fetchf('https://example.com/second', { flattenResponse: true, @@ -927,187 +928,6 @@ describe('Request Handler', () => { }); }); - describe('parseData()', () => { - let mockResponse: FetchResponse; - const requestHandler = new RequestHandler({ fetcher }); - - beforeEach(() => { - mockResponse = { - headers: { - get: jest.fn(), - }, - clone: jest.fn(), - json: jest.fn(), - formData: jest.fn(), - blob: jest.fn(), - text: jest.fn(), - body: 'something', - } as unknown as FetchResponse; - }); - - it('should parse JSON response when Content-Type is application/json', async () => { - (mockResponse.headers.get as jest.Mock).mockReturnValue( - 'application/json', - ); - const expectedData = { key: 'value' }; - (mockResponse.json as jest.Mock).mockResolvedValue(expectedData); - - const data = await requestHandler.parseData(mockResponse); - expect(data).toEqual(expectedData); - }); - - it('should parse JSON response when Content-Type is application/vnd.api+json', async () => { - (mockResponse.headers.get as jest.Mock).mockReturnValue( - 'application/vnd.api+json', - ); - const expectedData = { key: 'value' }; - (mockResponse.json as jest.Mock).mockResolvedValue(expectedData); - - const data = await requestHandler.parseData(mockResponse); - expect(data).toEqual(expectedData); - }); - - it('should parse FormData when Content-Type is multipart/form-data', async () => { - (mockResponse.headers.get as jest.Mock).mockReturnValue( - 'multipart/form-data', - ); - const expectedData = new FormData(); - (mockResponse.formData as jest.Mock).mockResolvedValue(expectedData); - - const data = await requestHandler.parseData(mockResponse); - expect(data).toEqual(expectedData); - }); - - it('should parse Blob when Content-Type is application/octet-stream', async () => { - (mockResponse.headers.get as jest.Mock).mockReturnValue( - 'application/octet-stream', - ); - const expectedData = new Blob(['test']); - (mockResponse.blob as jest.Mock).mockResolvedValue(expectedData); - - const data = await requestHandler.parseData(mockResponse); - expect(data).toEqual(expectedData); - }); - - it('should parse FormData when Content-Type is application/x-www-form-urlencoded', async () => { - (mockResponse.headers.get as jest.Mock).mockReturnValue( - 'application/x-www-form-urlencoded', - ); - const expectedData = new FormData(); - (mockResponse.formData as jest.Mock).mockResolvedValue(expectedData); - - const data = await requestHandler.parseData(mockResponse); - expect(data).toEqual(expectedData); - }); - - it('should parse text when Content-Type is text/plain', async () => { - (mockResponse.headers.get as jest.Mock).mockReturnValue('text/plain'); - const expectedData = 'Some plain text'; - (mockResponse.text as jest.Mock).mockResolvedValue(expectedData); - - const data = await requestHandler.parseData(mockResponse); - expect(data).toEqual(expectedData); - }); - - it('should return plain text when Content-Type is missing and JSON parsing fails', async () => { - (mockResponse.headers.get as jest.Mock).mockReturnValue(''); - const responseClone = { - json: jest.fn().mockRejectedValue(new Error('JSON parsing error')), - }; - (mockResponse.clone as jest.Mock).mockReturnValue(responseClone); - - const expectedData = 'Some plain text'; - (mockResponse.text as jest.Mock).mockResolvedValue(expectedData); - - const data = await requestHandler.parseData(mockResponse); - - expect(data).toBe('Some plain text'); - }); - - it('should return null when content type is not recognized and response parsing fails', async () => { - (mockResponse.headers.get as jest.Mock).mockReturnValue( - 'application/unknown-type', - ); - (mockResponse.text as jest.Mock).mockRejectedValue( - new Error('Text parsing error'), - ); - - const data = await requestHandler.parseData(mockResponse); - expect(data).toBeNull(); - }); - - it('should handle streams and return body or data when Content-Type is not recognized', async () => { - (mockResponse.headers.get as jest.Mock).mockReturnValue( - 'application/unknown-type', - ); - - // Mock the `text` method to simulate stream content - const streamContent = 'stream content'; - (mockResponse.text as jest.Mock).mockResolvedValue(streamContent); - - const data = await requestHandler.parseData(mockResponse); - expect(data).toEqual(streamContent); - }); - }); - - describe('processHeaders()', () => { - const requestHandler = new RequestHandler({ fetcher }); - - // Test when headers is null or undefined - it('should return an empty object if headers are null or undefined', () => { - const response = { headers: null } as unknown as FetchResponse; - const result = requestHandler.processHeaders(response); - expect(result).toEqual({}); - - const responseUndefined = { - headers: undefined, - } as unknown as FetchResponse; - const resultUndefined = requestHandler.processHeaders(responseUndefined); - expect(resultUndefined).toEqual({}); - }); - - // Test when headers is an instance of Headers - it('should convert Headers object to a plain object', () => { - const headers = new Headers(); - headers.append('Content-Type', 'application/json'); - headers.append('Authorization', 'Bearer token'); - - const response = { headers } as FetchResponse; - const result = requestHandler.processHeaders(response); - - expect(result).toEqual({ - 'content-type': 'application/json', - authorization: 'Bearer token', - }); - }); - - // Test when headers is a plain object - it('should handle plain object headers', () => { - const response = { - headers: { - 'Content-Type': 'application/json', - Authorization: 'Bearer token', - }, - } as unknown as FetchResponse; - - const result = requestHandler.processHeaders(response); - - expect(result).toEqual({ - 'content-type': 'application/json', - authorization: 'Bearer token', - }); - }); - - // Test when headers is an empty Headers object - it('should handle an empty Headers object', () => { - const headers = new Headers(); // Empty Headers - const response = { headers } as FetchResponse; - const result = requestHandler.processHeaders(response); - - expect(result).toEqual({}); - }); - }); - describe('outputResponse()', () => { it('should show nested data object if flattening is off', async () => { const requestHandler = new RequestHandler({ diff --git a/test/request-parser.spec.ts b/test/request-parser.spec.ts new file mode 100644 index 0000000..4c7b3c0 --- /dev/null +++ b/test/request-parser.spec.ts @@ -0,0 +1,122 @@ +import { parseResponseData } from '../src/response-parser'; +import type { FetchResponse } from '../src/types/request-handler'; + +describe('parseData()', () => { + let mockResponse: FetchResponse; + + beforeEach(() => { + mockResponse = { + headers: { + get: jest.fn(), + }, + clone: jest.fn(), + json: jest.fn(), + formData: jest.fn(), + blob: jest.fn(), + text: jest.fn(), + body: 'something', + } as unknown as FetchResponse; + }); + + it('should parse JSON response when Content-Type is application/json', async () => { + (mockResponse.headers.get as jest.Mock).mockReturnValue('application/json'); + const expectedData = { key: 'value' }; + (mockResponse.json as jest.Mock).mockResolvedValue(expectedData); + + const data = await parseResponseData(mockResponse); + expect(data).toEqual(expectedData); + }); + + it('should parse JSON response when Content-Type is application/vnd.api+json', async () => { + (mockResponse.headers.get as jest.Mock).mockReturnValue( + 'application/vnd.api+json', + ); + const expectedData = { key: 'value' }; + (mockResponse.json as jest.Mock).mockResolvedValue(expectedData); + + const data = await parseResponseData(mockResponse); + expect(data).toEqual(expectedData); + }); + + it('should parse FormData when Content-Type is multipart/form-data', async () => { + (mockResponse.headers.get as jest.Mock).mockReturnValue( + 'multipart/form-data', + ); + const expectedData = new FormData(); + (mockResponse.formData as jest.Mock).mockResolvedValue(expectedData); + + const data = await parseResponseData(mockResponse); + expect(data).toEqual(expectedData); + }); + + it('should parse Blob when Content-Type is application/octet-stream', async () => { + (mockResponse.headers.get as jest.Mock).mockReturnValue( + 'application/octet-stream', + ); + const expectedData = new Blob(['test']); + (mockResponse.blob as jest.Mock).mockResolvedValue(expectedData); + + const data = await parseResponseData(mockResponse); + expect(data).toEqual(expectedData); + }); + + it('should parse FormData when Content-Type is application/x-www-form-urlencoded', async () => { + (mockResponse.headers.get as jest.Mock).mockReturnValue( + 'application/x-www-form-urlencoded', + ); + const expectedData = new FormData(); + (mockResponse.formData as jest.Mock).mockResolvedValue(expectedData); + + const data = await parseResponseData(mockResponse); + expect(data).toEqual(expectedData); + }); + + it('should parse text when Content-Type is text/plain', async () => { + (mockResponse.headers.get as jest.Mock).mockReturnValue('text/plain'); + const expectedData = 'Some plain text'; + (mockResponse.text as jest.Mock).mockResolvedValue(expectedData); + + const data = await parseResponseData(mockResponse); + expect(data).toEqual(expectedData); + }); + + it('should return plain text when Content-Type is missing and JSON parsing fails', async () => { + (mockResponse.headers.get as jest.Mock).mockReturnValue(''); + const responseClone = { + json: jest.fn().mockRejectedValue(new Error('JSON parsing error')), + }; + (mockResponse.clone as jest.Mock).mockReturnValue(responseClone); + + const expectedData = 'Some plain text'; + (mockResponse.text as jest.Mock).mockResolvedValue(expectedData); + + const data = await parseResponseData(mockResponse); + + expect(data).toBe('Some plain text'); + }); + + it('should return null when content type is not recognized and response parsing fails', async () => { + (mockResponse.headers.get as jest.Mock).mockReturnValue( + 'application/unknown-type', + ); + (mockResponse.text as jest.Mock).mockRejectedValue( + new Error('Text parsing error'), + ); + + const data = await parseResponseData(mockResponse); + expect(data).toBeNull(); + }); + + it('should handle streams and return body or data when Content-Type is not recognized', async () => { + (mockResponse.headers.get as jest.Mock).mockReturnValue( + 'application/unknown-type', + ); + + // Mock the `text` method to simulate stream content + const streamContent = 'stream content'; + (mockResponse.text as jest.Mock).mockResolvedValue(streamContent); + + const data = await parseResponseData(mockResponse); + expect(data).toEqual(streamContent); + }); +}); diff --git a/test/utils.spec.ts b/test/utils.spec.ts index 6aa05b2..648b570 100644 --- a/test/utils.spec.ts +++ b/test/utils.spec.ts @@ -3,6 +3,7 @@ import { replaceUrlPathParams, appendQueryParams, delayInvocation, + processHeaders, } from '../src/utils'; jest.mock('../src/interceptor-manager', () => ({ @@ -393,4 +394,46 @@ describe('Utils', () => { expect(result).toBe(true); }); }); + + describe('processHeaders()', () => { + it('should return an empty object if headers are null or undefined', () => { + const result = processHeaders(null); + expect(result).toEqual({}); + + const resultUndefined = processHeaders(undefined); + expect(resultUndefined).toEqual({}); + }); + + it('should convert Headers object to a plain object', () => { + const headers = new Headers(); + headers.append('Content-Type', 'application/json'); + headers.append('Authorization', 'Bearer token'); + + const result = processHeaders(headers); + + expect(result).toEqual({ + 'content-type': 'application/json', + authorization: 'Bearer token', + }); + }); + + it('should handle plain object headers', () => { + const result = processHeaders({ + 'Content-Type': 'application/json', + Authorization: 'Bearer token', + }); + + expect(result).toEqual({ + 'content-type': 'application/json', + authorization: 'Bearer token', + }); + }); + + it('should handle an empty Headers object', () => { + const headers = new Headers(); // Empty Headers + const result = processHeaders(headers); + + expect(result).toEqual({}); + }); + }); }); From 0ccff5c74057b699f0f34bf0b7886e36cbcf27d1 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 13 Sep 2024 04:30:18 +0200 Subject: [PATCH 09/18] docs: Add mode information about request deduplication to docs --- README.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a07f2ff..0a37860 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [npm-url]: https://npmjs.org/package/fetchff [npm-image]: http://img.shields.io/npm/v/fetchff.svg -[![NPM version][npm-image]][npm-url] [![Blazing Fast](https://badgen.now.sh/badge/speed/blazing%20%F0%9F%94%A5/green)](https://github.com/MattCCC/fetchff) [![Code Coverage](https://badgen.now.sh/badge/coverage/92.53/blue)](https://github.com/MattCCC/fetchff) [![npm downloads](https://img.shields.io/npm/dm/fetchff.svg?style=flat-square)](http://npm-stat.com/charts.html?package=fetchff) [![gzip size](https://img.shields.io/bundlephobia/minzip/fetchff)](https://bundlephobia.com/result?p=fetchff) +[![NPM version][npm-image]][npm-url] [![Blazing Fast](https://badgen.now.sh/badge/speed/blazing%20%F0%9F%94%A5/green)](https://github.com/MattCCC/fetchff) [![Code Coverage](https://badgen.now.sh/badge/coverage/97.68%/blue)](https://github.com/MattCCC/fetchff) [![npm downloads](https://img.shields.io/npm/dm/fetchff.svg?style=flat-square)](http://npm-stat.com/charts.html?package=fetchff) [![gzip size](https://img.shields.io/bundlephobia/minzip/fetchff)](https://bundlephobia.com/result?p=fetchff) ## Why? @@ -24,6 +24,7 @@ Managing multiple API endpoints can be complex and time-consuming. `fetchff` sim - **100% Performance-Oriented**: Optimized for speed and efficiency, ensuring fast and reliable API interactions. - **Fully TypeScript Compatible**: Enjoy full TypeScript support for better development experience and type safety. - **Smart Error Retry**: Features exponential backoff for intelligent error handling and retry mechanisms. +- **Automatic Request Deduplication**: Set the time during which requests are deduplicated (treated as same request). - **Dynamic URLs Support**: Easily manage routes with dynamic parameters, such as `/user/:userId`. - **Native `fetch()` Support**: Uses the modern `fetch()` API by default, eliminating the need for libraries like Axios. - **Global and Per Request Error Handling**: Flexible error management at both global and individual request levels. @@ -503,8 +504,10 @@ Check Examples section below for more information. | Feature | fetchff | ofetch | wretch | axios | native fetch() | | --------------------------------------- | ------------ | ------------ | ------------ | ------------ | -------------- | | **Unified API Client** | ✅ | -- | -- | -- | -- | +| **Automatic Request Deduplication** | ✅ | -- | -- | -- | -- | | **Customizable Error Handling** | ✅ | -- | ✅ | ✅ | -- | | **Retries with exponential backoff** | ✅ | -- | -- | -- | -- | +| **Custokm Retry logic** | ✅ | ✅ | ✅ | -- | -- | | **Easy Timeouts** | ✅ | ✅ | ✅ | ✅ | -- | | **Easy Cancellation** | ✅ | -- | -- | -- | -- | | **Default Responses** | ✅ | -- | -- | -- | -- | @@ -530,9 +533,7 @@ fetchf includes all necessary [TypeScript](http://typescriptlang.org) definition ### Example of interfaces ```typescript -import type { DefaultEndpoints } from 'fetchff'; -import { createApiFetcher } from 'fetchff'; - +// books.d.ts interface Book { id: number; title: string; @@ -551,6 +552,12 @@ interface BookQueryParams { interface BookPathParams { bookId?: number; } +``` + +```typescript +// api.ts +import type { DefaultEndpoints } from 'fetchff'; +import { createApiFetcher } from 'fetchff'; const endpoints = { fetchBooks: { @@ -561,7 +568,7 @@ const endpoints = { }, }; -// Note how you don't need to specify all endpoints for typings here. The "fetchBooks" is inferred +// No need to specify all endpoints types. For example, the "fetchBooks" is inferred automatically. interface EndpointsList { fetchBook: Endpoint; } @@ -570,8 +577,9 @@ const api = createApiFetcher({ apiUrl: 'https://example.com/api/', endpoints, }); +``` -// Fetch book +```typescript const book = await api.fetchBook({ newBook: true }, { bookId: 1 }); // Will return an error since "rating" does not exist in "BookQueryParams" From efa23b490325b067894094282f361905a5d0f2a8 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 13 Sep 2024 05:13:39 +0200 Subject: [PATCH 10/18] refactor: Convert to functions so to decrease bundle size --- src/api-handler.ts | 4 +- src/index.ts | 4 +- src/request-handler.ts | 276 ++++++++++++++++++----------------- src/types/api-handler.ts | 4 +- src/types/request-handler.ts | 22 ++- test/request-handler.spec.ts | 61 ++++---- 6 files changed, 203 insertions(+), 168 deletions(-) diff --git a/src/api-handler.ts b/src/api-handler.ts index 68ebb0f..cac0f4b 100644 --- a/src/api-handler.ts +++ b/src/api-handler.ts @@ -1,4 +1,3 @@ -import { RequestHandler } from './request-handler'; import type { FetcherInstance, RequestConfig, @@ -12,6 +11,7 @@ import type { QueryParamsOrBody, UrlPathParams, } from './types/api-handler'; +import { createRequestHandler } from './request-handler'; /** * Creates an instance of API Handler. @@ -69,7 +69,7 @@ function createApiFetcher< EndpointsCfg = never, >(config: ApiHandlerConfig) { const endpoints = config.endpoints; - const requestHandler = new RequestHandler(config); + const requestHandler = createRequestHandler(config); /** * Get Fetcher Provider Instance diff --git a/src/index.ts b/src/index.ts index 5c00749..531913a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import { RequestHandler } from './request-handler'; +import { createRequestHandler } from './request-handler'; import type { APIResponse, FetchResponse, RequestHandlerConfig } from './types'; /** @@ -13,7 +13,7 @@ export async function fetchf( url: string, config: RequestHandlerConfig = {}, ): Promise> { - return new RequestHandler(config).request(url, null, config); + return createRequestHandler(config).request(url, null, config); } export * from './types'; diff --git a/src/request-handler.ts b/src/request-handler.ts index b89d194..3c6bd5f 100644 --- a/src/request-handler.ts +++ b/src/request-handler.ts @@ -7,6 +7,7 @@ import type { RetryOptions, FetchResponse, ResponseError, + RequestHandlerReturnType, } from './types/request-handler'; import type { APIResponse, @@ -29,99 +30,114 @@ import { addRequest, removeRequest } from './queue-manager'; import { APPLICATION_JSON, CONTENT_TYPE } from './const'; import { parseResponseData } from './response-parser'; +const defaultConfig: RequestHandlerConfig = { + method: 'GET', + strategy: 'reject', + timeout: 30000, + rejectCancelled: false, + dedupeTime: 1000, + withCredentials: false, + flattenResponse: false, + defaultResponse: null, + logger: null, + fetcher: null, + baseURL: '', + retry: { + retries: 0, + delay: 1000, + maxDelay: 30000, + resetTimeout: true, + backoff: 1.5, + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status + retryOn: [ + 408, // Request Timeout + 409, // Conflict + 425, // Too Early + 429, // Too Many Requests + 500, // Internal Server Error + 502, // Bad Gateway + 503, // Service Unavailable + 504, // Gateway Timeout + ], + + shouldRetry: async () => true, + }, +}; + /** - * Generic Request Handler - * It creates an Request Fetcher instance and handles requests within that instance - * It handles errors depending on a chosen error handling strategy + * Create a Request Handler + * + * @param {RequestHandlerConfig} config - Configuration object for the request handler + * @returns {Object} An object with methods for handling requests */ -export class RequestHandler { - public requestInstance: FetcherInstance; - public config: RequestHandlerConfig = {}; - - public constructor(config: RequestHandlerConfig) { - this.config = { - method: 'GET', - strategy: 'reject', - timeout: 30000, - rejectCancelled: false, - dedupeTime: 1000, - withCredentials: false, - flattenResponse: false, - defaultResponse: null, - logger: null, - fetcher: null, - baseURL: config.apiUrl || '', - retry: { - retries: 0, - delay: 1000, - maxDelay: 30000, - resetTimeout: true, - backoff: 1.5, - - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status - retryOn: [ - 408, // Request Timeout - 409, // Conflict - 425, // Too Early - 429, // Too Many Requests - 500, // Internal Server Error - 502, // Bad Gateway - 503, // Service Unavailable - 504, // Gateway Timeout - ], - - shouldRetry: async () => true, - }, - ...config, - }; +function createRequestHandler( + config: RequestHandlerConfig, +): RequestHandlerReturnType { + const handlerConfig: RequestHandlerConfig = { + ...defaultConfig, + baseURL: config.apiUrl || '', + ...config, + }; + + /** + * Detects if a custom fetcher is utilized + * + * @returns {boolean} True if it's a custom fetcher + */ + const isCustomFetcher = (): boolean => { + return handlerConfig.fetcher !== null; + }; - this.requestInstance = this.isCustomFetcher() - ? (this.config.fetcher as any).create({ - ...config, - baseURL: this.config.baseURL, - timeout: this.config.timeout, - }) - : null; - } + const requestInstance = isCustomFetcher() + ? (handlerConfig.fetcher as any).create({ + ...config, + baseURL: handlerConfig.baseURL, + timeout: handlerConfig.timeout, + }) + : null; /** * Get Provider Instance * * @returns {FetcherInstance} Provider's instance */ - public getInstance(): FetcherInstance { - return this.requestInstance; - } + const getInstance = (): FetcherInstance => { + return requestInstance; + }; /** * Build request configuration * * @param {string} url - Request url * @param {QueryParamsOrBody} data - Query Params in case of GET and HEAD requests, body payload otherwise - * @param {RequestConfig} config - Request config passed when making the request + * @param {RequestConfig} reqConfig - Request config passed when making the request * @returns {RequestConfig} - Provider's instance */ - protected buildConfig( + const buildConfig = ( url: string, data: QueryParamsOrBody, - config: RequestConfig, - ): RequestConfig { + reqConfig: RequestConfig, + ): RequestConfig => { const method = ( - config.method || (this.config.method as string) + reqConfig.method || (handlerConfig.method as string) ).toUpperCase() as Method; const isGetAlikeMethod = method === 'GET' || method === 'HEAD'; const dynamicUrl = replaceUrlPathParams( url, - config.urlPathParams || this.config.urlPathParams || null, + reqConfig.urlPathParams || handlerConfig.urlPathParams || null, ); // The explicitly passed "params" - const explicitParams = config.params || this.config.params; + const explicitParams = reqConfig.params || handlerConfig.params; // The explicitly passed "body" or "data" const explicitBodyData = - config.body || config.data || this.config.body || this.config.data; + reqConfig.body || + reqConfig.data || + handlerConfig.body || + handlerConfig.data; // For convenience, in POST requests the body payload is the "data" // In edge cases we want to use Query Params in the POST requests @@ -137,9 +153,9 @@ export class RequestHandler { body = explicitBodyData || (data as BodyPayload); } - if (this.isCustomFetcher()) { + if (isCustomFetcher()) { return { - ...config, + ...reqConfig, method, url: dynamicUrl, params: shouldTreatDataAsParams @@ -151,23 +167,23 @@ export class RequestHandler { // Native fetch const isWithCredentials = - typeof config.withCredentials !== 'undefined' - ? config.withCredentials - : this.config.withCredentials; + typeof reqConfig.withCredentials !== 'undefined' + ? reqConfig.withCredentials + : handlerConfig.withCredentials; const credentials = isWithCredentials ? 'include' - : config.credentials || undefined; + : reqConfig.credentials || undefined; - deleteProperty(config, 'data'); - deleteProperty(config, 'withCredentials'); + deleteProperty(reqConfig, 'data'); + deleteProperty(reqConfig, 'withCredentials'); const urlPath = explicitParams || shouldTreatDataAsParams ? appendQueryParams(dynamicUrl, explicitParams || (data as QueryParams)) : dynamicUrl; const isFullUrl = urlPath.includes('://'); - const baseURL = isFullUrl ? '' : config.baseURL || this.config.baseURL; + const baseURL = isFullUrl ? '' : reqConfig.baseURL || handlerConfig.baseURL; // Automatically stringify request body, if possible and when not dealing with strings if ( @@ -180,7 +196,7 @@ export class RequestHandler { } return { - ...config, + ...reqConfig, credentials, body, method, @@ -191,11 +207,11 @@ export class RequestHandler { headers: { Accept: APPLICATION_JSON + ', text/plain, */*', [CONTENT_TYPE]: APPLICATION_JSON + ';charset=utf-8', - ...(this.config.headers || {}), - ...(config.headers || {}), + ...(handlerConfig.headers || {}), + ...(reqConfig.headers || {}), }, }; - } + }; /** * Process global Request Error @@ -204,16 +220,16 @@ export class RequestHandler { * @param {RequestConfig} requestConfig Per endpoint request config * @returns {void} */ - protected processError( + const processError = ( error: ResponseError, requestConfig: RequestConfig, - ): void { - if (this.isRequestCancelled(error)) { + ): void => { + if (isRequestCancelled(error)) { return; } - if (this.config.logger?.warn) { - this.config.logger.warn('API ERROR', error); + if (handlerConfig.logger?.warn) { + handlerConfig.logger.warn('API ERROR', error); } // Invoke per request "onError" interceptor @@ -222,10 +238,10 @@ export class RequestHandler { } // Invoke global "onError" interceptor - if (this.config.onError) { - this.config.onError(error); + if (handlerConfig.onError) { + handlerConfig.onError(error); } - } + }; /** * Output default response in case of an error, depending on chosen strategy @@ -235,21 +251,21 @@ export class RequestHandler { * @param {RequestConfig} requestConfig Per endpoint request config * @returns {*} Error response */ - protected async outputErrorResponse( + const outputErrorResponse = async ( error: ResponseError, response: FetchResponse | null, requestConfig: RequestConfig, - ): Promise { - const isRequestCancelled = this.isRequestCancelled(error); + ): Promise => { + const _isRequestCancelled = isRequestCancelled(error); const errorHandlingStrategy = - requestConfig.strategy || this.config.strategy; + requestConfig.strategy || handlerConfig.strategy; const rejectCancelled = typeof requestConfig.rejectCancelled !== 'undefined' ? requestConfig.rejectCancelled - : this.config.rejectCancelled; + : handlerConfig.rejectCancelled; // By default cancelled requests aren't rejected (softFail strategy) - if (!(isRequestCancelled && !rejectCancelled)) { + if (!(_isRequestCancelled && !rejectCancelled)) { // Hang the promise if (errorHandlingStrategy === 'silent') { await new Promise(() => null); @@ -260,8 +276,8 @@ export class RequestHandler { } } - return this.outputResponse(response, requestConfig, error); - } + return outputResponse(response, requestConfig, error); + }; /** * Output error response depending on chosen strategy @@ -269,49 +285,40 @@ export class RequestHandler { * @param {ResponseError} error Error instance * @returns {boolean} True if request is aborted */ - public isRequestCancelled(error: ResponseError): boolean { + const isRequestCancelled = (error: ResponseError): boolean => { return error.name === 'AbortError' || error.name === 'CanceledError'; - } - - /** - * Detects if a custom fetcher is utilized - * - * @returns {boolean} True if it's a custom fetcher - */ - protected isCustomFetcher(): boolean { - return this.config.fetcher !== null; - } + }; /** * Handle Request depending on used strategy * * @param {string} url - Request url * @param {QueryParamsOrBody} data - Query Params in case of GET and HEAD requests, body payload otherwise - * @param {RequestConfig} config - Request config + * @param {RequestConfig} reqConfig - Request config * @throws {ResponseError} * @returns {Promise>} Response Data */ - public async request( + const request = async ( url: string, data: QueryParamsOrBody = null, - config: RequestConfig | null = null, - ): Promise> { + reqConfig: RequestConfig | null = null, + ): Promise> => { let response: FetchResponse | null = null; - const _config = config || {}; - const _requestConfig = this.buildConfig(url, data, _config); + const _reqConfig = reqConfig || {}; + const _requestConfig = buildConfig(url, data, _reqConfig); const timeout = typeof _requestConfig.timeout !== 'undefined' ? _requestConfig.timeout - : (this.config.timeout as number); + : (handlerConfig.timeout as number); const isCancellable = typeof _requestConfig.cancellable !== 'undefined' ? _requestConfig.cancellable - : this.config.cancellable; + : handlerConfig.cancellable; const dedupeTime = typeof _requestConfig.dedupeTime !== 'undefined' ? _requestConfig.dedupeTime - : this.config.dedupeTime; + : handlerConfig.dedupeTime; const { retries, @@ -322,7 +329,7 @@ export class RequestHandler { maxDelay, resetTimeout, } = { - ...this.config.retry, + ...handlerConfig.retry, ...(_requestConfig?.retry || {}), } as Required; @@ -355,11 +362,11 @@ export class RequestHandler { // Global interceptors requestConfig = await interceptRequest( requestConfig, - this.config?.onRequest, + handlerConfig?.onRequest, ); - if (this.isCustomFetcher()) { - response = (await (this.requestInstance as any).request( + if (isCustomFetcher()) { + response = (await (requestInstance as any).request( requestConfig, )) as FetchResponse; } else { @@ -386,9 +393,9 @@ export class RequestHandler { response = await interceptResponse(response, requestConfig?.onResponse); // Global interceptors - response = await interceptResponse(response, this.config?.onResponse); + response = await interceptResponse(response, handlerConfig?.onResponse); - return this.outputResponse(response, requestConfig) as ResponseData & + return outputResponse(response, requestConfig) as ResponseData & FetchResponse; } catch (err) { const error = err as ResponseError; @@ -399,15 +406,15 @@ export class RequestHandler { !(await shouldRetry(error, attempt)) || !retryOn?.includes(status) ) { - this.processError(error, _requestConfig); + processError(error, _requestConfig); removeRequest(_requestConfig); - return this.outputErrorResponse(error, response, _requestConfig); + return outputErrorResponse(error, response, _requestConfig); } - if (this.config.logger?.warn) { - this.config.logger.warn( + if (handlerConfig.logger?.warn) { + handlerConfig.logger.warn( `Attempt ${attempt + 1} failed. Retrying in ${waitTime}ms...`, ); } @@ -420,9 +427,9 @@ export class RequestHandler { } } - return this.outputResponse(response, _requestConfig) as ResponseData & + return outputResponse(response, _requestConfig) as ResponseData & FetchResponse; - } + }; /** * Output response @@ -432,19 +439,19 @@ export class RequestHandler { * @param error - whether the response is erroneous * @returns {ResponseData | FetchResponse} Response data */ - protected outputResponse( + const outputResponse = ( response: FetchResponse | null, requestConfig: RequestConfig, error: ResponseError | null = null, - ): ResponseData | FetchResponse { + ): ResponseData | FetchResponse => { const defaultResponse = typeof requestConfig.defaultResponse !== 'undefined' ? requestConfig.defaultResponse - : this.config.defaultResponse; + : handlerConfig.defaultResponse; const flattenResponse = typeof requestConfig.flattenResponse !== 'undefined' ? requestConfig.flattenResponse - : this.config.flattenResponse; + : handlerConfig.flattenResponse; if (!response) { return flattenResponse @@ -478,9 +485,7 @@ export class RequestHandler { return flattenData(data); } - const isCustomFetcher = this.isCustomFetcher(); - - if (isCustomFetcher) { + if (isCustomFetcher()) { return response; } @@ -507,5 +512,14 @@ export class RequestHandler { headers: processHeaders(response.headers), config: requestConfig, }; - } + }; + + return { + getInstance, + buildConfig, + config, + request, + }; } + +export { createRequestHandler }; diff --git a/src/types/api-handler.ts b/src/types/api-handler.ts index 0341501..a2485a7 100644 --- a/src/types/api-handler.ts +++ b/src/types/api-handler.ts @@ -1,9 +1,9 @@ -import type { RequestHandler } from '../request-handler'; import type { RequestConfig, FetcherInstance, RequestHandlerConfig, FetchResponse, + RequestHandlerReturnType, } from './request-handler'; // Common type definitions @@ -91,7 +91,7 @@ export type ApiHandlerReturnType< export type ApiHandlerMethods = { config: ApiHandlerConfig; endpoints: EndpointsConfig; - requestHandler: RequestHandler; + requestHandler: RequestHandlerReturnType; getInstance: () => FetcherInstance; request: ( endpointName: keyof EndpointsMethods | string, diff --git a/src/types/request-handler.ts b/src/types/request-handler.ts index 38d7db7..ca0302d 100644 --- a/src/types/request-handler.ts +++ b/src/types/request-handler.ts @@ -1,5 +1,10 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { BodyPayload, QueryParams, UrlPathParams } from './api-handler'; +import type { + BodyPayload, + QueryParams, + QueryParamsOrBody, + UrlPathParams, +} from './api-handler'; import type { RequestInterceptor, ResponseInterceptor, @@ -246,3 +251,18 @@ interface BaseRequestHandlerConfig extends RequestConfig { export type RequestConfig = ExtendedRequestConfig; export type RequestHandlerConfig = BaseRequestHandlerConfig; + +export interface RequestHandlerReturnType { + config: RequestHandlerConfig; + getInstance: () => FetcherInstance; + buildConfig: ( + url: string, + data: QueryParamsOrBody, + config: RequestConfig, + ) => RequestConfig; + request: ( + url: string, + data?: QueryParamsOrBody, + config?: RequestConfig | null, + ) => Promise>; +} diff --git a/test/request-handler.spec.ts b/test/request-handler.spec.ts index 856ed29..3be2b29 100644 --- a/test/request-handler.spec.ts +++ b/test/request-handler.spec.ts @@ -1,12 +1,13 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { RequestHandler } from '../src/request-handler'; +import { createRequestHandler } from '../src/request-handler'; import fetchMock from 'fetch-mock'; -import { fetchf } from '../src'; import { interceptRequest, interceptResponse, } from '../src/interceptor-manager'; import { delayInvocation } from '../src/utils'; +import type { RequestHandlerReturnType } from '../src/types/request-handler'; +import { fetchf } from '../src'; jest.mock('../src/interceptor-manager', () => ({ interceptRequest: jest.fn().mockImplementation(async (config) => config), @@ -45,7 +46,7 @@ describe('Request Handler', () => { }); it('should get request instance', () => { - const requestHandler = new RequestHandler({ fetcher }); + const requestHandler = createRequestHandler({ fetcher }); const response = requestHandler.getInstance(); @@ -53,10 +54,10 @@ describe('Request Handler', () => { }); describe('buildConfig() with native fetch()', () => { - let requestHandler: RequestHandler | null = null; + let requestHandler: RequestHandlerReturnType | null = null; beforeAll(() => { - requestHandler = new RequestHandler({}); + requestHandler = createRequestHandler({}); }); const buildConfig = (method: string, url: string, data: any, config: any) => @@ -319,12 +320,12 @@ describe('Request Handler', () => { }); it('should properly hang promise when using Silent strategy', async () => { - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ fetcher, strategy: 'silent', }); - (requestHandler.requestInstance as any).request = jest + (requestHandler.getInstance() as any).request = jest .fn() .mockRejectedValue(new Error('Request Failed')); @@ -348,12 +349,12 @@ describe('Request Handler', () => { }); it('should reject promise when using rejection strategy', async () => { - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ fetcher, strategy: 'reject', }); - (requestHandler.requestInstance as any).request = jest + (requestHandler.getInstance() as any).request = jest .fn() .mockRejectedValue(new Error('Request Failed')); @@ -366,12 +367,12 @@ describe('Request Handler', () => { }); it('should reject promise when using reject strategy per endpoint', async () => { - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ fetcher, strategy: 'silent', }); - (requestHandler.requestInstance as any).request = jest + (requestHandler.getInstance() as any).request = jest .fn() .mockRejectedValue(new Error('Request Failed')); @@ -411,7 +412,7 @@ describe('Request Handler', () => { }; // Initialize RequestHandler with mock configuration - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ baseURL, retry: retryConfig, logger: mockLogger, @@ -476,7 +477,7 @@ describe('Request Handler', () => { retryOn: [500], // Retry on server errors shouldRetry: jest.fn(() => Promise.resolve(true)), }; - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ baseURL, retry: retryConfig, logger: mockLogger, @@ -526,7 +527,7 @@ describe('Request Handler', () => { retryOn: [500], shouldRetry: jest.fn(() => Promise.resolve(true)), }; - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ baseURL, retry: retryConfig, logger: mockLogger, @@ -555,7 +556,7 @@ describe('Request Handler', () => { retryOn: [500], shouldRetry: jest.fn(() => Promise.resolve(true)), }; - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ baseURL, retry: retryConfig, logger: mockLogger, @@ -598,7 +599,7 @@ describe('Request Handler', () => { retryOn: [500], shouldRetry: jest.fn(() => Promise.resolve(false)), }; - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ baseURL, retry: retryConfig, logger: mockLogger, @@ -620,10 +621,10 @@ describe('Request Handler', () => { }); describe('request() with interceptors', () => { - let requestHandler: RequestHandler; + let requestHandler: RequestHandlerReturnType; beforeEach(() => { - requestHandler = new RequestHandler({ + requestHandler = createRequestHandler({ baseURL: 'https://api.example.com', timeout: 5000, cancellable: true, @@ -791,7 +792,7 @@ describe('Request Handler', () => { }); it('should properly hang promise when using Silent strategy', async () => { - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ strategy: 'silent', }); @@ -819,7 +820,7 @@ describe('Request Handler', () => { }); it('should reject promise when using rejection strategy', async () => { - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ strategy: 'reject', }); @@ -836,7 +837,7 @@ describe('Request Handler', () => { }); it('should reject promise when using reject strategy per endpoint', async () => { - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ strategy: 'silent', }); @@ -862,7 +863,7 @@ describe('Request Handler', () => { it('should cancel previous request when successive request is made', async () => { fetchMock.reset(); - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ cancellable: true, rejectCancelled: true, flattenResponse: true, @@ -930,12 +931,12 @@ describe('Request Handler', () => { describe('outputResponse()', () => { it('should show nested data object if flattening is off', async () => { - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ fetcher, flattenResponse: false, }); - (requestHandler.requestInstance as any).request = jest + (requestHandler.getInstance() as any).request = jest .fn() .mockResolvedValue(responseMock); @@ -947,12 +948,12 @@ describe('Request Handler', () => { }); it('should handle nested data if data flattening is on', async () => { - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ fetcher, flattenResponse: true, }); - (requestHandler.requestInstance as any).request = jest + (requestHandler.getInstance() as any).request = jest .fn() .mockResolvedValue(responseMock); @@ -964,12 +965,12 @@ describe('Request Handler', () => { }); it('should handle deeply nested data if data flattening is on', async () => { - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ fetcher, flattenResponse: true, }); - (requestHandler.requestInstance as any).request = jest + (requestHandler.getInstance() as any).request = jest .fn() .mockResolvedValue({ data: responseMock }); @@ -981,13 +982,13 @@ describe('Request Handler', () => { }); it('should return null if there is no data', async () => { - const requestHandler = new RequestHandler({ + const requestHandler = createRequestHandler({ fetcher, flattenResponse: true, defaultResponse: null, }); - (requestHandler.requestInstance as any).request = jest + (requestHandler.getInstance() as any).request = jest .fn() .mockResolvedValue({ data: null }); From 3ce058e63adba565e4619805fa7805133cad4345 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 13 Sep 2024 05:18:25 +0200 Subject: [PATCH 11/18] fix: Properly consider request "credentials" passed --- src/request-handler.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/request-handler.ts b/src/request-handler.ts index 3c6bd5f..f6669ef 100644 --- a/src/request-handler.ts +++ b/src/request-handler.ts @@ -173,7 +173,7 @@ function createRequestHandler( const credentials = isWithCredentials ? 'include' - : reqConfig.credentials || undefined; + : reqConfig.credentials || handlerConfig.credentials || undefined; deleteProperty(reqConfig, 'data'); deleteProperty(reqConfig, 'withCredentials'); @@ -305,19 +305,19 @@ function createRequestHandler( ): Promise> => { let response: FetchResponse | null = null; const _reqConfig = reqConfig || {}; - const _requestConfig = buildConfig(url, data, _reqConfig); + const fetcherConfig = buildConfig(url, data, _reqConfig); const timeout = - typeof _requestConfig.timeout !== 'undefined' - ? _requestConfig.timeout + typeof fetcherConfig.timeout !== 'undefined' + ? fetcherConfig.timeout : (handlerConfig.timeout as number); const isCancellable = - typeof _requestConfig.cancellable !== 'undefined' - ? _requestConfig.cancellable + typeof fetcherConfig.cancellable !== 'undefined' + ? fetcherConfig.cancellable : handlerConfig.cancellable; const dedupeTime = - typeof _requestConfig.dedupeTime !== 'undefined' - ? _requestConfig.dedupeTime + typeof fetcherConfig.dedupeTime !== 'undefined' + ? fetcherConfig.dedupeTime : handlerConfig.dedupeTime; const { @@ -330,7 +330,7 @@ function createRequestHandler( resetTimeout, } = { ...handlerConfig.retry, - ...(_requestConfig?.retry || {}), + ...(fetcherConfig?.retry || {}), } as Required; let attempt = 0; @@ -340,7 +340,7 @@ function createRequestHandler( try { // Add the request to the queue. Make sure to handle deduplication, cancellation, timeouts in accordance to retry settings const controller = await addRequest( - _requestConfig, + fetcherConfig, timeout, dedupeTime, isCancellable, @@ -350,7 +350,7 @@ function createRequestHandler( let requestConfig: RequestConfig = { signal, - ..._requestConfig, + ...fetcherConfig, }; // Local interceptors @@ -406,11 +406,11 @@ function createRequestHandler( !(await shouldRetry(error, attempt)) || !retryOn?.includes(status) ) { - processError(error, _requestConfig); + processError(error, fetcherConfig); - removeRequest(_requestConfig); + removeRequest(fetcherConfig); - return outputErrorResponse(error, response, _requestConfig); + return outputErrorResponse(error, response, fetcherConfig); } if (handlerConfig.logger?.warn) { @@ -427,7 +427,7 @@ function createRequestHandler( } } - return outputResponse(response, _requestConfig) as ResponseData & + return outputResponse(response, fetcherConfig) as ResponseData & FetchResponse; }; From 295d7c5a7ebcba8f0039da111971291d740dc297 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 14 Sep 2024 16:11:24 +0200 Subject: [PATCH 12/18] chore: Remove unused plugin --- package-lock.json | 227 ---------------------------------------------- package.json | 1 - 2 files changed, 228 deletions(-) diff --git a/package-lock.json b/package-lock.json index c02b6af..78edd7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,6 @@ "fetch-mock": "11.0.0", "jest": "29.7.0", "prettier": "3.3.3", - "rollup-plugin-bundle-imports": "1.5.1", "size-limit": "11.1.4", "ts-jest": "29.2.4", "tslib": "2.7.0", @@ -1451,78 +1450,6 @@ "url": "https://opencollective.com/unts" } }, - "node_modules/@rollup/plugin-commonjs": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.1.0.tgz", - "integrity": "sha512-6ZtHx3VHIp2ReNNDxHjuUml6ur+WcQ28N1yHgCQwsbNkQg2suhxGMDQGJOn/KuDxKtd1xuZP5xSTwBA4GQ8hbA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^2.38.3" - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz", - "integrity": "sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "deepmerge": "^4.2.2", - "is-builtin-module": "^3.1.0", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^2.42.0" - } - }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", @@ -1851,14 +1778,6 @@ "@babel/types": "^7.20.7" } }, - "node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/@types/graceful-fs": { "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", @@ -1917,17 +1836,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", @@ -2565,20 +2473,6 @@ "dev": true, "license": "MIT" }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/bundle-require": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.0.0.tgz", @@ -2807,14 +2701,6 @@ "node": ">= 6" } }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3351,14 +3237,6 @@ "node": ">=4.0" } }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3960,23 +3838,6 @@ "node": ">=8" } }, - "node_modules/is-builtin-module": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-core-module": { "version": "2.14.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", @@ -4036,14 +3897,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -4064,17 +3917,6 @@ "node": ">=8" } }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/estree": "*" - } - }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -5035,17 +4877,6 @@ "yallist": "^3.0.2" } }, - "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "sourcemap-codec": "^1.4.8" - } - }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -5843,55 +5674,6 @@ "node": ">=0.10.0" } }, - "node_modules/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-bundle-imports": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-bundle-imports/-/rollup-plugin-bundle-imports-1.5.1.tgz", - "integrity": "sha512-EIOiPV3Pk+RJtujTAXOdiKBV82qd+PM44uczsZI07XQ53nmMy5rFq2+YcMSRmGWRz9aCGEmib7Q6Ge4EZaRG+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "rollup-pluginutils": "^2.8.1" - }, - "peerDependencies": { - "@rollup/plugin-commonjs": "^21.0.0", - "@rollup/plugin-node-resolve": "^13.0.5", - "rollup": "^1.20.1 || ^2.0.0" - } - }, - "node_modules/rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "estree-walker": "^0.6.1" - } - }, - "node_modules/rollup-pluginutils/node_modules/estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true, - "license": "MIT" - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6016,15 +5798,6 @@ "source-map": "^0.6.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", diff --git a/package.json b/package.json index 97edecd..97c37c8 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,6 @@ "fetch-mock": "11.0.0", "jest": "29.7.0", "prettier": "3.3.3", - "rollup-plugin-bundle-imports": "1.5.1", "size-limit": "11.1.4", "ts-jest": "29.2.4", "tslib": "2.7.0", From 6467d8688ea543190d55248fa82e3595f8f10c1c Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 14 Sep 2024 16:14:09 +0200 Subject: [PATCH 13/18] chore: Update install stage --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 66124c1..2ee5afd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,8 +19,8 @@ jobs: with: node-version: ${{ matrix.node }} - - name: Install deps and build (with cache) - uses: bahmutov/npm-install@v1 + - name: Install deps + run: npm i - name: Lint run: npm run lint From 1116ebd69bf02b8d414ab48ab204ae297b720ea1 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 14 Sep 2024 16:17:34 +0200 Subject: [PATCH 14/18] chore: Update install stage --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2ee5afd..bf37343 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,7 +20,7 @@ jobs: node-version: ${{ matrix.node }} - name: Install deps - run: npm i + run: npm ci - name: Lint run: npm run lint From 2f6de1fe6d7b2ce38a76a0c54b0b33a52f9e78e7 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 14 Sep 2024 16:20:23 +0200 Subject: [PATCH 15/18] chore: Update install stage --- package-lock.json | 229 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 + 2 files changed, 232 insertions(+) diff --git a/package-lock.json b/package-lock.json index 78edd7e..c0a4016 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "fetchff", "version": "2.7.3", "license": "UNLICENSED", + "dependencies": { + "@rollup/rollup-linux-x64-gnu": "*" + }, "devDependencies": { "@size-limit/preset-small-lib": "11.1.4", "@types/jest": "29.5.12", @@ -26,6 +29,9 @@ }, "engines": { "node": ">=18" + }, + "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "4.21.3" } }, "node_modules/@ampproject/remapping": { @@ -1450,6 +1456,34 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", + "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz", + "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", @@ -1464,6 +1498,173 @@ "darwin" ] }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz", + "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz", + "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz", + "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz", + "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz", + "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz", + "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz", + "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz", + "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.3.tgz", + "integrity": "sha512-kZPbX/NOPh0vhS5sI+dR8L1bU2cSO9FgxwM8r7wHzGydzfSjLRCFAT87GR5U9scj2rhzN3JPYVC7NoBbl4FZ0g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", + "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", + "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", + "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -6331,6 +6532,34 @@ } } }, + "node_modules/tsup/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", + "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/tsup/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", + "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/tsup/node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", diff --git a/package.json b/package.json index 97c37c8..9100c92 100644 --- a/package.json +++ b/package.json @@ -69,5 +69,8 @@ "tsup": "8.2.4", "typescript": "5.6.2", "typescript-eslint": "8.5.0" + }, + "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "4.21.3" } } From d15e27ee00cd39774319c8b8d534484349877c04 Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 17 Sep 2024 00:28:35 +0200 Subject: [PATCH 16/18] feat: Improve queue handling + optimize size --- README.md | 2 +- src/api-handler.ts | 2 +- src/queue-manager.ts | 148 ++++++++++------------ src/request-handler.ts | 5 +- src/types/queue-manager.ts | 1 + src/types/request-handler.ts | 6 +- test/queue-manager.spec.ts | 230 +++++++++++++++++++++++++++++++---- 7 files changed, 281 insertions(+), 113 deletions(-) diff --git a/README.md b/README.md index 0a37860..c074005 100644 --- a/README.md +++ b/README.md @@ -432,7 +432,7 @@ You can also pass all `fetch()` settings. | endpoints \* | object | | List of your endpoints. Each endpoint accepts all these settings. They can be set globally or per-endpoint when they are called. | | fetcher \* | Function | fetch | The native `fetch()` is used by default. A custom instance that exposes create() and request() can be used otherwise. | | strategy | string | reject | Error handling strategies - basically what to return when an error occurs. It can be a default data, promise can be hanged (nothing would be returned) or rejected so to use try/catch.

Available: `reject`, `softFail`, `defaultResponse`, `silent`.

`reject` - Promises are rejected, and global error handling is triggered. Requires try/catch for handling.

`softFail` - returns a response object with additional properties such as `data`, `error`, `config`, `request`, and `headers` when an error occurs. This approach avoids throwing errors, allowing you to handle error information directly within the response object without the need for try/catch blocks.

`defaultResponse` - returns default response specified in case of an error. Promise will not be rejected. It could be used in conjuction with `flattenResponse` and as `defaultResponse: {}` so to provide a sensible defaults.

`silent` - hangs the promise silently on error, useful for fire-and-forget requests without the need for try/catch. In case of an error, the promise will never be resolved or rejected, and any code after will never be executed. The requests could be dispatched within an asynchronous wrapper functions that do not need to be awaited. If used properly, it prevents excessive usage of try/catch or additional response data checks everywhere. You can use it in combination with `onError` to handle errors separately. | -| cancellable | boolean | false | If `true`, any previous requests to same API endpoint will be cancelled, if a subsequent request is made meanwhile. This helps you avoid unnecessary requests to the backend. | +| cancellable | boolean | false | If `true`, any ongoing previous requests to same API endpoint will be cancelled, if a subsequent request is made meanwhile. This helps you avoid unnecessary requests to the backend. | | rejectCancelled | boolean | false | If `true` and request is set to `cancellable`, a cancelled requests' promise will be rejected. By default, instead of rejecting the promise, `defaultResponse` is returned. | | flattenResponse | boolean | false | Flatten nested response data, so you can avoid writing `response.data.data` and obtain response directly. Response is flattened when there is a "data" within response "data", and no other object properties set. | | defaultResponse | any | null | Default response when there is no data or when endpoint fails depending on the chosen `strategy` | diff --git a/src/api-handler.ts b/src/api-handler.ts index cac0f4b..f3af3fa 100644 --- a/src/api-handler.ts +++ b/src/api-handler.ts @@ -21,7 +21,7 @@ import { createRequestHandler } from './request-handler'; * @param {string} config.apiUrl - The base URL for the API. * @param {Object} config.endpoints - An object containing endpoint definitions. * @param {number} config.timeout - You can set the timeout for particular request in milliseconds. - * @param {number} config.cancellable - If true, the previous requests will be automatically cancelled. + * @param {number} config.cancellable - If true, the ongoing previous requests will be automatically cancelled. * @param {number} config.rejectCancelled - If true and request is set to cancellable, a cancelled request promise will be rejected. By default, instead of rejecting the promise, defaultResponse is returned. * @param {number} config.timeout - Request timeout * @param {string} config.strategy - Error Handling Strategy diff --git a/src/queue-manager.ts b/src/queue-manager.ts index 8a87697..b05bce5 100644 --- a/src/queue-manager.ts +++ b/src/queue-manager.ts @@ -9,36 +9,7 @@ import type { QueueItem, RequestsQueue } from './types/queue-manager'; * - Concurrency Control and Locking * - Request Lifecycle Management */ -const queue: RequestsQueue = new WeakMap(); -const locks = new WeakMap>(); - -/** - * Ensures that the operation on the queue is performed atomically. - * - * @param fn - The function to be executed with lock. - * @returns {Promise} - A promise that resolves when the operation is complete. - */ -export async function withLock( - key: object, - fn: () => Promise, -): Promise { - let release: () => void = () => {}; - const lock = new Promise((resolve) => (release = resolve)); - - // Wait for existing locks to be released - if (locks.has(key)) { - await locks.get(key); - } - - locks.set(key, lock); - - try { - return await fn(); - } finally { - release(); - locks.delete(key); - } -} +const queue: RequestsQueue = new Map(); /** * Adds a request to the queue if it's not already being processed within the dedupeTime interval. @@ -47,7 +18,7 @@ export async function withLock( * @param {number} timeout - Timeout in milliseconds for the request. * @param {number} dedupeTime - Deduplication time in milliseconds. * @param {boolean} isCancellable - If true, then the previous request with same configuration should be aborted. - * @param {boolean} resetTimeout - Whether to reset the timeout. + * @param {boolean} isTimeoutEnabled - Whether timeout is enabled. * @returns {Promise} - A promise that resolves to an AbortController. */ export async function addRequest( @@ -55,66 +26,74 @@ export async function addRequest( timeout: number, dedupeTime: number = 0, isCancellable: boolean = false, - resetTimeout: boolean = false, + isTimeoutEnabled: boolean = true, ): Promise { - return withLock(config, async () => { - const now = Date.now(); - const existingItem = queue.get(config); - - if (existingItem) { - // If the request is already in the queue and within the dedupeTime, reuse the existing controller - if (now - existingItem.timestamp < dedupeTime) { - return existingItem.controller; - } - - // Abort previous request, if applicable, and continue as usual - if (isCancellable) { - existingItem.controller.abort(); - } - - // If the request is too old, remove it and proceed to add a new one - removeRequest(config); + const now = Date.now(); + const item = queue.get(config); + + if (item) { + // If the request is already in the queue and within the dedupeTime, reuse the existing controller + if (!item.isCancellable && now - item.timestamp < dedupeTime) { + return item.controller; + } + + // If the request is too old, remove it and proceed to add a new one + // Abort previous request, if applicable, and continue as usual + if (item.isCancellable) { + item.controller.abort( + new DOMException('Aborted due to new request', 'AbortError'), + ); + } + + if (item.timeoutId !== null) { + clearTimeout(item.timeoutId); } - // Create a new AbortController and add the request to the queue - const controller = new AbortController(); - - // Set up a timeout to automatically abort the request if it exceeds the specified time. - const timeoutId = - // Timeout might be already set and we may not want to reset it, so do not create it when "resetTimeout" is set to "true" - timeout > 0 && !resetTimeout - ? setTimeout(() => { - const error = new Error(`${config.url} aborted due to timeout`); - error.name = 'TimeoutError'; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (error as any).code = 23; // DOMException.TIMEOUT_ERR - - controller.abort(error); - removeRequest(config); - }, timeout) - : null; - - queue.set(config, { controller, timeoutId, timestamp: now }); - return controller; - }); + queue.delete(config); + } + + const controller = new AbortController(); + + const timeoutId = isTimeoutEnabled + ? setTimeout(() => { + const error = new DOMException( + `${config.url} aborted due to timeout`, + 'TimeoutError', + ); + + removeRequest(config, error); + }, timeout) + : null; + + queue.set(config, { controller, timeoutId, timestamp: now, isCancellable }); + + return controller; } /** * Removes a request from the queue and clears its timeout. * * @param config - The request configuration. + * @param {boolean} error - Error payload so to force the request to abort. */ -export async function removeRequest(config: RequestConfig): Promise { - await withLock(config, async () => { - const item = queue.get(config); - - if (item) { - if (item.timeoutId !== null) { - clearTimeout(item.timeoutId); - } - queue.delete(config); +export async function removeRequest( + config: RequestConfig, + error: DOMException | null | string = null, +): Promise { + const item = queue.get(config); + + if (item) { + // If the request is not yet aborted, abort it with the provided error + if (error && !item.controller.signal.aborted) { + item.controller.abort(error); + } + + if (item.timeoutId !== null) { + clearTimeout(item.timeoutId); } - }); + + queue.delete(config); + } } /** @@ -126,12 +105,7 @@ export async function removeRequest(config: RequestConfig): Promise { export async function getController( config: RequestConfig, ): Promise { - let controller: AbortController | undefined; - - await withLock(config, async () => { - const item = queue.get(config); - controller = item?.controller; - }); + const item = queue.get(config); - return controller; + return item?.controller; } diff --git a/src/request-handler.ts b/src/request-handler.ts index f6669ef..db95869 100644 --- a/src/request-handler.ts +++ b/src/request-handler.ts @@ -344,7 +344,8 @@ function createRequestHandler( timeout, dedupeTime, isCancellable, - resetTimeout, + // Reset timeouts by default or when retries are ON + timeout > 0 && (!retries || resetTimeout), ); const signal = controller.signal; @@ -395,6 +396,8 @@ function createRequestHandler( // Global interceptors response = await interceptResponse(response, handlerConfig?.onResponse); + removeRequest(fetcherConfig); + return outputResponse(response, requestConfig) as ResponseData & FetchResponse; } catch (err) { diff --git a/src/types/queue-manager.ts b/src/types/queue-manager.ts index fe4535f..734b14b 100644 --- a/src/types/queue-manager.ts +++ b/src/types/queue-manager.ts @@ -6,4 +6,5 @@ export interface QueueItem { controller: AbortController; timeoutId?: NodeJS.Timeout | null; timestamp: number; + isCancellable: boolean; } diff --git a/src/types/request-handler.ts b/src/types/request-handler.ts index ca0302d..db37b48 100644 --- a/src/types/request-handler.ts +++ b/src/types/request-handler.ts @@ -148,12 +148,14 @@ interface ExtendedRequestConfig extends Omit { flattenResponse?: boolean; /** - * If `true`, allows the request to be cancellable using an `AbortController`. + * If true, the ongoing previous requests will be automatically cancelled. + * @default false */ cancellable?: boolean; /** * If `true`, rejects the request promise when the request is cancelled. + * @default false */ rejectCancelled?: boolean; @@ -175,6 +177,7 @@ interface ExtendedRequestConfig extends Omit { /** * The HTTP method to use for the request (e.g., 'GET', 'POST', etc.). + * @default GET */ method?: Method | string; @@ -236,7 +239,6 @@ interface ExtendedRequestConfig extends Omit { /** * Time window, in miliseconds, during which identical requests are deduplicated (treated as single request). - * * @default 1000 (1 second) */ dedupeTime?: number; diff --git a/test/queue-manager.spec.ts b/test/queue-manager.spec.ts index ee585cc..6eb53b3 100644 --- a/test/queue-manager.spec.ts +++ b/test/queue-manager.spec.ts @@ -28,7 +28,13 @@ describe('Request Queue Manager', () => { expect(retrievedController).toBeUndefined(); }); - it('should handle concurrent requests', async () => { + it('should handle removing a non-existent request', async () => { + await expect( + removeRequest(createConfig('https://example.com')), + ).resolves.not.toThrow(); + }); + + it('should handle multiple concurrent requests correctly', async () => { const config1 = createConfig('https://example1.com'); const config2 = createConfig('https://example2.com'); @@ -52,6 +58,71 @@ describe('Request Queue Manager', () => { await removeRequest(config2); }); + it('should handle concurrent requests with different configurations separately', async () => { + const config1 = createConfig('https://example.com/a'); + const config2 = createConfig('https://example.com/b'); + + // Add two concurrent requests with different configurations + const [controller1, controller2] = await Promise.all([ + addRequest(config1, 2000), + addRequest(config2, 2000), + ]); + + jest.advanceTimersByTime(2000); + + expect(controller1).toBeDefined(); + expect(controller2).toBeDefined(); + expect(controller1).not.toBe(controller2); + }); + + it('should abort request due to timeout and remove it from queue', async () => { + const config = createConfig('https://example.com'); + const timeout = 1000; + + // Add a request + await addRequest(config, timeout); + + // Advance timers to simulate timeout + jest.advanceTimersByTime(timeout); + + // Verify that the request was removed from the queue + const controller = await getController(config); + expect(controller).toBeUndefined(); // Ensure the request was removed + + // Ensure request removal + await removeRequest(config); + }); + + it('should queue multiple operations on the same request config correctly', async () => { + const config = createConfig('https://example.com'); + + // Simulate a long-running first request + const firstRequestPromise = addRequest(config, 2000); + + // Attempt to add a second request that should be queued + const secondRequestPromise = addRequest(config, 2000); + + // Advance timers to simulate part of the delay for the first request + jest.advanceTimersByTime(500); + + // Ensure the first request is being processed + expect(await getController(config)).toBeTruthy(); + + // Advance timers to complete the first request + jest.advanceTimersByTime(1500); + + // Ensure both requests are resolved + const firstRequestController = await firstRequestPromise; + const secondRequestController = await secondRequestPromise; + + // Check that controllers are distinct if they are meant to be different requests + // or the same if deduplication is in effect (depending on your implementation) + expect(firstRequestController).not.toBe(secondRequestController); + + // Ensure the queue is empty after processing both requests + expect(await getController(config)).toBeUndefined(); + }); + it('should clear timeout and abort request on removal', async () => { const configWithTimeout = createConfig('https://example.com'); await addRequest(configWithTimeout, 1000); @@ -90,6 +161,15 @@ describe('Request Queue Manager', () => { expect(controller1).not.toBe(controller2); }); + it('should not abort the request when timeout is disabled', async () => { + const controller = await addRequest(mockConfig, 0, 0, false, false); + + jest.advanceTimersByTime(1000); + + expect(controller.signal.aborted).toBe(false); + await removeRequest(mockConfig, null); + }); + it('should handle multiple distinct requests separately', async () => { const configA: RequestConfig = { url: 'https://example.com/a', @@ -106,51 +186,159 @@ describe('Request Queue Manager', () => { jest.advanceTimersByTime(1000); - // Ensure both requests have their own controllers expect(controllerA).not.toBe(controllerB); }); - it('should deduplicate requests and not abort if isCancellable is true', async () => { + it('should handle both timeout and cancellation correctly', async () => { + const config = createConfig('https://example.com'); + const timeout = 1000; + + // Add multiple requests + const controller1 = await addRequest(config, timeout, 1000, true); + const controller2 = await addRequest(config, timeout, 1000, true); + + // Advance timers to simulate timeout + jest.advanceTimersByTime(timeout + 500); + + expect(controller1.signal.aborted).toBe(true); + expect(controller2.signal.aborted).toBe(true); + }); + + it('should handle requests with the same configuration but different options correctly', async () => { + const config = createConfig('https://example.com'); + const controller1 = await addRequest(config, 2000, 1000, true); // Cancellable + const controller2 = await addRequest(config, 2000, 1000, false); // Not cancellable + + // Advance timers to simulate request handling + jest.advanceTimersByTime(1500); + + // Check that the cancellable request was aborted and non-cancellable was not + expect(controller1.signal.aborted).toBe(true); + expect(controller2.signal.aborted).toBe(false); + }); + + it('should handle request configuration changes correctly', async () => { + const config1 = createConfig('https://example.com'); + const config2 = createConfig('https://example.com'); + config2.method = 'POST'; // Change method to simulate different config + + // Add requests with different configurations + const controller1 = await addRequest(config1, 2000, 1000); + const controller2 = await addRequest(config2, 2000, 1000); + + // Advance timers to simulate request handling + jest.advanceTimersByTime(1500); + + expect(controller1).not.toBe(controller2); // Different configurations should not deduplicate + expect(controller1.signal.aborted).toBe(false); + expect(controller2.signal.aborted).toBe(false); + }); + + it('should cancel all previous requests if they are cancellable and deduplication time is not yet passed', async () => { const controller1 = await addRequest(mockConfig, 2000, 1000, true); const controller2 = await addRequest(mockConfig, 2000, 1000, true); + const controller3 = await addRequest(mockConfig, 2000, 1000, true); jest.advanceTimersByTime(500); - expect(controller1).toBe(controller2); - expect(controller1.signal.aborted).toBe(false); // Ensure the previous request was aborted - expect(controller2.signal.aborted).toBe(false); // Ensure the current request was not aborted - expect(controller2).toBeInstanceOf(AbortController); // Ensure new controller is created + expect(controller1).not.toBe(controller3); + expect(controller2).not.toBe(controller3); + expect(controller1.signal.aborted).toBe(true); + expect(controller2.signal.aborted).toBe(true); + expect(controller3.signal.aborted).toBe(false); + expect(controller3).toBeInstanceOf(AbortController); jest.spyOn(Date, 'now').mockRestore(); + await removeRequest(mockConfig); }); - it('should cancel the previous request if isCancellable is true', async () => { - const controllerA = await addRequest(mockConfig, 2000, 1000, true); + it('should cancel all previous requests if they are cancellable and deduplication time is passed', async () => { + const controller1 = await addRequest(mockConfig, 2000, 1000, true); + const controller2 = await addRequest(mockConfig, 2000, 1000, true); + const controller3 = await addRequest(mockConfig, 2000, 1000, true); jest.advanceTimersByTime(1500); - const controllerB = await addRequest(mockConfig, 2000, 1000, true); + expect(controller1).not.toBe(controller3); + expect(controller2).not.toBe(controller3); + expect(controller1.signal.aborted).toBe(true); + expect(controller2.signal.aborted).toBe(true); + expect(controller3.signal.aborted).toBe(false); + expect(controller3).toBeInstanceOf(AbortController); - expect(controllerA).not.toBe(controllerB); - expect(controllerA.signal.aborted).toBe(true); // Ensure the previous request was aborted - expect(controllerB.signal.aborted).toBe(false); // Ensure the current request was not aborted - expect(controllerB).toBeInstanceOf(AbortController); // Ensure new controller is created + jest.spyOn(Date, 'now').mockRestore(); + await removeRequest(mockConfig); + }); + + it('should cancel all requests if they are cancellable and timeout is passed', async () => { + const controller1 = await addRequest(mockConfig, 2000, 1000, true); + const controller2 = await addRequest(mockConfig, 2000, 1000, true); + const controller3 = await addRequest(mockConfig, 2000, 1000, true); + + jest.advanceTimersByTime(2500); + + expect(controller1).not.toBe(controller3); + expect(controller2).not.toBe(controller3); + expect(controller1.signal.aborted).toBe(true); + expect(controller2.signal.aborted).toBe(true); + expect(controller3.signal.aborted).toBe(true); + expect(controller3).toBeInstanceOf(AbortController); + + jest.spyOn(Date, 'now').mockRestore(); + await removeRequest(mockConfig); + }); + + it('should not cancel any request if not cancellable and deduplication time is not yet passed', async () => { + const controller1 = await addRequest(mockConfig, 2000, 1000, false); + const controller2 = await addRequest(mockConfig, 2000, 1000, false); + const controller3 = await addRequest(mockConfig, 2000, 1000, false); + + jest.advanceTimersByTime(500); + + expect(controller1).toBe(controller3); + expect(controller2).toBe(controller3); + expect(controller1.signal.aborted).toBe(false); + expect(controller2.signal.aborted).toBe(false); + expect(controller3.signal.aborted).toBe(false); + expect(controller3).toBeInstanceOf(AbortController); + + jest.spyOn(Date, 'now').mockRestore(); + await removeRequest(mockConfig); + }); + + it('should not cancel any request if not cancellable and deduplication time is passed for each request', async () => { + const controller1 = await addRequest(mockConfig, 20000, 1000, false); + jest.advanceTimersByTime(1500); + const controller2 = await addRequest(mockConfig, 20000, 1000, false); + jest.advanceTimersByTime(1500); + const controller3 = await addRequest(mockConfig, 20000, 1000, false); + jest.advanceTimersByTime(1500); + + expect(controller1).not.toBe(controller3); + expect(controller1).not.toBe(controller2); + expect(controller2).not.toBe(controller3); + expect(controller1.signal.aborted).toBe(false); + expect(controller2.signal.aborted).toBe(false); + expect(controller3.signal.aborted).toBe(false); + expect(controller3).toBeInstanceOf(AbortController); jest.spyOn(Date, 'now').mockRestore(); + await removeRequest(mockConfig); }); - it('should not cancel the previous request if isCancellable is false', async () => { - const controllerA = await addRequest(mockConfig, 2000, 1000, true); + it('should not cancel the previous requests if they are not cancellable', async () => { + const controller1 = await addRequest(mockConfig, 2000, 1000, false); jest.advanceTimersByTime(1500); - const controllerB = await addRequest(mockConfig, 2000, 1000, false); + const controller2 = await addRequest(mockConfig, 2000, 1000, true); - expect(controllerA).not.toBe(controllerB); - expect(controllerA.signal.aborted).toBe(false); // Ensure the previous request was aborted - expect(controllerB.signal.aborted).toBe(false); // Ensure the current request was not aborted - expect(controllerB).toBeInstanceOf(AbortController); // Ensure new controller is created + expect(controller1).not.toBe(controller2); + expect(controller1.signal.aborted).toBe(false); + expect(controller2.signal.aborted).toBe(false); + expect(controller2).toBeInstanceOf(AbortController); jest.spyOn(Date, 'now').mockRestore(); + await removeRequest(mockConfig); }); }); From d83c20a22cc3e4744d9219da0ec57cc130b6eee6 Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 17 Sep 2024 00:42:01 +0200 Subject: [PATCH 17/18] feat: Add Accept-Encoding headers with brotli compression enabled by default --- src/request-handler.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/request-handler.ts b/src/request-handler.ts index db95869..07522de 100644 --- a/src/request-handler.ts +++ b/src/request-handler.ts @@ -206,6 +206,7 @@ function createRequestHandler( // Add sensible defaults headers: { Accept: APPLICATION_JSON + ', text/plain, */*', + 'Accept-Encoding': 'gzip, deflate, br', [CONTENT_TYPE]: APPLICATION_JSON + ';charset=utf-8', ...(handlerConfig.headers || {}), ...(reqConfig.headers || {}), From 0b73bbf6109ab4b78c7ef7a1245ab6576f964ded Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 17 Sep 2024 00:51:23 +0200 Subject: [PATCH 18/18] test: Add new header --- test/request-handler.spec.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/request-handler.spec.ts b/test/request-handler.spec.ts index 3be2b29..a68eec2 100644 --- a/test/request-handler.spec.ts +++ b/test/request-handler.spec.ts @@ -97,6 +97,7 @@ describe('Request Handler', () => { method: 'GET', headers: { Accept: 'application/json, text/plain, */*', + 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/json;charset=utf-8', }, }); @@ -115,6 +116,7 @@ describe('Request Handler', () => { method: 'POST', headers: { Accept: 'application/json, text/plain, */*', + 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/json;charset=utf-8', }, body: JSON.stringify({ foo: 'bar' }), @@ -134,6 +136,7 @@ describe('Request Handler', () => { method: 'PUT', headers: { Accept: 'application/json, text/plain, */*', + 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/json;charset=utf-8', }, body: JSON.stringify({ foo: 'bar' }), @@ -153,6 +156,7 @@ describe('Request Handler', () => { method: 'DELETE', headers: { Accept: 'application/json, text/plain, */*', + 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/json;charset=utf-8', }, body: JSON.stringify({ foo: 'bar' }), @@ -175,6 +179,7 @@ describe('Request Handler', () => { method: 'POST', headers: { Accept: 'application/json, text/plain, */*', + 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/json;charset=utf-8', Authorization: 'Bearer token', }, @@ -190,6 +195,7 @@ describe('Request Handler', () => { method: 'POST', headers: { Accept: 'application/json, text/plain, */*', + 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/json;charset=utf-8', }, body: null, @@ -209,6 +215,7 @@ describe('Request Handler', () => { method: 'POST', headers: { Accept: 'application/json, text/plain, */*', + 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/json;charset=utf-8', }, body: 'rawData', @@ -228,6 +235,7 @@ describe('Request Handler', () => { method: 'HEAD', headers: { Accept: 'application/json, text/plain, */*', + 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/json;charset=utf-8', }, }); @@ -246,6 +254,7 @@ describe('Request Handler', () => { method: 'POST', headers: { Accept: 'application/json, text/plain, */*', + 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/json;charset=utf-8', }, body: JSON.stringify({ additional: 'info' }), @@ -262,6 +271,7 @@ describe('Request Handler', () => { method: 'POST', headers: { Accept: 'application/json, text/plain, */*', + 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/json;charset=utf-8', }, credentials: 'include', @@ -284,6 +294,7 @@ describe('Request Handler', () => { method: 'POST', headers: { Accept: 'application/json, text/plain, */*', + 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/json;charset=utf-8', }, body: JSON.stringify({ foo: 'bar' }), @@ -303,6 +314,7 @@ describe('Request Handler', () => { method: 'GET', headers: { Accept: 'application/json, text/plain, */*', + 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/json;charset=utf-8', }, });