diff --git a/ratelimit/ts/biome.json b/ratelimit/ts/biome.json index 2eb0751..c2974e4 100644 --- a/ratelimit/ts/biome.json +++ b/ratelimit/ts/biome.json @@ -1,30 +1,30 @@ { - "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", - "vcs": { - "enabled": false, - "clientKind": "git", - "useIgnoreFile": false - }, - "files": { - "ignoreUnknown": false, - "ignore": [] - }, - "formatter": { - "enabled": true, - "indentStyle": "tab" - }, - "organizeImports": { - "enabled": true - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true - } - }, - "javascript": { - "formatter": { - "quoteStyle": "double" - } - } + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "ignoreUnknown": false, + "ignore": [] + }, + "formatter": { + "enabled": true, + "indentStyle": "tab" + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double" + } + } } diff --git a/ratelimit/ts/package.json b/ratelimit/ts/package.json index 6da49f1..53ec677 100644 --- a/ratelimit/ts/package.json +++ b/ratelimit/ts/package.json @@ -1,6 +1,6 @@ { "name": "@unkey/ratelimit", - "version": "2.1.2", + "version": "2.1.3", "main": "./dist/index.js", "module": "./dist/index.mjs", "types": "./dist/index.d.ts", @@ -26,13 +26,16 @@ "author": "Andreas Thomas ", "scripts": { "build": "tsup", - "fmt": "bunx biome check ." + "fmt": "bunx biome check .", + "test": "vitest run" }, "devDependencies": { "@biomejs/biome": "2.1.3", "@types/node": "^24.2.0", + "msw": "^2.10.5", "tsup": "^8.0.2", - "typescript": "^5.9.2" + "typescript": "^5.9.2", + "vitest": "^3.2.4" }, "dependencies": { "@unkey/api": "2.0.3" diff --git a/ratelimit/ts/pnpm-lock.yaml b/ratelimit/ts/pnpm-lock.yaml index c435670..8bbaf48 100644 --- a/ratelimit/ts/pnpm-lock.yaml +++ b/ratelimit/ts/pnpm-lock.yaml @@ -1,48 +1,59 @@ -lockfileVersion: '6.0' +lockfileVersion: "6.0" settings: autoInstallPeers: true excludeLinksFromLockfile: false dependencies: - '@unkey/api': + "@unkey/api": specifier: 2.0.3 version: 2.0.3 devDependencies: - '@biomejs/biome': + "@biomejs/biome": specifier: 2.1.3 version: 2.1.3 - '@types/node': + "@types/node": specifier: ^24.2.0 version: 24.2.0 + msw: + specifier: ^2.10.5 + version: 2.10.5(@types/node@24.2.0)(typescript@5.9.2) tsup: specifier: ^8.0.2 version: 8.5.0(typescript@5.9.2) typescript: specifier: ^5.9.2 version: 5.9.2 + vitest: + specifier: ^3.2.4 + version: 3.2.4(@types/node@24.2.0)(msw@2.10.5) packages: - /@biomejs/biome@2.1.3: - resolution: {integrity: sha512-KE/tegvJIxTkl7gJbGWSgun7G6X/n2M6C35COT6ctYrAy7SiPyNvi6JtoQERVK/VRbttZfgGq96j2bFmhmnH4w==} - engines: {node: '>=14.21.3'} + resolution: + { + integrity: sha512-KE/tegvJIxTkl7gJbGWSgun7G6X/n2M6C35COT6ctYrAy7SiPyNvi6JtoQERVK/VRbttZfgGq96j2bFmhmnH4w==, + } + engines: { node: ">=14.21.3" } hasBin: true optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.1.3 - '@biomejs/cli-darwin-x64': 2.1.3 - '@biomejs/cli-linux-arm64': 2.1.3 - '@biomejs/cli-linux-arm64-musl': 2.1.3 - '@biomejs/cli-linux-x64': 2.1.3 - '@biomejs/cli-linux-x64-musl': 2.1.3 - '@biomejs/cli-win32-arm64': 2.1.3 - '@biomejs/cli-win32-x64': 2.1.3 + "@biomejs/cli-darwin-arm64": 2.1.3 + "@biomejs/cli-darwin-x64": 2.1.3 + "@biomejs/cli-linux-arm64": 2.1.3 + "@biomejs/cli-linux-arm64-musl": 2.1.3 + "@biomejs/cli-linux-x64": 2.1.3 + "@biomejs/cli-linux-x64-musl": 2.1.3 + "@biomejs/cli-win32-arm64": 2.1.3 + "@biomejs/cli-win32-x64": 2.1.3 dev: true /@biomejs/cli-darwin-arm64@2.1.3: - resolution: {integrity: sha512-LFLkSWRoSGS1wVUD/BE6Nlt2dSn0ulH3XImzg2O/36BoToJHKXjSxzPEMAqT9QvwVtk7/9AQhZpTneERU9qaXA==} - engines: {node: '>=14.21.3'} + resolution: + { + integrity: sha512-LFLkSWRoSGS1wVUD/BE6Nlt2dSn0ulH3XImzg2O/36BoToJHKXjSxzPEMAqT9QvwVtk7/9AQhZpTneERU9qaXA==, + } + engines: { node: ">=14.21.3" } cpu: [arm64] os: [darwin] requiresBuild: true @@ -50,8 +61,11 @@ packages: optional: true /@biomejs/cli-darwin-x64@2.1.3: - resolution: {integrity: sha512-Q/4OTw8P9No9QeowyxswcWdm0n2MsdCwWcc5NcKQQvzwPjwuPdf8dpPPf4r+x0RWKBtl1FLiAUtJvBlri6DnYw==} - engines: {node: '>=14.21.3'} + resolution: + { + integrity: sha512-Q/4OTw8P9No9QeowyxswcWdm0n2MsdCwWcc5NcKQQvzwPjwuPdf8dpPPf4r+x0RWKBtl1FLiAUtJvBlri6DnYw==, + } + engines: { node: ">=14.21.3" } cpu: [x64] os: [darwin] requiresBuild: true @@ -59,8 +73,11 @@ packages: optional: true /@biomejs/cli-linux-arm64-musl@2.1.3: - resolution: {integrity: sha512-KXouFSBnoxAWZYDQrnNRzZBbt5s9UJkIm40hdvSL9mBxSSoxRFQJbtg1hP3aa8A2SnXyQHxQfpiVeJlczZt76w==} - engines: {node: '>=14.21.3'} + resolution: + { + integrity: sha512-KXouFSBnoxAWZYDQrnNRzZBbt5s9UJkIm40hdvSL9mBxSSoxRFQJbtg1hP3aa8A2SnXyQHxQfpiVeJlczZt76w==, + } + engines: { node: ">=14.21.3" } cpu: [arm64] os: [linux] requiresBuild: true @@ -68,8 +85,11 @@ packages: optional: true /@biomejs/cli-linux-arm64@2.1.3: - resolution: {integrity: sha512-2hS6LgylRqMFmAZCOFwYrf77QMdUwJp49oe8PX/O8+P2yKZMSpyQTf3Eo5ewnsMFUEmYbPOskafdV1ds1MZMJA==} - engines: {node: '>=14.21.3'} + resolution: + { + integrity: sha512-2hS6LgylRqMFmAZCOFwYrf77QMdUwJp49oe8PX/O8+P2yKZMSpyQTf3Eo5ewnsMFUEmYbPOskafdV1ds1MZMJA==, + } + engines: { node: ">=14.21.3" } cpu: [arm64] os: [linux] requiresBuild: true @@ -77,8 +97,11 @@ packages: optional: true /@biomejs/cli-linux-x64-musl@2.1.3: - resolution: {integrity: sha512-KaLAxnROouzIWtl6a0Y88r/4hW5oDUJTIqQorOTVQITaKQsKjZX4XCUmHIhdEk8zMnaiLZzRTAwk1yIAl+mIew==} - engines: {node: '>=14.21.3'} + resolution: + { + integrity: sha512-KaLAxnROouzIWtl6a0Y88r/4hW5oDUJTIqQorOTVQITaKQsKjZX4XCUmHIhdEk8zMnaiLZzRTAwk1yIAl+mIew==, + } + engines: { node: ">=14.21.3" } cpu: [x64] os: [linux] requiresBuild: true @@ -86,8 +109,11 @@ packages: optional: true /@biomejs/cli-linux-x64@2.1.3: - resolution: {integrity: sha512-NxlSCBhLvQtWGagEztfAZ4WcE1AkMTntZV65ZvR+J9jp06+EtOYEBPQndA70ZGhHbEDG57bR6uNvqkd1WrEYVA==} - engines: {node: '>=14.21.3'} + resolution: + { + integrity: sha512-NxlSCBhLvQtWGagEztfAZ4WcE1AkMTntZV65ZvR+J9jp06+EtOYEBPQndA70ZGhHbEDG57bR6uNvqkd1WrEYVA==, + } + engines: { node: ">=14.21.3" } cpu: [x64] os: [linux] requiresBuild: true @@ -95,8 +121,11 @@ packages: optional: true /@biomejs/cli-win32-arm64@2.1.3: - resolution: {integrity: sha512-V9CUZCtWH4u0YwyCYbQ3W5F4ZGPWp2C2TYcsiWFNNyRfmOW1j/TY/jAurl33SaRjgZPO5UUhGyr9m6BN9t84NQ==} - engines: {node: '>=14.21.3'} + resolution: + { + integrity: sha512-V9CUZCtWH4u0YwyCYbQ3W5F4ZGPWp2C2TYcsiWFNNyRfmOW1j/TY/jAurl33SaRjgZPO5UUhGyr9m6BN9t84NQ==, + } + engines: { node: ">=14.21.3" } cpu: [arm64] os: [win32] requiresBuild: true @@ -104,17 +133,51 @@ packages: optional: true /@biomejs/cli-win32-x64@2.1.3: - resolution: {integrity: sha512-dxy599q6lgp8ANPpR8sDMscwdp9oOumEsVXuVCVT9N2vAho8uYXlCz53JhxX6LtJOXaE73qzgkGQ7QqvFlMC0g==} - engines: {node: '>=14.21.3'} + resolution: + { + integrity: sha512-dxy599q6lgp8ANPpR8sDMscwdp9oOumEsVXuVCVT9N2vAho8uYXlCz53JhxX6LtJOXaE73qzgkGQ7QqvFlMC0g==, + } + engines: { node: ">=14.21.3" } cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true + /@bundled-es-modules/cookie@2.0.1: + resolution: + { + integrity: sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==, + } + dependencies: + cookie: 0.7.2 + dev: true + + /@bundled-es-modules/statuses@1.0.1: + resolution: + { + integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==, + } + dependencies: + statuses: 2.0.2 + dev: true + + /@bundled-es-modules/tough-cookie@0.1.6: + resolution: + { + integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==, + } + dependencies: + "@types/tough-cookie": 4.0.5 + tough-cookie: 4.1.4 + dev: true + /@esbuild/aix-ppc64@0.25.8: - resolution: {integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==, + } + engines: { node: ">=18" } cpu: [ppc64] os: [aix] requiresBuild: true @@ -122,8 +185,11 @@ packages: optional: true /@esbuild/android-arm64@0.25.8: - resolution: {integrity: sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==, + } + engines: { node: ">=18" } cpu: [arm64] os: [android] requiresBuild: true @@ -131,8 +197,11 @@ packages: optional: true /@esbuild/android-arm@0.25.8: - resolution: {integrity: sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==, + } + engines: { node: ">=18" } cpu: [arm] os: [android] requiresBuild: true @@ -140,8 +209,11 @@ packages: optional: true /@esbuild/android-x64@0.25.8: - resolution: {integrity: sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==, + } + engines: { node: ">=18" } cpu: [x64] os: [android] requiresBuild: true @@ -149,8 +221,11 @@ packages: optional: true /@esbuild/darwin-arm64@0.25.8: - resolution: {integrity: sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==, + } + engines: { node: ">=18" } cpu: [arm64] os: [darwin] requiresBuild: true @@ -158,8 +233,11 @@ packages: optional: true /@esbuild/darwin-x64@0.25.8: - resolution: {integrity: sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==, + } + engines: { node: ">=18" } cpu: [x64] os: [darwin] requiresBuild: true @@ -167,8 +245,11 @@ packages: optional: true /@esbuild/freebsd-arm64@0.25.8: - resolution: {integrity: sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==, + } + engines: { node: ">=18" } cpu: [arm64] os: [freebsd] requiresBuild: true @@ -176,8 +257,11 @@ packages: optional: true /@esbuild/freebsd-x64@0.25.8: - resolution: {integrity: sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==, + } + engines: { node: ">=18" } cpu: [x64] os: [freebsd] requiresBuild: true @@ -185,8 +269,11 @@ packages: optional: true /@esbuild/linux-arm64@0.25.8: - resolution: {integrity: sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==, + } + engines: { node: ">=18" } cpu: [arm64] os: [linux] requiresBuild: true @@ -194,8 +281,11 @@ packages: optional: true /@esbuild/linux-arm@0.25.8: - resolution: {integrity: sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==, + } + engines: { node: ">=18" } cpu: [arm] os: [linux] requiresBuild: true @@ -203,8 +293,11 @@ packages: optional: true /@esbuild/linux-ia32@0.25.8: - resolution: {integrity: sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==, + } + engines: { node: ">=18" } cpu: [ia32] os: [linux] requiresBuild: true @@ -212,8 +305,11 @@ packages: optional: true /@esbuild/linux-loong64@0.25.8: - resolution: {integrity: sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==, + } + engines: { node: ">=18" } cpu: [loong64] os: [linux] requiresBuild: true @@ -221,8 +317,11 @@ packages: optional: true /@esbuild/linux-mips64el@0.25.8: - resolution: {integrity: sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==, + } + engines: { node: ">=18" } cpu: [mips64el] os: [linux] requiresBuild: true @@ -230,8 +329,11 @@ packages: optional: true /@esbuild/linux-ppc64@0.25.8: - resolution: {integrity: sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==, + } + engines: { node: ">=18" } cpu: [ppc64] os: [linux] requiresBuild: true @@ -239,8 +341,11 @@ packages: optional: true /@esbuild/linux-riscv64@0.25.8: - resolution: {integrity: sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==, + } + engines: { node: ">=18" } cpu: [riscv64] os: [linux] requiresBuild: true @@ -248,8 +353,11 @@ packages: optional: true /@esbuild/linux-s390x@0.25.8: - resolution: {integrity: sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==, + } + engines: { node: ">=18" } cpu: [s390x] os: [linux] requiresBuild: true @@ -257,8 +365,11 @@ packages: optional: true /@esbuild/linux-x64@0.25.8: - resolution: {integrity: sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==, + } + engines: { node: ">=18" } cpu: [x64] os: [linux] requiresBuild: true @@ -266,8 +377,11 @@ packages: optional: true /@esbuild/netbsd-arm64@0.25.8: - resolution: {integrity: sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==, + } + engines: { node: ">=18" } cpu: [arm64] os: [netbsd] requiresBuild: true @@ -275,8 +389,11 @@ packages: optional: true /@esbuild/netbsd-x64@0.25.8: - resolution: {integrity: sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==, + } + engines: { node: ">=18" } cpu: [x64] os: [netbsd] requiresBuild: true @@ -284,8 +401,11 @@ packages: optional: true /@esbuild/openbsd-arm64@0.25.8: - resolution: {integrity: sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==, + } + engines: { node: ">=18" } cpu: [arm64] os: [openbsd] requiresBuild: true @@ -293,8 +413,11 @@ packages: optional: true /@esbuild/openbsd-x64@0.25.8: - resolution: {integrity: sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==, + } + engines: { node: ">=18" } cpu: [x64] os: [openbsd] requiresBuild: true @@ -302,8 +425,11 @@ packages: optional: true /@esbuild/openharmony-arm64@0.25.8: - resolution: {integrity: sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==, + } + engines: { node: ">=18" } cpu: [arm64] os: [openharmony] requiresBuild: true @@ -311,8 +437,11 @@ packages: optional: true /@esbuild/sunos-x64@0.25.8: - resolution: {integrity: sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==, + } + engines: { node: ">=18" } cpu: [x64] os: [sunos] requiresBuild: true @@ -320,8 +449,11 @@ packages: optional: true /@esbuild/win32-arm64@0.25.8: - resolution: {integrity: sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==, + } + engines: { node: ">=18" } cpu: [arm64] os: [win32] requiresBuild: true @@ -329,8 +461,11 @@ packages: optional: true /@esbuild/win32-ia32@0.25.8: - resolution: {integrity: sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==, + } + engines: { node: ">=18" } cpu: [ia32] os: [win32] requiresBuild: true @@ -338,17 +473,86 @@ packages: optional: true /@esbuild/win32-x64@0.25.8: - resolution: {integrity: sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==, + } + engines: { node: ">=18" } cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true + /@inquirer/confirm@5.1.15(@types/node@24.2.0): + resolution: + { + integrity: sha512-SwHMGa8Z47LawQN0rog0sT+6JpiL0B7eW9p1Bb7iCeKDGTI5Ez25TSc2l8kw52VV7hA4sX/C78CGkMrKXfuspA==, + } + engines: { node: ">=18" } + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + dependencies: + "@inquirer/core": 10.1.15(@types/node@24.2.0) + "@inquirer/type": 3.0.8(@types/node@24.2.0) + "@types/node": 24.2.0 + dev: true + + /@inquirer/core@10.1.15(@types/node@24.2.0): + resolution: + { + integrity: sha512-8xrp836RZvKkpNbVvgWUlxjT4CraKk2q+I3Ksy+seI2zkcE+y6wNs1BVhgcv8VyImFecUhdQrYLdW32pAjwBdA==, + } + engines: { node: ">=18" } + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + dependencies: + "@inquirer/figures": 1.0.13 + "@inquirer/type": 3.0.8(@types/node@24.2.0) + "@types/node": 24.2.0 + ansi-escapes: 4.3.2 + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.2 + dev: true + + /@inquirer/figures@1.0.13: + resolution: + { + integrity: sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==, + } + engines: { node: ">=18" } + dev: true + + /@inquirer/type@3.0.8(@types/node@24.2.0): + resolution: + { + integrity: sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==, + } + engines: { node: ">=18" } + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + dependencies: + "@types/node": 24.2.0 + dev: true + /@isaacs/cliui@8.0.2: - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, + } + engines: { node: ">=12" } dependencies: string-width: 5.1.2 string-width-cjs: /string-width@4.2.3 @@ -359,37 +563,94 @@ packages: dev: true /@jridgewell/gen-mapping@0.3.12: - resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} + resolution: + { + integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==, + } dependencies: - '@jridgewell/sourcemap-codec': 1.5.4 - '@jridgewell/trace-mapping': 0.3.29 + "@jridgewell/sourcemap-codec": 1.5.4 + "@jridgewell/trace-mapping": 0.3.29 dev: true /@jridgewell/resolve-uri@3.1.2: - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} + resolution: + { + integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, + } + engines: { node: ">=6.0.0" } dev: true /@jridgewell/sourcemap-codec@1.5.4: - resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} + resolution: + { + integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==, + } dev: true /@jridgewell/trace-mapping@0.3.29: - resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} + resolution: + { + integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==, + } + dependencies: + "@jridgewell/resolve-uri": 3.1.2 + "@jridgewell/sourcemap-codec": 1.5.4 + dev: true + + /@mswjs/interceptors@0.39.6: + resolution: + { + integrity: sha512-bndDP83naYYkfayr/qhBHMhk0YGwS1iv6vaEGcr0SQbO0IZtbOPqjKjds/WcG+bJA+1T5vCx6kprKOzn5Bg+Vw==, + } + engines: { node: ">=18" } + dependencies: + "@open-draft/deferred-promise": 2.2.0 + "@open-draft/logger": 0.3.0 + "@open-draft/until": 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 + dev: true + + /@open-draft/deferred-promise@2.2.0: + resolution: + { + integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==, + } + dev: true + + /@open-draft/logger@0.3.0: + resolution: + { + integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==, + } dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.4 + is-node-process: 1.2.0 + outvariant: 1.4.3 + dev: true + + /@open-draft/until@2.1.0: + resolution: + { + integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==, + } dev: true /@pkgjs/parseargs@0.11.0: - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} + resolution: + { + integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==, + } + engines: { node: ">=14" } requiresBuild: true dev: true optional: true /@rollup/rollup-android-arm-eabi@4.45.1: - resolution: {integrity: sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==} + resolution: + { + integrity: sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==, + } cpu: [arm] os: [android] requiresBuild: true @@ -397,7 +658,10 @@ packages: optional: true /@rollup/rollup-android-arm64@4.45.1: - resolution: {integrity: sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==} + resolution: + { + integrity: sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==, + } cpu: [arm64] os: [android] requiresBuild: true @@ -405,7 +669,10 @@ packages: optional: true /@rollup/rollup-darwin-arm64@4.45.1: - resolution: {integrity: sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==} + resolution: + { + integrity: sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==, + } cpu: [arm64] os: [darwin] requiresBuild: true @@ -413,7 +680,10 @@ packages: optional: true /@rollup/rollup-darwin-x64@4.45.1: - resolution: {integrity: sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==} + resolution: + { + integrity: sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==, + } cpu: [x64] os: [darwin] requiresBuild: true @@ -421,7 +691,10 @@ packages: optional: true /@rollup/rollup-freebsd-arm64@4.45.1: - resolution: {integrity: sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==} + resolution: + { + integrity: sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==, + } cpu: [arm64] os: [freebsd] requiresBuild: true @@ -429,7 +702,10 @@ packages: optional: true /@rollup/rollup-freebsd-x64@4.45.1: - resolution: {integrity: sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==} + resolution: + { + integrity: sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==, + } cpu: [x64] os: [freebsd] requiresBuild: true @@ -437,7 +713,10 @@ packages: optional: true /@rollup/rollup-linux-arm-gnueabihf@4.45.1: - resolution: {integrity: sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==} + resolution: + { + integrity: sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==, + } cpu: [arm] os: [linux] requiresBuild: true @@ -445,7 +724,10 @@ packages: optional: true /@rollup/rollup-linux-arm-musleabihf@4.45.1: - resolution: {integrity: sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==} + resolution: + { + integrity: sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==, + } cpu: [arm] os: [linux] requiresBuild: true @@ -453,7 +735,10 @@ packages: optional: true /@rollup/rollup-linux-arm64-gnu@4.45.1: - resolution: {integrity: sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==} + resolution: + { + integrity: sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==, + } cpu: [arm64] os: [linux] requiresBuild: true @@ -461,7 +746,10 @@ packages: optional: true /@rollup/rollup-linux-arm64-musl@4.45.1: - resolution: {integrity: sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==} + resolution: + { + integrity: sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==, + } cpu: [arm64] os: [linux] requiresBuild: true @@ -469,7 +757,10 @@ packages: optional: true /@rollup/rollup-linux-loongarch64-gnu@4.45.1: - resolution: {integrity: sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==} + resolution: + { + integrity: sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==, + } cpu: [loong64] os: [linux] requiresBuild: true @@ -477,7 +768,10 @@ packages: optional: true /@rollup/rollup-linux-powerpc64le-gnu@4.45.1: - resolution: {integrity: sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==} + resolution: + { + integrity: sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==, + } cpu: [ppc64] os: [linux] requiresBuild: true @@ -485,7 +779,10 @@ packages: optional: true /@rollup/rollup-linux-riscv64-gnu@4.45.1: - resolution: {integrity: sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==} + resolution: + { + integrity: sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==, + } cpu: [riscv64] os: [linux] requiresBuild: true @@ -493,7 +790,10 @@ packages: optional: true /@rollup/rollup-linux-riscv64-musl@4.45.1: - resolution: {integrity: sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==} + resolution: + { + integrity: sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==, + } cpu: [riscv64] os: [linux] requiresBuild: true @@ -501,7 +801,10 @@ packages: optional: true /@rollup/rollup-linux-s390x-gnu@4.45.1: - resolution: {integrity: sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==} + resolution: + { + integrity: sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==, + } cpu: [s390x] os: [linux] requiresBuild: true @@ -509,7 +812,10 @@ packages: optional: true /@rollup/rollup-linux-x64-gnu@4.45.1: - resolution: {integrity: sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==} + resolution: + { + integrity: sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==, + } cpu: [x64] os: [linux] requiresBuild: true @@ -517,7 +823,10 @@ packages: optional: true /@rollup/rollup-linux-x64-musl@4.45.1: - resolution: {integrity: sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==} + resolution: + { + integrity: sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==, + } cpu: [x64] os: [linux] requiresBuild: true @@ -525,7 +834,10 @@ packages: optional: true /@rollup/rollup-win32-arm64-msvc@4.45.1: - resolution: {integrity: sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==} + resolution: + { + integrity: sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==, + } cpu: [arm64] os: [win32] requiresBuild: true @@ -533,7 +845,10 @@ packages: optional: true /@rollup/rollup-win32-ia32-msvc@4.45.1: - resolution: {integrity: sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==} + resolution: + { + integrity: sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==, + } cpu: [ia32] os: [win32] requiresBuild: true @@ -541,127 +856,380 @@ packages: optional: true /@rollup/rollup-win32-x64-msvc@4.45.1: - resolution: {integrity: sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==} + resolution: + { + integrity: sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==, + } cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true + /@types/chai@5.2.2: + resolution: + { + integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==, + } + dependencies: + "@types/deep-eql": 4.0.2 + dev: true + + /@types/cookie@0.6.0: + resolution: + { + integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==, + } + dev: true + + /@types/deep-eql@4.0.2: + resolution: + { + integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==, + } + dev: true + /@types/estree@1.0.8: - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + resolution: + { + integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==, + } dev: true /@types/node@24.2.0: - resolution: {integrity: sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw==} + resolution: + { + integrity: sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw==, + } dependencies: undici-types: 7.10.0 dev: true + /@types/statuses@2.0.6: + resolution: + { + integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==, + } + dev: true + + /@types/tough-cookie@4.0.5: + resolution: + { + integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==, + } + dev: true + /@unkey/api@2.0.3: - resolution: {integrity: sha512-ru+I//qmSTBcZUTV43Pb4LF3JWLgcvXe8/MQKQZV2tA5Ypw61rFwIiOzNM1qKjB4erunFuv7I86/MTCdqfb0eA==} + resolution: + { + integrity: sha512-ru+I//qmSTBcZUTV43Pb4LF3JWLgcvXe8/MQKQZV2tA5Ypw61rFwIiOzNM1qKjB4erunFuv7I86/MTCdqfb0eA==, + } hasBin: true peerDependencies: - '@modelcontextprotocol/sdk': '>=1.5.0 <1.10.0' + "@modelcontextprotocol/sdk": ">=1.5.0 <1.10.0" peerDependenciesMeta: - '@modelcontextprotocol/sdk': + "@modelcontextprotocol/sdk": optional: true dependencies: zod: 3.25.76 dev: false + /@vitest/expect@3.2.4: + resolution: + { + integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==, + } + dependencies: + "@types/chai": 5.2.2 + "@vitest/spy": 3.2.4 + "@vitest/utils": 3.2.4 + chai: 5.3.1 + tinyrainbow: 2.0.0 + dev: true + + /@vitest/mocker@3.2.4(msw@2.10.5)(vite@7.1.3): + resolution: + { + integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==, + } + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + dependencies: + "@vitest/spy": 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.17 + msw: 2.10.5(@types/node@24.2.0)(typescript@5.9.2) + vite: 7.1.3(@types/node@24.2.0) + dev: true + + /@vitest/pretty-format@3.2.4: + resolution: + { + integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==, + } + dependencies: + tinyrainbow: 2.0.0 + dev: true + + /@vitest/runner@3.2.4: + resolution: + { + integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==, + } + dependencies: + "@vitest/utils": 3.2.4 + pathe: 2.0.3 + strip-literal: 3.0.0 + dev: true + + /@vitest/snapshot@3.2.4: + resolution: + { + integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==, + } + dependencies: + "@vitest/pretty-format": 3.2.4 + magic-string: 0.30.17 + pathe: 2.0.3 + dev: true + + /@vitest/spy@3.2.4: + resolution: + { + integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==, + } + dependencies: + tinyspy: 4.0.3 + dev: true + + /@vitest/utils@3.2.4: + resolution: + { + integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==, + } + dependencies: + "@vitest/pretty-format": 3.2.4 + loupe: 3.2.0 + tinyrainbow: 2.0.0 + dev: true + /acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} - engines: {node: '>=0.4.0'} + resolution: + { + integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==, + } + engines: { node: ">=0.4.0" } hasBin: true dev: true + /ansi-escapes@4.3.2: + resolution: + { + integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==, + } + engines: { node: ">=8" } + dependencies: + type-fest: 0.21.3 + dev: true + /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, + } + engines: { node: ">=8" } dev: true /ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==, + } + engines: { node: ">=12" } dev: true /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, + } + engines: { node: ">=8" } dependencies: color-convert: 2.0.1 dev: true /ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==, + } + engines: { node: ">=12" } dev: true /any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + resolution: + { + integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==, + } + dev: true + + /assertion-error@2.0.1: + resolution: + { + integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==, + } + engines: { node: ">=12" } dev: true /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + resolution: + { + integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, + } dev: true /brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + resolution: + { + integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==, + } dependencies: balanced-match: 1.0.2 dev: true /bundle-require@5.1.0(esbuild@0.25.8): - resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + resolution: + { + integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } peerDependencies: - esbuild: '>=0.18' + esbuild: ">=0.18" dependencies: esbuild: 0.25.8 load-tsconfig: 0.2.5 dev: true /cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==, + } + engines: { node: ">=8" } + dev: true + + /chai@5.3.1: + resolution: + { + integrity: sha512-48af6xm9gQK8rhIcOxWwdGzIervm8BVTin+yRp9HEvU20BtVZ2lBywlIJBzwaDtvo0FvjeL7QdCADoUoqIbV3A==, + } + engines: { node: ">=18" } + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.2.0 + pathval: 2.0.1 + dev: true + + /check-error@2.1.1: + resolution: + { + integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==, + } + engines: { node: ">= 16" } dev: true /chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} + resolution: + { + integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==, + } + engines: { node: ">= 14.16.0" } dependencies: readdirp: 4.1.2 dev: true + /cli-width@4.1.0: + resolution: + { + integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==, + } + engines: { node: ">= 12" } + dev: true + + /cliui@8.0.1: + resolution: + { + integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==, + } + engines: { node: ">=12" } + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + resolution: + { + integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, + } + engines: { node: ">=7.0.0" } dependencies: color-name: 1.1.4 dev: true /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + resolution: + { + integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, + } dev: true /commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==, + } + engines: { node: ">= 6" } dev: true /confbox@0.1.8: - resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + resolution: + { + integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==, + } dev: true /consola@3.4.2: - resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} - engines: {node: ^14.18.0 || >=16.10.0} + resolution: + { + integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==, + } + engines: { node: ^14.18.0 || >=16.10.0 } + dev: true + + /cookie@0.7.2: + resolution: + { + integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==, + } + engines: { node: ">= 0.6" } dev: true /cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==, + } + engines: { node: ">= 8" } dependencies: path-key: 3.1.1 shebang-command: 2.0.0 @@ -669,10 +1237,13 @@ packages: dev: true /debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} - engines: {node: '>=6.0'} + resolution: + { + integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==, + } + engines: { node: ">=6.0" } peerDependencies: - supports-color: '*' + supports-color: "*" peerDependenciesMeta: supports-color: optional: true @@ -680,54 +1251,124 @@ packages: ms: 2.1.3 dev: true + /deep-eql@5.0.2: + resolution: + { + integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==, + } + engines: { node: ">=6" } + dev: true + /eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + resolution: + { + integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==, + } dev: true /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + resolution: + { + integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, + } dev: true /emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + resolution: + { + integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, + } + dev: true + + /es-module-lexer@1.7.0: + resolution: + { + integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==, + } dev: true /esbuild@0.25.8: - resolution: {integrity: sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==, + } + engines: { node: ">=18" } hasBin: true requiresBuild: true optionalDependencies: - '@esbuild/aix-ppc64': 0.25.8 - '@esbuild/android-arm': 0.25.8 - '@esbuild/android-arm64': 0.25.8 - '@esbuild/android-x64': 0.25.8 - '@esbuild/darwin-arm64': 0.25.8 - '@esbuild/darwin-x64': 0.25.8 - '@esbuild/freebsd-arm64': 0.25.8 - '@esbuild/freebsd-x64': 0.25.8 - '@esbuild/linux-arm': 0.25.8 - '@esbuild/linux-arm64': 0.25.8 - '@esbuild/linux-ia32': 0.25.8 - '@esbuild/linux-loong64': 0.25.8 - '@esbuild/linux-mips64el': 0.25.8 - '@esbuild/linux-ppc64': 0.25.8 - '@esbuild/linux-riscv64': 0.25.8 - '@esbuild/linux-s390x': 0.25.8 - '@esbuild/linux-x64': 0.25.8 - '@esbuild/netbsd-arm64': 0.25.8 - '@esbuild/netbsd-x64': 0.25.8 - '@esbuild/openbsd-arm64': 0.25.8 - '@esbuild/openbsd-x64': 0.25.8 - '@esbuild/openharmony-arm64': 0.25.8 - '@esbuild/sunos-x64': 0.25.8 - '@esbuild/win32-arm64': 0.25.8 - '@esbuild/win32-ia32': 0.25.8 - '@esbuild/win32-x64': 0.25.8 + "@esbuild/aix-ppc64": 0.25.8 + "@esbuild/android-arm": 0.25.8 + "@esbuild/android-arm64": 0.25.8 + "@esbuild/android-x64": 0.25.8 + "@esbuild/darwin-arm64": 0.25.8 + "@esbuild/darwin-x64": 0.25.8 + "@esbuild/freebsd-arm64": 0.25.8 + "@esbuild/freebsd-x64": 0.25.8 + "@esbuild/linux-arm": 0.25.8 + "@esbuild/linux-arm64": 0.25.8 + "@esbuild/linux-ia32": 0.25.8 + "@esbuild/linux-loong64": 0.25.8 + "@esbuild/linux-mips64el": 0.25.8 + "@esbuild/linux-ppc64": 0.25.8 + "@esbuild/linux-riscv64": 0.25.8 + "@esbuild/linux-s390x": 0.25.8 + "@esbuild/linux-x64": 0.25.8 + "@esbuild/netbsd-arm64": 0.25.8 + "@esbuild/netbsd-x64": 0.25.8 + "@esbuild/openbsd-arm64": 0.25.8 + "@esbuild/openbsd-x64": 0.25.8 + "@esbuild/openharmony-arm64": 0.25.8 + "@esbuild/sunos-x64": 0.25.8 + "@esbuild/win32-arm64": 0.25.8 + "@esbuild/win32-ia32": 0.25.8 + "@esbuild/win32-x64": 0.25.8 + dev: true + + /escalade@3.2.0: + resolution: + { + integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==, + } + engines: { node: ">=6" } + dev: true + + /estree-walker@3.0.3: + resolution: + { + integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==, + } + dependencies: + "@types/estree": 1.0.8 + dev: true + + /expect-type@1.2.2: + resolution: + { + integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==, + } + engines: { node: ">=12.0.0" } dev: true /fdir@6.4.6(picomatch@4.0.3): - resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} + resolution: + { + integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==, + } + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + dependencies: + picomatch: 4.0.3 + dev: true + + /fdir@6.5.0(picomatch@4.0.3): + resolution: + { + integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==, + } + engines: { node: ">=12.0.0" } peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: @@ -738,7 +1379,10 @@ packages: dev: true /fix-dts-default-cjs-exports@1.0.1: - resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + resolution: + { + integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==, + } dependencies: magic-string: 0.30.17 mlly: 1.7.4 @@ -746,23 +1390,40 @@ packages: dev: true /foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} + resolution: + { + integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==, + } + engines: { node: ">=14" } dependencies: cross-spawn: 7.0.6 signal-exit: 4.1.0 dev: true /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + resolution: + { + integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, + } + engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } os: [darwin] requiresBuild: true dev: true optional: true + /get-caller-file@2.0.5: + resolution: + { + integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==, + } + engines: { node: 6.* || 8.* || >= 10.* } + dev: true + /glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + resolution: + { + integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==, + } hasBin: true dependencies: foreground-child: 3.3.1 @@ -773,70 +1434,145 @@ packages: path-scurry: 1.11.1 dev: true + /graphql@16.11.0: + resolution: + { + integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==, + } + engines: { node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0 } + dev: true + + /headers-polyfill@4.0.3: + resolution: + { + integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==, + } + dev: true + /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, + } + engines: { node: ">=8" } + dev: true + + /is-node-process@1.2.0: + resolution: + { + integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==, + } dev: true /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + resolution: + { + integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + } dev: true /jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + resolution: + { + integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==, + } dependencies: - '@isaacs/cliui': 8.0.2 + "@isaacs/cliui": 8.0.2 optionalDependencies: - '@pkgjs/parseargs': 0.11.0 + "@pkgjs/parseargs": 0.11.0 dev: true /joycon@3.1.1: - resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==, + } + engines: { node: ">=10" } + dev: true + + /js-tokens@9.0.1: + resolution: + { + integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==, + } dev: true /lilconfig@3.1.3: - resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} - engines: {node: '>=14'} + resolution: + { + integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==, + } + engines: { node: ">=14" } dev: true /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + resolution: + { + integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, + } dev: true /load-tsconfig@0.2.5: - resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + resolution: + { + integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } dev: true /lodash.sortby@4.7.0: - resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + resolution: + { + integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==, + } + dev: true + + /loupe@3.2.0: + resolution: + { + integrity: sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==, + } dev: true /lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + resolution: + { + integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==, + } dev: true /magic-string@0.30.17: - resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + resolution: + { + integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==, + } dependencies: - '@jridgewell/sourcemap-codec': 1.5.4 + "@jridgewell/sourcemap-codec": 1.5.4 dev: true /minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} + resolution: + { + integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==, + } + engines: { node: ">=16 || 14 >=14.17" } dependencies: brace-expansion: 2.0.2 dev: true /minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: '>=16 || 14 >=14.17'} + resolution: + { + integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==, + } + engines: { node: ">=16 || 14 >=14.17" } dev: true /mlly@1.7.4: - resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + resolution: + { + integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==, + } dependencies: acorn: 8.15.0 pathe: 2.0.3 @@ -845,59 +1581,168 @@ packages: dev: true /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + resolution: + { + integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, + } + dev: true + + /msw@2.10.5(@types/node@24.2.0)(typescript@5.9.2): + resolution: + { + integrity: sha512-0EsQCrCI1HbhpBWd89DvmxY6plmvrM96b0sCIztnvcNHQbXn5vqwm1KlXslo6u4wN9LFGLC1WFjjgljcQhe40A==, + } + engines: { node: ">=18" } + hasBin: true + requiresBuild: true + peerDependencies: + typescript: ">= 4.8.x" + peerDependenciesMeta: + typescript: + optional: true + dependencies: + "@bundled-es-modules/cookie": 2.0.1 + "@bundled-es-modules/statuses": 1.0.1 + "@bundled-es-modules/tough-cookie": 0.1.6 + "@inquirer/confirm": 5.1.15(@types/node@24.2.0) + "@mswjs/interceptors": 0.39.6 + "@open-draft/deferred-promise": 2.2.0 + "@open-draft/until": 2.1.0 + "@types/cookie": 0.6.0 + "@types/statuses": 2.0.6 + graphql: 16.11.0 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + strict-event-emitter: 0.5.1 + type-fest: 4.41.0 + typescript: 5.9.2 + yargs: 17.7.2 + transitivePeerDependencies: + - "@types/node" + dev: true + + /mute-stream@2.0.0: + resolution: + { + integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==, + } + engines: { node: ^18.17.0 || >=20.5.0 } dev: true /mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + resolution: + { + integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==, + } dependencies: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 dev: true + /nanoid@3.3.11: + resolution: + { + integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==, + } + engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } + hasBin: true + dev: true + /object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, + } + engines: { node: ">=0.10.0" } + dev: true + + /outvariant@1.4.3: + resolution: + { + integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==, + } dev: true /package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + resolution: + { + integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==, + } dev: true /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, + } + engines: { node: ">=8" } dev: true /path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} + resolution: + { + integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==, + } + engines: { node: ">=16 || 14 >=14.18" } dependencies: lru-cache: 10.4.3 minipass: 7.1.2 dev: true + /path-to-regexp@6.3.0: + resolution: + { + integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==, + } + dev: true + /pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + resolution: + { + integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==, + } + dev: true + + /pathval@2.0.1: + resolution: + { + integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==, + } + engines: { node: ">= 14.16" } dev: true /picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + resolution: + { + integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, + } dev: true /picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==, + } + engines: { node: ">=12" } dev: true /pirates@4.0.7: - resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==, + } + engines: { node: ">= 6" } dev: true /pkg-types@1.3.1: - resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + resolution: + { + integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==, + } dependencies: confbox: 0.1.8 mlly: 1.7.4 @@ -905,11 +1750,14 @@ packages: dev: true /postcss-load-config@6.0.1: - resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} - engines: {node: '>= 18'} + resolution: + { + integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==, + } + engines: { node: ">= 18" } peerDependencies: - jiti: '>=1.21.0' - postcss: '>=8.0.9' + jiti: ">=1.21.0" + postcss: ">=8.0.9" tsx: ^4.8.1 yaml: ^2.4.2 peerDependenciesMeta: @@ -925,78 +1773,192 @@ packages: lilconfig: 3.1.3 dev: true + /postcss@8.5.6: + resolution: + { + integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==, + } + engines: { node: ^10 || ^12 || >=14 } + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + dev: true + + /psl@1.15.0: + resolution: + { + integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==, + } + dependencies: + punycode: 2.3.1 + dev: true + /punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, + } + engines: { node: ">=6" } + dev: true + + /querystringify@2.2.0: + resolution: + { + integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==, + } dev: true /readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} + resolution: + { + integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==, + } + engines: { node: ">= 14.18.0" } + dev: true + + /require-directory@2.1.1: + resolution: + { + integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==, + } + engines: { node: ">=0.10.0" } + dev: true + + /requires-port@1.0.0: + resolution: + { + integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==, + } dev: true /resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==, + } + engines: { node: ">=8" } dev: true /rollup@4.45.1: - resolution: {integrity: sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} + resolution: + { + integrity: sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==, + } + engines: { node: ">=18.0.0", npm: ">=8.0.0" } hasBin: true dependencies: - '@types/estree': 1.0.8 + "@types/estree": 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.45.1 - '@rollup/rollup-android-arm64': 4.45.1 - '@rollup/rollup-darwin-arm64': 4.45.1 - '@rollup/rollup-darwin-x64': 4.45.1 - '@rollup/rollup-freebsd-arm64': 4.45.1 - '@rollup/rollup-freebsd-x64': 4.45.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.45.1 - '@rollup/rollup-linux-arm-musleabihf': 4.45.1 - '@rollup/rollup-linux-arm64-gnu': 4.45.1 - '@rollup/rollup-linux-arm64-musl': 4.45.1 - '@rollup/rollup-linux-loongarch64-gnu': 4.45.1 - '@rollup/rollup-linux-powerpc64le-gnu': 4.45.1 - '@rollup/rollup-linux-riscv64-gnu': 4.45.1 - '@rollup/rollup-linux-riscv64-musl': 4.45.1 - '@rollup/rollup-linux-s390x-gnu': 4.45.1 - '@rollup/rollup-linux-x64-gnu': 4.45.1 - '@rollup/rollup-linux-x64-musl': 4.45.1 - '@rollup/rollup-win32-arm64-msvc': 4.45.1 - '@rollup/rollup-win32-ia32-msvc': 4.45.1 - '@rollup/rollup-win32-x64-msvc': 4.45.1 + "@rollup/rollup-android-arm-eabi": 4.45.1 + "@rollup/rollup-android-arm64": 4.45.1 + "@rollup/rollup-darwin-arm64": 4.45.1 + "@rollup/rollup-darwin-x64": 4.45.1 + "@rollup/rollup-freebsd-arm64": 4.45.1 + "@rollup/rollup-freebsd-x64": 4.45.1 + "@rollup/rollup-linux-arm-gnueabihf": 4.45.1 + "@rollup/rollup-linux-arm-musleabihf": 4.45.1 + "@rollup/rollup-linux-arm64-gnu": 4.45.1 + "@rollup/rollup-linux-arm64-musl": 4.45.1 + "@rollup/rollup-linux-loongarch64-gnu": 4.45.1 + "@rollup/rollup-linux-powerpc64le-gnu": 4.45.1 + "@rollup/rollup-linux-riscv64-gnu": 4.45.1 + "@rollup/rollup-linux-riscv64-musl": 4.45.1 + "@rollup/rollup-linux-s390x-gnu": 4.45.1 + "@rollup/rollup-linux-x64-gnu": 4.45.1 + "@rollup/rollup-linux-x64-musl": 4.45.1 + "@rollup/rollup-win32-arm64-msvc": 4.45.1 + "@rollup/rollup-win32-ia32-msvc": 4.45.1 + "@rollup/rollup-win32-x64-msvc": 4.45.1 fsevents: 2.3.3 dev: true /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, + } + engines: { node: ">=8" } dependencies: shebang-regex: 3.0.0 dev: true /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, + } + engines: { node: ">=8" } + dev: true + + /siginfo@2.0.0: + resolution: + { + integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==, + } dev: true /signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} + resolution: + { + integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==, + } + engines: { node: ">=14" } + dev: true + + /source-map-js@1.2.1: + resolution: + { + integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, + } + engines: { node: ">=0.10.0" } dev: true /source-map@0.8.0-beta.0: - resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==, + } + engines: { node: ">= 8" } dependencies: whatwg-url: 7.1.0 dev: true + /stackback@0.0.2: + resolution: + { + integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==, + } + dev: true + + /statuses@2.0.2: + resolution: + { + integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==, + } + engines: { node: ">= 0.8" } + dev: true + + /std-env@3.9.0: + resolution: + { + integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==, + } + dev: true + + /strict-event-emitter@0.5.1: + resolution: + { + integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==, + } + dev: true + /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, + } + engines: { node: ">=8" } dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 @@ -1004,8 +1966,11 @@ packages: dev: true /string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==, + } + engines: { node: ">=12" } dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 @@ -1013,25 +1978,43 @@ packages: dev: true /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, + } + engines: { node: ">=8" } dependencies: ansi-regex: 5.0.1 dev: true /strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==, + } + engines: { node: ">=12" } dependencies: ansi-regex: 6.1.0 dev: true + /strip-literal@3.0.0: + resolution: + { + integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==, + } + dependencies: + js-tokens: 9.0.1 + dev: true + /sucrase@3.35.0: - resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} - engines: {node: '>=16 || 14 >=14.17'} + resolution: + { + integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==, + } + engines: { node: ">=16 || 14 >=14.17" } hasBin: true dependencies: - '@jridgewell/gen-mapping': 0.3.12 + "@jridgewell/gen-mapping": 0.3.12 commander: 4.1.1 glob: 10.4.5 lines-and-columns: 1.2.4 @@ -1041,58 +2024,126 @@ packages: dev: true /thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} + resolution: + { + integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==, + } + engines: { node: ">=0.8" } dependencies: thenify: 3.3.1 dev: true /thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + resolution: + { + integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==, + } dependencies: any-promise: 1.3.0 dev: true + /tinybench@2.9.0: + resolution: + { + integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==, + } + dev: true + /tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + resolution: + { + integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==, + } dev: true /tinyglobby@0.2.14: - resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} - engines: {node: '>=12.0.0'} + resolution: + { + integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==, + } + engines: { node: ">=12.0.0" } dependencies: fdir: 6.4.6(picomatch@4.0.3) picomatch: 4.0.3 dev: true + /tinypool@1.1.1: + resolution: + { + integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==, + } + engines: { node: ^18.0.0 || >=20.0.0 } + dev: true + + /tinyrainbow@2.0.0: + resolution: + { + integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==, + } + engines: { node: ">=14.0.0" } + dev: true + + /tinyspy@4.0.3: + resolution: + { + integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==, + } + engines: { node: ">=14.0.0" } + dev: true + + /tough-cookie@4.1.4: + resolution: + { + integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==, + } + engines: { node: ">=6" } + dependencies: + psl: 1.15.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + dev: true + /tr46@1.0.1: - resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + resolution: + { + integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==, + } dependencies: punycode: 2.3.1 dev: true /tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + resolution: + { + integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==, + } hasBin: true dev: true /ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + resolution: + { + integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==, + } dev: true /tsup@8.5.0(typescript@5.9.2): - resolution: {integrity: sha512-VmBp77lWNQq6PfuMqCHD3xWl22vEoWsKajkF8t+yMBawlUS8JzEI+vOVMeuNZIuMML8qXRizFKi9oD5glKQVcQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-VmBp77lWNQq6PfuMqCHD3xWl22vEoWsKajkF8t+yMBawlUS8JzEI+vOVMeuNZIuMML8qXRizFKi9oD5glKQVcQ==, + } + engines: { node: ">=18" } hasBin: true peerDependencies: - '@microsoft/api-extractor': ^7.36.0 - '@swc/core': ^1 + "@microsoft/api-extractor": ^7.36.0 + "@swc/core": ^1 postcss: ^8.4.12 - typescript: '>=4.5.0' + typescript: ">=4.5.0" peerDependenciesMeta: - '@microsoft/api-extractor': + "@microsoft/api-extractor": optional: true - '@swc/core': + "@swc/core": optional: true postcss: optional: true @@ -1124,26 +2175,227 @@ packages: - yaml dev: true + /type-fest@0.21.3: + resolution: + { + integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==, + } + engines: { node: ">=10" } + dev: true + + /type-fest@4.41.0: + resolution: + { + integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==, + } + engines: { node: ">=16" } + dev: true + /typescript@5.9.2: - resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} - engines: {node: '>=14.17'} + resolution: + { + integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==, + } + engines: { node: ">=14.17" } hasBin: true dev: true /ufo@1.6.1: - resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + resolution: + { + integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==, + } dev: true /undici-types@7.10.0: - resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} + resolution: + { + integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==, + } + dev: true + + /universalify@0.2.0: + resolution: + { + integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==, + } + engines: { node: ">= 4.0.0" } + dev: true + + /url-parse@1.5.10: + resolution: + { + integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==, + } + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + dev: true + + /vite-node@3.2.4(@types/node@24.2.0): + resolution: + { + integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==, + } + engines: { node: ^18.0.0 || ^20.0.0 || >=22.0.0 } + hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.4.1 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.1.3(@types/node@24.2.0) + transitivePeerDependencies: + - "@types/node" + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + dev: true + + /vite@7.1.3(@types/node@24.2.0): + resolution: + { + integrity: sha512-OOUi5zjkDxYrKhTV3V7iKsoS37VUM7v40+HuwEmcrsf11Cdx9y3DIr2Px6liIcZFwt3XSRpQvFpL3WVy7ApkGw==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + hasBin: true + peerDependencies: + "@types/node": ^20.19.0 || >=22.12.0 + jiti: ">=1.21.0" + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: ">=0.54.8" + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + "@types/node": + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + dependencies: + "@types/node": 24.2.0 + esbuild: 0.25.8 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.45.1 + tinyglobby: 0.2.14 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /vitest@3.2.4(@types/node@24.2.0)(msw@2.10.5): + resolution: + { + integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==, + } + engines: { node: ^18.0.0 || ^20.0.0 || >=22.0.0 } + hasBin: true + peerDependencies: + "@edge-runtime/vm": "*" + "@types/debug": ^4.1.12 + "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 + "@vitest/browser": 3.2.4 + "@vitest/ui": 3.2.4 + happy-dom: "*" + jsdom: "*" + peerDependenciesMeta: + "@edge-runtime/vm": + optional: true + "@types/debug": + optional: true + "@types/node": + optional: true + "@vitest/browser": + optional: true + "@vitest/ui": + optional: true + happy-dom: + optional: true + jsdom: + optional: true + dependencies: + "@types/chai": 5.2.2 + "@types/node": 24.2.0 + "@vitest/expect": 3.2.4 + "@vitest/mocker": 3.2.4(msw@2.10.5)(vite@7.1.3) + "@vitest/pretty-format": 3.2.4 + "@vitest/runner": 3.2.4 + "@vitest/snapshot": 3.2.4 + "@vitest/spy": 3.2.4 + "@vitest/utils": 3.2.4 + chai: 5.3.1 + debug: 4.4.1 + expect-type: 1.2.2 + magic-string: 0.30.17 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.9.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.14 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.1.3(@types/node@24.2.0) + vite-node: 3.2.4(@types/node@24.2.0) + why-is-node-running: 2.3.0 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml dev: true /webidl-conversions@4.0.2: - resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + resolution: + { + integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==, + } dev: true /whatwg-url@7.1.0: - resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + resolution: + { + integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==, + } dependencies: lodash.sortby: 4.7.0 tr46: 1.0.1 @@ -1151,16 +2403,46 @@ packages: dev: true /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, + } + engines: { node: ">= 8" } hasBin: true dependencies: isexe: 2.0.0 dev: true + /why-is-node-running@2.3.0: + resolution: + { + integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==, + } + engines: { node: ">=8" } + hasBin: true + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + dev: true + + /wrap-ansi@6.2.0: + resolution: + { + integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==, + } + engines: { node: ">=8" } + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==, + } + engines: { node: ">=10" } dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 @@ -1168,14 +2450,60 @@ packages: dev: true /wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==, + } + engines: { node: ">=12" } dependencies: ansi-styles: 6.2.1 string-width: 5.1.2 strip-ansi: 7.1.0 dev: true + /y18n@5.0.8: + resolution: + { + integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==, + } + engines: { node: ">=10" } + dev: true + + /yargs-parser@21.1.1: + resolution: + { + integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==, + } + engines: { node: ">=12" } + dev: true + + /yargs@17.7.2: + resolution: + { + integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==, + } + engines: { node: ">=12" } + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: true + + /yoctocolors-cjs@2.1.2: + resolution: + { + integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==, + } + engines: { node: ">=18" } + dev: true + /zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + resolution: + { + integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==, + } dev: false diff --git a/ratelimit/ts/src/interface.ts b/ratelimit/ts/src/interface.ts index 395205f..aa9578f 100644 --- a/ratelimit/ts/src/interface.ts +++ b/ratelimit/ts/src/interface.ts @@ -1,7 +1,10 @@ import type { LimitOptions, RatelimitResponse } from "./types"; export interface Ratelimiter { - limit: (identifier: string, opts?: LimitOptions) => Promise; + limit: ( + identifier: string, + opts?: LimitOptions, + ) => Promise; // retrieveLimit: (identifier: string) => Promise; // reset: (identifier: string) => Promise; diff --git a/ratelimit/ts/src/noop.ts b/ratelimit/ts/src/noop.ts index dfa03e7..02f33c7 100644 --- a/ratelimit/ts/src/noop.ts +++ b/ratelimit/ts/src/noop.ts @@ -2,7 +2,10 @@ import type { Ratelimiter } from "./interface"; import type { LimitOptions, RatelimitResponse } from "./types"; export class NoopRatelimit implements Ratelimiter { - public limit(_identifier: string, _opts?: LimitOptions): Promise { + public limit( + _identifier: string, + _opts?: LimitOptions, + ): Promise { return Promise.resolve({ limit: 0, remaining: 0, diff --git a/ratelimit/ts/src/onError.example.test.ts b/ratelimit/ts/src/onError.example.test.ts new file mode 100644 index 0000000..9ebed49 --- /dev/null +++ b/ratelimit/ts/src/onError.example.test.ts @@ -0,0 +1,34 @@ +import { test, expect } from "vitest"; +import { Ratelimit } from "../src/ratelimit"; + +test("auth errors use the fallback", async () => { + let onErrorCalled = 0; + + const unkey = new Ratelimit({ + rootKey: "this_key_does_not_exist", + namespace: "test", + limit: 10, + duration: "60s", + onError: (_error, _identifier) => { + // console.error(_error) + onErrorCalled++; + + return { + success: true, + limit: 10, + remaining: 10, + reset: 999, + }; + }, + }); + + const res = await unkey.limit("test"); + + expect(res).toEqual({ + success: true, + limit: 10, + remaining: 10, + reset: 999, + }); + expect(onErrorCalled).toBe(1); +}); diff --git a/ratelimit/ts/src/ratelimit.test.ts b/ratelimit/ts/src/ratelimit.test.ts new file mode 100644 index 0000000..30bd578 --- /dev/null +++ b/ratelimit/ts/src/ratelimit.test.ts @@ -0,0 +1,687 @@ +import { describe, test, expect, afterEach } from "vitest"; +import { http, HttpResponse } from "msw"; +import { createTestServer } from "./testutil/server"; +import { + createTestRatelimit, + createTestEnvironment, + createSuccessResponse, + createErrorResponse, + createRatelimitHandler, + captureRequests, + handlers, + expectRatelimitResponse, + waitFor, +} from "./testutil/helpers"; + +describe("Ratelimit Core Functionality", () => { + const cleanupFunctions: Array<() => void> = []; + + afterEach(() => { + // Clean up all test servers after each test + while (cleanupFunctions.length > 0) { + // biome-ignore lint/style/noNonNullAssertion: already checked in the while condition + const cleanup = cleanupFunctions.pop()!; + cleanup(); + } + }); + + describe("Successful API Responses", () => { + test("should handle successful ratelimit check within limits", async () => { + const { ratelimit, cleanup } = createTestEnvironment([ + handlers.success(), + ]); + + cleanupFunctions.push(cleanup); + + const result = await ratelimit.limit("test-user-123"); + + expectRatelimitResponse(result, expect); + expect(result.success).toBe(true); + expect(result.remaining).toBe(9); + }); + + test("should handle ratelimit exceeded response", async () => { + const { cleanup } = createTestServer([handlers.ratelimited()]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit(); + const result = await rl.limit("heavy-user"); + + expect(result.success).toBe(false); + expect(result.remaining).toBe(0); + expect(result.limit).toBe(10); + }); + + test("should handle custom cost parameter", async () => { + const { requests, handler } = captureRequests(); + + const { cleanup } = createTestServer([handler]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit(); + await rl.limit("test-user", { cost: 3 }); + + expect(requests[0]).toMatchObject({ + cost: 3, + namespace: "test-namespace", + identifier: "test-user", + }); + }); + + test("should handle response with override ID", async () => { + const overrideHandler = createRatelimitHandler( + createSuccessResponse({ + overrideId: "override_abc123", + }), + ); + + const { cleanup } = createTestServer([overrideHandler]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit(); + const result = await rl.limit("vip-user"); + + expect(result.overrideId).toBe("override_abc123"); + expectRatelimitResponse(result, expect); + }); + }); + + describe("HTTP Error Handling", () => { + const errorCases = [ + { status: 400, message: "Bad Request" }, + { status: 401, message: "Unauthorized" }, + { status: 403, message: "Forbidden" }, + { status: 404, message: "Not Found" }, + { status: 422, message: "Unprocessable Entity" }, + { status: 429, message: "Too Many Requests" }, + { status: 500, message: "Internal Server Error" }, + ]; + + test.each(errorCases)( + "should throw APIError for $status $message", + async ({ status, message }) => { + const { cleanup } = createTestServer([handlers.error(status, message)]); + cleanupFunctions.push(cleanup); + + // Disable timeout and error handlers so errors actually throw + const rl = createTestRatelimit({ + timeout: false, + // Don't provide onError handler so errors throw + }); + + // Just verify that an error is thrown, don't worry about the exact message + await expect(rl.limit("test-user")).rejects.toThrow(); + }, + ); + }); + + describe("Timeout Handling", () => { + test("should use default timeout fallback when API is slow", async () => { + const { cleanup } = createTestServer([handlers.timeout(6000)]); // Longer than default 5s timeout + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit(); + const result = await rl.limit("test-user"); + + // Should get the default fallback response + expect(result.success).toBe(false); + expect(result.limit).toBe(0); + expect(result.remaining).toBe(0); + }); + + test("should use custom timeout configuration", async () => { + const { cleanup } = createTestServer([handlers.timeout(3000)]); // Longer than our custom 2s timeout + cleanupFunctions.push(cleanup); + + const customFallback = { + success: true, + limit: 5, + remaining: 3, + reset: Date.now() + 30000, + }; + + const rl = createTestRatelimit({ + timeout: { + ms: 2000, + fallback: customFallback, + }, + }); + + const result = await rl.limit("test-user"); + + expect(result).toMatchObject(customFallback); + }); + + test("should support dynamic timeout fallback function", async () => { + const { cleanup } = createTestServer([handlers.timeout(2000)]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit({ + timeout: { + ms: 1000, + fallback: (identifier: string) => ({ + success: identifier.startsWith("vip_"), + limit: 10, + remaining: identifier.startsWith("vip_") ? 5 : 0, + reset: Date.now(), + }), + }, + }); + + const vipResult = await rl.limit("vip_user123"); + const regularResult = await rl.limit("regular_user456"); + + expect(vipResult.success).toBe(true); + expect(vipResult.remaining).toBe(5); + + expect(regularResult.success).toBe(false); + expect(regularResult.remaining).toBe(0); + }); + + test("should disable timeout when configured as false", async () => { + const { cleanup } = createTestServer([handlers.timeout(8000)]); // Very long delay + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit({ + timeout: false, + }); + + const result = await rl.limit("patient-user"); + + // Should wait for the actual response + expect(result.success).toBe(true); + expect(result.remaining).toBe(9); + }, 10000); // Increase test timeout for this specific test + }); + + describe("Custom Error Handling", () => { + test("should use custom timeout fallback with onError as alternative", async () => { + const { cleanup } = createTestServer([handlers.timeout(8000)]); // Longer delay + cleanupFunctions.push(cleanup); + + const customErrorResponse = { + success: false, + limit: 0, + remaining: 0, + reset: Date.now(), + }; + + let errorHandlerCalled = false; + const rl = createTestRatelimit({ + timeout: { + ms: 1000, // Short timeout + fallback: customErrorResponse, + }, + onError: (error: Error, identifier: string) => { + errorHandlerCalled = true; + return customErrorResponse; + }, + }); + + const result = await rl.limit("timeout-user"); + + // Should use timeout fallback, not error handler for timeouts + expect(result.success).toBe(false); + expect(result.limit).toBe(0); + // Error handler should not be called for timeout + expect(errorHandlerCalled).toBe(false); + }); + + test("should use onError handler for API errors like 404", async () => { + const { cleanup } = createTestServer([handlers.error(404, "Not Found")]); + cleanupFunctions.push(cleanup); + + let errorHandlerCalled = false; + let caughtError: any = null; + + const rl = createTestRatelimit({ + timeout: false, + onError: (error: Error, identifier: string) => { + errorHandlerCalled = true; + caughtError = error; + expect(identifier).toBe("api-error-user"); + return { + success: false, + limit: 0, + remaining: 0, + reset: Date.now(), + }; + }, + }); + + const result = await rl.limit("api-error-user"); + + expect(errorHandlerCalled).toBe(true); + expect(caughtError).toBeTruthy(); + expect(result.success).toBe(false); + expect(result.limit).toBe(0); + }); + + test("should use onError handler for API errors like 401", async () => { + const { cleanup } = createTestServer([ + handlers.error(401, "Unauthorized"), + ]); + cleanupFunctions.push(cleanup); + + let errorHandlerCalled = false; + const rl = createTestRatelimit({ + timeout: false, + onError: (error: Error, identifier: string) => { + errorHandlerCalled = true; + expect(error.message).toContain("API error occurred"); + expect(identifier).toBe("auth-error-user"); + return { + success: false, + limit: 0, + remaining: 0, + reset: Date.now(), + }; + }, + }); + + const result = await rl.limit("auth-error-user"); + + expect(errorHandlerCalled).toBe(true); + expect(result.success).toBe(false); + }); + }); + + describe("Caching Behavior", () => { + test("should cache ratelimited responses", async () => { + let apiCallCount = 0; + + // Create a custom handler that counts API calls + const countingHandler = http.post( + "http://localhost:3000/v2/ratelimit.limit", + async () => { + apiCallCount++; + return HttpResponse.json( + createSuccessResponse({ + success: false, + remaining: 0, + reset: Date.now() + 60000, // Reset in 1 minute + }), + ); + }, + ); + + const { cleanup } = createTestServer([countingHandler]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit(); + + // First request should hit the API + const result1 = await rl.limit("cached-user"); + expect(result1.success).toBe(false); + expect(apiCallCount).toBe(1); + + // Second request should use cache (no additional API call) + const result2 = await rl.limit("cached-user"); + expect(result2.success).toBe(false); + expect(apiCallCount).toBe(1); // Should still be 1 + + // Results should be identical + expect(result1).toEqual(result2); + }); + + test("should expire cache after reset time", async () => { + let apiCallCount = 0; + const shortResetTime = Date.now() + 100; // Reset in 100ms + + const countingHandler = http.post( + "http://localhost:3000/v2/ratelimit.limit", + async () => { + apiCallCount++; + return HttpResponse.json( + createSuccessResponse({ + success: false, + remaining: 0, + reset: shortResetTime, + }), + ); + }, + ); + + const { cleanup } = createTestServer([countingHandler]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit(); + + // First request + await rl.limit("expiring-cache-user"); + expect(apiCallCount).toBe(1); + + // Wait for cache to expire + await waitFor(150); + + // Second request should hit API again (cache expired) + await rl.limit("expiring-cache-user"); + expect(apiCallCount).toBe(2); + }); + + test("should not cache successful responses", async () => { + let apiCallCount = 0; + + const countingHandler = http.post( + "http://localhost:3000/v2/ratelimit.limit", + async () => { + apiCallCount++; + return HttpResponse.json(createSuccessResponse()); + }, + ); + + const { cleanup } = createTestServer([countingHandler]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit(); + + await rl.limit("non-cached-user"); + expect(apiCallCount).toBe(1); + + await rl.limit("non-cached-user"); + expect(apiCallCount).toBe(2); // Should make another API call + }); + }); + + describe("Namespace Handling", () => { + test("should treat same identifier in different namespaces separately", async () => { + const { requests, handler } = captureRequests(); + const { cleanup } = createTestServer([handler]); + cleanupFunctions.push(cleanup); + + const rl1 = createTestRatelimit({ namespace: "namespace-1" }); + const rl2 = createTestRatelimit({ namespace: "namespace-2" }); + + await rl1.limit("same-user"); + await rl2.limit("same-user"); + + expect(requests).toHaveLength(2); + expect(requests[0].namespace).toBe("namespace-1"); + expect(requests[1].namespace).toBe("namespace-2"); + expect(requests[0].identifier).toBe("same-user"); + expect(requests[1].identifier).toBe("same-user"); + }); + + test("should include namespace in cache keys for isolation", async () => { + let apiCallCount = 0; + + const countingHandler = http.post( + "http://localhost:3000/v2/ratelimit.limit", + async ({ request }) => { + const body = await request.json(); + apiCallCount++; + return HttpResponse.json( + createSuccessResponse({ + success: false, + remaining: 0, + reset: Date.now() + 60000, + }), + ); + }, + ); + + const { cleanup } = createTestServer([countingHandler]); + cleanupFunctions.push(cleanup); + + const rl1 = createTestRatelimit({ namespace: "cache-test-1" }); + const rl2 = createTestRatelimit({ namespace: "cache-test-2" }); + + // First request to each namespace + await rl1.limit("cached-user"); + await rl2.limit("cached-user"); + expect(apiCallCount).toBe(2); // Both should hit API + + // Second request to each namespace (should use cache) + await rl1.limit("cached-user"); + await rl2.limit("cached-user"); + expect(apiCallCount).toBe(2); // Should still be 2 (cached) + }); + }); + + describe("Input Validation and Boundary Tests", () => { + test("should handle empty identifier", async () => { + const { cleanup } = createTestServer([handlers.success()]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit(); + const result = await rl.limit(""); + + expectRatelimitResponse(result, expect); + }); + + test("should handle very long identifier", async () => { + const { cleanup } = createTestServer([handlers.success()]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit(); + const longIdentifier = "a".repeat(1000); + const result = await rl.limit(longIdentifier); + + expectRatelimitResponse(result, expect); + }); + + test("should handle special characters in identifier", async () => { + const { requests, handler } = captureRequests(); + const { cleanup } = createTestServer([handler]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit(); + const specialIdentifier = "user@example.com:12345!#$%&"; + await rl.limit(specialIdentifier); + + expect(requests[0].identifier).toBe(specialIdentifier); + }); + + test("should handle zero cost", async () => { + const { requests, handler } = captureRequests(); + const { cleanup } = createTestServer([handler]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit(); + await rl.limit("test-user", { cost: 0 }); + + expect(requests[0].cost).toBe(0); + }); + + test("should handle very large cost", async () => { + const { requests, handler } = captureRequests(); + const { cleanup } = createTestServer([handler]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit(); + const largeCost = 999999; + await rl.limit("test-user", { cost: largeCost }); + + expect(requests[0].cost).toBe(largeCost); + }); + + test("should handle custom limit overrides", async () => { + const { requests, handler } = captureRequests(); + const { cleanup } = createTestServer([handler]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit(); + await rl.limit("test-user", { + limit: { limit: 20, duration: "2m" }, + }); + + expect(requests[0].limit).toBe(20); + expect(requests[0].duration).toBe(120000); // 2 minutes in ms + }); + }); + + describe("Concurrent Request Tests", () => { + test("should handle multiple simultaneous requests correctly", async () => { + let apiCallCount = 0; + + const countingHandler = http.post( + "http://localhost:3000/v2/ratelimit.limit", + async () => { + apiCallCount++; + // Small delay to ensure concurrency + await new Promise((resolve) => setTimeout(resolve, 50)); + return HttpResponse.json(createSuccessResponse()); + }, + ); + + const { cleanup } = createTestServer([countingHandler]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit(); + + // Send 5 concurrent requests + const promises = Array.from({ length: 5 }, (_, i) => + rl.limit(`concurrent-user-${i}`), + ); + + const results = await Promise.all(promises); + + expect(results).toHaveLength(5); + expect(apiCallCount).toBe(5); + results.forEach((result) => { + expectRatelimitResponse(result, expect); + expect(result.success).toBe(true); + }); + }); + + test("should maintain cache consistency under concurrent access", async () => { + let apiCallCount = 0; + + const countingHandler = http.post( + "http://localhost:3000/v2/ratelimit.limit", + async () => { + apiCallCount++; + return HttpResponse.json( + createSuccessResponse({ + success: false, + remaining: 0, + reset: Date.now() + 60000, + }), + ); + }, + ); + + const { cleanup } = createTestServer([countingHandler]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit(); + + // Send multiple concurrent requests for the same identifier + const promises = Array.from({ length: 3 }, () => + rl.limit("cached-concurrent-user"), + ); + + const results = await Promise.all(promises); + + expect(results).toHaveLength(3); + // Should have made at least one API call, but due to caching, + // subsequent requests might be cached + expect(apiCallCount).toBeGreaterThanOrEqual(1); + expect(apiCallCount).toBeLessThanOrEqual(3); + + // All results should be the same (either all from cache or all from API) + results.forEach((result) => { + expect(result.success).toBe(false); + expect(result.remaining).toBe(0); + }); + }); + }); + + describe("Custom Cache Implementation", () => { + test("should use custom cache instance", async () => { + const customCache = new Map(); + let cacheGets = 0; + let cacheSets = 0; + + // Wrap the custom cache to track usage + const wrappedCache = { + get: (key: string) => { + cacheGets++; + return customCache.get(key); + }, + set: (key: string, value: any) => { + cacheSets++; + return customCache.set(key, value); + }, + delete: (key: string) => { + return customCache.delete(key); + }, + }; + + const countingHandler = http.post( + "http://localhost:3000/v2/ratelimit.limit", + async () => { + return HttpResponse.json( + createSuccessResponse({ + success: false, + remaining: 0, + reset: Date.now() + 60000, + }), + ); + }, + ); + + const { cleanup } = createTestServer([countingHandler]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit({ cache: wrappedCache }); + + // First request should check cache (miss) and set cache + await rl.limit("cache-test-user"); + expect(cacheGets).toBeGreaterThanOrEqual(1); // Cache get + expect(cacheSets).toBe(1); // Cache set + + // Reset counters + cacheGets = 0; + cacheSets = 0; + + // Second request should hit cache + await rl.limit("cache-test-user"); + expect(cacheGets).toBeGreaterThanOrEqual(1); // Cache get + expect(cacheSets).toBe(0); // No cache set (hit) + }); + }); + + describe("Base URL Configuration", () => { + test("should use custom baseUrl when configured", async () => { + // Use a different port for custom base URL test + const customHandler = http.post( + "http://localhost:3001/v2/ratelimit.limit", + async () => { + return HttpResponse.json(createSuccessResponse()); + }, + ); + + const { cleanup } = createTestServer([customHandler]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit({ baseUrl: "http://localhost:3001" }); + const result = await rl.limit("custom-url-user"); + + expectRatelimitResponse(result, expect); + expect(result.success).toBe(true); + }); + + test("should handle baseUrl without trailing slash", async () => { + const { cleanup } = createTestServer([handlers.success()]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit({ baseUrl: "http://localhost:3000" }); + const result = await rl.limit("no-slash-user"); + + expectRatelimitResponse(result, expect); + expect(result.success).toBe(true); + }); + + test("should handle baseUrl with trailing slash", async () => { + const { cleanup } = createTestServer([handlers.success()]); + cleanupFunctions.push(cleanup); + + const rl = createTestRatelimit({ baseUrl: "http://localhost:3000/" }); + const result = await rl.limit("with-slash-user"); + + expectRatelimitResponse(result, expect); + expect(result.success).toBe(true); + }); + }); +}); diff --git a/ratelimit/ts/src/ratelimit.ts b/ratelimit/ts/src/ratelimit.ts index 539c063..48e488d 100644 --- a/ratelimit/ts/src/ratelimit.ts +++ b/ratelimit/ts/src/ratelimit.ts @@ -1,5 +1,5 @@ import { Unkey } from "@unkey/api"; -import { APIError } from "@unkey/api/models/errors"; +import { UnkeyError } from "@unkey/api/models/errors/unkeyerror"; import { type Duration, ms } from "./duration"; import type { Ratelimiter } from "./interface"; import type { Cache, Limit, LimitOptions, RatelimitResponse } from "./types"; @@ -39,83 +39,85 @@ export type RatelimitConfig = Limit & { * ``` */ timeout?: - | { - /** - * Time in milliseconds until the response is returned - */ - ms: number | Duration; - - /** - * A custom response to return when the timeout is reached. - * - * The important bit is the `success` value, choose whether you want to let requests pass or not. - * - * @example With a static response - * ```ts - * { - * // 5 seconds - * ms: 5000 - * fallback: () => ({ success: true, limit: 0, remaining: 0, reset: 0 }) - * } - * ``` - * @example With a dynamic response - * ```ts - * { - * // 5 seconds - * ms: 5000 - * fallback: (identifier: string) => { - * if (someCheck(identifier)) { - * return { success: false, limit: 0, remaining: 0, reset: 0 } - * } - * return { success: true, limit: 0, remaining: 0, reset: 0 } - * } - * } - * ``` - */ - fallback: - | RatelimitResponse - | ((identifier: string) => RatelimitResponse | Promise); - } - | false;/** - * Configure what happens for unforeseen errors - * - * @example Letting requests pass - * ```ts - * onError: () => ({ success: true, limit: 0, remaining: 0, reset: 0 }) - * ``` - * - * @example Rejecting the request - * ```ts - * onError: () => ({ success: true, limit: 0, remaining: 0, reset: 0 }) - * ``` - * - * @example Dynamic response - * ```ts - * onError: (error, identifier) => { - * if (someCheck(error, identifier)) { - * return { success: false, limit: 0, remaining: 0, reset: 0 } - * } - * return { success: true, limit: 0, remaining: 0, reset: 0 } - * } - * ``` - */ + | { + /** + * Time in milliseconds until the response is returned + */ + ms: number | Duration; + + /** + * A custom response to return when the timeout is reached. + * + * The important bit is the `success` value, choose whether you want to let requests pass or not. + * + * @example With a static response + * ```ts + * { + * // 5 seconds + * ms: 5000 + * fallback: () => ({ success: true, limit: 0, remaining: 0, reset: 0 }) + * } + * ``` + * @example With a dynamic response + * ```ts + * { + * // 5 seconds + * ms: 5000 + * fallback: (identifier: string) => { + * if (someCheck(identifier)) { + * return { success: false, limit: 0, remaining: 0, reset: 0 } + * } + * return { success: true, limit: 0, remaining: 0, reset: 0 } + * } + * } + * ``` + */ + fallback: + | RatelimitResponse + | (( + identifier: string, + ) => RatelimitResponse | Promise); + } + | false /** + * Configure what happens for unforeseen errors + * + * @example Letting requests pass + * ```ts + * onError: () => ({ success: true, limit: 0, remaining: 0, reset: 0 }) + * ``` + * + * @example Rejecting the request + * ```ts + * onError: () => ({ success: true, limit: 0, remaining: 0, reset: 0 }) + * ``` + * + * @example Dynamic response + * ```ts + * onError: (error, identifier) => { + * if (someCheck(error, identifier)) { + * return { success: false, limit: 0, remaining: 0, reset: 0 } + * } + * return { success: true, limit: 0, remaining: 0, reset: 0 } + * } + * ``` + */; onError?: ( err: Error, identifier: string, ) => RatelimitResponse | Promise /** - * Cache abusive identifiers and block them immediately without a network request. - * - * ```ts - * // in global scope - * const cache = new Map() - * - * const unkey = new Ratelimit({ - * // ... - * cache: cache, - * }) - * ```` - */ - cache?: Cache + * Cache abusive identifiers and block them immediately without a network request. + * + * ```ts + * // in global scope + * const cache = new Map() + * + * const unkey = new Ratelimit({ + * // ... + * cache: cache, + * }) + * ```` + */; + cache?: Cache; /** * @@ -130,7 +132,7 @@ export type RatelimitConfig = Limit & { export class Ratelimit implements Ratelimiter { private readonly config: RatelimitConfig; private readonly unkey: Unkey; - private readonly cache: Cache + private readonly cache: Cache; constructor(config: RatelimitConfig) { this.config = config; @@ -141,7 +143,6 @@ export class Ratelimit implements Ratelimiter { this.cache = config.cache ?? new Map(); } - /** * Limit a specific identifier, you can override a lot of things about this specific request using * the 2nd argument. @@ -157,43 +158,62 @@ export class Ratelimit implements Ratelimiter { * // handle request * ``` */ - public async limit(identifier: string, opts?: LimitOptions): Promise { + public async limit( + identifier: string, + opts?: LimitOptions, + ): Promise { try { - return this._limit( + return await this._limit( identifier, opts?.limit?.limit ?? this.config.limit, ms(opts?.limit?.duration ?? this.config.duration), - opts?.cost ?? 1); + opts?.cost ?? 1, + ); } catch (e) { - if (!this.config.onError) { + if (typeof this.config.onError !== "function") { throw e; } - const err = e instanceof Error ? e : new Error(String(e)); + + const err = + e instanceof UnkeyError + ? new Error(e.message) + : e instanceof Error + ? e + : new Error(String(e)); return await this.config.onError(err, identifier); } } - - private async _limit(identifier: string, limit: number, duration: number, cost: number): Promise { + // _limit just handles the racing and caching. It must not handle errors, those are handled by limit + private async _limit( + identifier: string, + limit: number, + duration: number, + cost: number, + ): Promise { const cacheKey = `${this.config.namespace}:${identifier}:${limit}:${duration}`; - const naughty = this.cache.get(cacheKey) + const naughty = this.cache.get(cacheKey); if (naughty) { if (naughty.reset > Date.now()) { - return naughty + return naughty; } else { - this.cache.delete(cacheKey) + this.cache.delete(cacheKey); } - } const timeout = this.config.timeout === false ? null : (this.config.timeout ?? { - ms: 5000, - fallback: () => ({ success: false, limit: 0, remaining: 0, reset: Date.now() }), - }); + ms: 5000, + fallback: () => ({ + success: false, + limit: 0, + remaining: 0, + reset: Date.now(), + }), + }); let timeoutId: any = null; try { @@ -208,15 +228,6 @@ export class Ratelimit implements Ratelimiter { }) .then(async (res) => { return res.data; - }) - .catch((err) => { - if (err instanceof APIError) { - throw new Error( - `Ratelimit failed: [${err.statusCode} - ${err.message}]: ${err.body}`, - ); - } - - throw new Error(`Ratelimit failed: ${err}`); }), ]; if (timeout) { @@ -235,10 +246,10 @@ export class Ratelimit implements Ratelimiter { const res = await Promise.race(ps); if (!res.success) { - this.cache.set(cacheKey, res) + this.cache.set(cacheKey, res); } - return res + return res; } finally { if (timeoutId) { clearTimeout(timeoutId); diff --git a/ratelimit/ts/src/testutil/helpers.ts b/ratelimit/ts/src/testutil/helpers.ts new file mode 100644 index 0000000..279de49 --- /dev/null +++ b/ratelimit/ts/src/testutil/helpers.ts @@ -0,0 +1,164 @@ +import { http, HttpResponse, delay } from "msw"; +import { Ratelimit, type RatelimitConfig } from "../ratelimit"; +import { createTestServer } from "./server"; + +// Test instance factory +export const createTestRatelimit = (config: Partial = {}) => { + return new Ratelimit({ + baseUrl: "http://localhost:3000", // MSW will intercept this + rootKey: "test-root-key", + namespace: "test-namespace", + limit: 10, + duration: "1m", + ...config, + }); +}; + +// Response factories +export const createSuccessResponse = (overrides = {}) => ({ + meta: { + requestId: "req_test", + }, + data: { + success: true, + limit: 10, + remaining: 9, + reset: Date.now() + 60000, + ...overrides, + }, +}); + +export const createErrorResponse = (message: string, status = 400) => ({ + meta: { + requestId: "req_test", + }, + error: { + title: getErrorTitle(status), + detail: message, + status: status, + type: `https://unkey.com/docs/errors/${status}`, + ...(status === 400 && { + errors: [ + { + path: ["request"], + message: message, + }, + ], + }), + }, +}); + +const getErrorTitle = (status: number): string => { + switch (status) { + case 400: + return "Bad Request"; + case 401: + return "Unauthorized"; + case 403: + return "Forbidden"; + case 404: + return "Not Found"; + case 500: + return "Internal Server Error"; + default: + return "Error"; + } +}; + +// Handler factories +export const createRatelimitHandler = ( + response: any, + options: { delay?: number; status?: number } = {}, +) => { + return http.post( + "http://localhost:3000/v2/ratelimit.limit", + async ({ request }) => { + if (options.delay) await delay(options.delay); + + if (options.status && options.status >= 400) { + return HttpResponse.json(response, { status: options.status }); + } + + return HttpResponse.json(response); + }, + ); +}; + +// Request capture utility +export const captureRequests = () => { + const requests: any[] = []; + + const handler = http.post( + "http://localhost:3000/v2/ratelimit.limit", + async ({ request }) => { + const body = await request.json(); + requests.push(body); + return HttpResponse.json(createSuccessResponse()); + }, + ); + + return { requests, handler }; +}; + +// Custom matchers/assertions +export const expectRatelimitResponse = (result: any, expect: any) => { + expect(result).toMatchObject({ + success: expect.any(Boolean), + limit: expect.any(Number), + remaining: expect.any(Number), + reset: expect.any(Number), + }); +}; + +// Test utilities +export const waitFor = (ms: number) => + new Promise((resolve) => setTimeout(resolve, ms)); + +/** + * Create a complete test environment with server and ratelimit instance + * Server starts automatically + */ +export const createTestEnvironment = ( + handlers: any[] = [], + config: Partial = {}, +) => { + const testServer = createTestServer(handlers); + const ratelimit = createTestRatelimit(config); + + return { + server: testServer, + ratelimit, + cleanup: testServer.cleanup, + }; +}; + +// Common handler collections +export const handlers = { + success: () => createRatelimitHandler(createSuccessResponse()), + + ratelimited: () => + createRatelimitHandler( + createSuccessResponse({ + success: false, + remaining: 0, + }), + ), + + timeout: (delayMs = 6000) => + createRatelimitHandler(createSuccessResponse(), { delay: delayMs }), + + error: (status = 500, message = "Internal Server Error") => + createRatelimitHandler(createErrorResponse(message), { status }), + + networkError: () => + http.post("http://localhost:3000/v2/ratelimit.limit", () => { + return HttpResponse.error(); + }), + + malformedResponse: () => + http.post("http://localhost:3000/v2/ratelimit.limit", () => { + return new HttpResponse("invalid json{", { + headers: { "Content-Type": "application/json" }, + }); + }), +}; diff --git a/ratelimit/ts/src/testutil/server.ts b/ratelimit/ts/src/testutil/server.ts new file mode 100644 index 0000000..85d715a --- /dev/null +++ b/ratelimit/ts/src/testutil/server.ts @@ -0,0 +1,31 @@ +import { setupServer } from "msw/node"; +import { type RequestHandler } from "msw"; + +/** + * Create a new MSW server instance for testing + * Each test should create its own server for better isolation + * Server starts automatically and returns cleanup function + */ +export const createTestServer = (handlers: RequestHandler[] = []) => { + const server = setupServer(...handlers); + + // Auto-start the server + server.listen({ onUnhandledRequest: "error" }); + + return { + /** + * Cleanup function to close the server + */ + cleanup: () => { + server.close(); + }, + /** + * Use additional handlers for this test + */ + use: server.use.bind(server), + /** + * Reset handlers to initial state + */ + reset: server.resetHandlers.bind(server), + }; +}; diff --git a/ratelimit/ts/src/types.ts b/ratelimit/ts/src/types.ts index 8c71ac4..055c94c 100644 --- a/ratelimit/ts/src/types.ts +++ b/ratelimit/ts/src/types.ts @@ -1,7 +1,6 @@ import type { Duration } from "./duration"; - -export type Cache = Map +export type Cache = Map; export type Limit = { /** diff --git a/ratelimit/ts/vitest.config.ts b/ratelimit/ts/vitest.config.ts new file mode 100644 index 0000000..2d8bf8c --- /dev/null +++ b/ratelimit/ts/vitest.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + environment: "node", + testTimeout: 10000, // 10 second default timeout + coverage: { + reporter: ["text", "json", "html"], + exclude: ["src/testutil/**", "dist/**", "node_modules/**", "*.config.*"], + thresholds: { + lines: 90, + functions: 90, + branches: 90, + statements: 90, + }, + }, + }, +});