From 1d8fa6286ebd9b1eb58b0832105f055181c6140d Mon Sep 17 00:00:00 2001 From: dev-xo Date: Sat, 21 Dec 2024 14:02:10 +0100 Subject: [PATCH] chore: add JSDocs & clean-up --- .gitignore | 5 +- .husky/pre-commit | 4 - .husky/pre-push | 4 - package.json | 5 +- pnpm-lock.yaml | 3124 ------------------------------------------- src/index.ts | 447 ++++++- src/lib/redirect.ts | 14 - src/utils.ts | 58 +- test/index.spec.ts | 191 +-- test/utils.ts | 6 +- vitest-setup.ts | 7 - vitest.config.ts | 3 - 12 files changed, 521 insertions(+), 3347 deletions(-) delete mode 100755 .husky/pre-commit delete mode 100755 .husky/pre-push delete mode 100644 pnpm-lock.yaml delete mode 100644 src/lib/redirect.ts delete mode 100644 vitest-setup.ts diff --git a/.gitignore b/.gitignore index 743d2b8..918477f 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,4 @@ node_modules .env # Tests. -/coverage - -# Miscellaneous. -TODO.md \ No newline at end of file +/coverage \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index e6b68b3..0000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - -npm run validate && npm run build diff --git a/.husky/pre-push b/.husky/pre-push deleted file mode 100755 index e6b68b3..0000000 --- a/.husky/pre-push +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - -npm run validate && npm run build diff --git a/package.json b/package.json index 5c4c4a1..c988f27 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,6 @@ "test": "vitest --reporter verbose", "test:cov": "vitest run --coverage", "validate": "npm run lint && npm run typecheck && npx vitest --watch=false", - "prepare": "husky install && npm run build", "prepublishOnly": "npm run validate && npm run build" }, "files": [ @@ -39,7 +38,7 @@ ], "dependencies": { "@epic-web/totp": "^2.0.0", - "@mjackson/headers": "^0.8.0", + "@mjackson/headers": "^0.9.0", "base32-encode": "^2.0.0", "jose": "^5.8.0" }, @@ -54,9 +53,7 @@ "eslint": "^8.57.0", "eslint-config-prettier": "^8.10.0", "eslint-plugin-prettier": "^4.2.1", - "husky": "^8.0.3", "prettier": "^2.8.8", - "tiny-invariant": "^1.3.3", "typescript": "^5.5.4", "vite": "^4.5.3", "vite-tsconfig-paths": "^4.3.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index 1207f40..0000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,3124 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@epic-web/totp': - specifier: ^2.0.0 - version: 2.0.0 - base32-encode: - specifier: ^2.0.0 - version: 2.0.0 - jose: - specifier: ^5.8.0 - version: 5.8.0 - remix-auth: - specifier: ^3.6.0 - version: 3.7.0(@remix-run/react@2.12.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@remix-run/server-runtime@2.12.0(typescript@5.6.2)) - devDependencies: - '@remix-run/node': - specifier: ^2.11.2 - version: 2.12.0(typescript@5.6.2) - '@remix-run/server-runtime': - specifier: ^2.11.2 - version: 2.12.0(typescript@5.6.2) - '@types/node': - specifier: ^20.16.2 - version: 20.16.5 - '@typescript-eslint/eslint-plugin': - specifier: ^5.62.0 - version: 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.2))(eslint@8.57.0)(typescript@5.6.2) - '@typescript-eslint/parser': - specifier: ^5.62.0 - version: 5.62.0(eslint@8.57.0)(typescript@5.6.2) - '@vitest/coverage-v8': - specifier: 1.0.0-beta.3 - version: 1.0.0-beta.3(vitest@1.6.0(@types/node@20.16.5)) - eslint: - specifier: ^8.57.0 - version: 8.57.0 - eslint-config-prettier: - specifier: ^8.10.0 - version: 8.10.0(eslint@8.57.0) - eslint-plugin-prettier: - specifier: ^4.2.1 - version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8) - husky: - specifier: ^8.0.3 - version: 8.0.3 - prettier: - specifier: ^2.8.8 - version: 2.8.8 - tiny-invariant: - specifier: ^1.3.3 - version: 1.3.3 - typescript: - specifier: ^5.5.4 - version: 5.6.2 - vite: - specifier: ^4.5.3 - version: 4.5.3(@types/node@20.16.5) - vite-tsconfig-paths: - specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.2)(vite@4.5.3(@types/node@20.16.5)) - vitest: - specifier: ^1.6.0 - version: 1.6.0(@types/node@20.16.5) - -packages: - - '@ampproject/remapping@2.3.0': - resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} - engines: {node: '>=6.0.0'} - - '@bcoe/v8-coverage@0.2.3': - resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - - '@epic-web/totp@2.0.0': - resolution: {integrity: sha512-lyN8KLhA5uDyX8Z21AwVnHPcqYVm0kxY5kumu5wSMuq2ME1Ry9PE7v2ID8RzIvsBq+MTZ47i4+J9eF6DHUbJ1A==} - engines: {node: '>=20'} - - '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.18.20': - resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.18.20': - resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.18.20': - resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.18.20': - resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.18.20': - resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.18.20': - resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.18.20': - resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.18.20': - resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.18.20': - resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.18.20': - resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.18.20': - resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.18.20': - resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-mips64el@0.21.5': - resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.18.20': - resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.18.20': - resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.18.20': - resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.18.20': - resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-x64@0.18.20': - resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-x64@0.18.20': - resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/sunos-x64@0.18.20': - resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.18.20': - resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.18.20': - resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.18.20': - resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@eslint-community/eslint-utils@4.4.0': - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.11.0': - resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@eslint/js@8.57.0': - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@humanwhocodes/config-array@0.11.14': - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead - - '@istanbuljs/schema@0.1.3': - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - - '@jest/schemas@29.6.3': - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jridgewell/gen-mapping@0.3.5': - resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} - engines: {node: '>=6.0.0'} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/set-array@1.2.1': - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - - '@jridgewell/trace-mapping@0.3.25': - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@remix-run/node@2.12.0': - resolution: {integrity: sha512-83Jaoc6gpSuD4e6rCk7N5ZHAXNmDw4fJC+kPeDCsd6+wLtTLSi7u9Zo9/Q7moLZ3oyH+aR+LGdkxLULYv+Q6Og==} - engines: {node: '>=18.0.0'} - peerDependencies: - typescript: ^5.1.0 - peerDependenciesMeta: - typescript: - optional: true - - '@remix-run/react@2.12.0': - resolution: {integrity: sha512-Y109tI37Icr0BSU8sWSo8jDPkXaErJ/e1h0fkPvq6LZ0DrlcmHWBxzWJKID431I/KJvhVvBgVCuDamZTRVOZ5Q==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 - typescript: ^5.1.0 - peerDependenciesMeta: - typescript: - optional: true - - '@remix-run/router@1.19.2': - resolution: {integrity: sha512-baiMx18+IMuD1yyvOGaHM9QrVUPGGG0jC+z+IPHnRJWUAUvaKuWKyE8gjDj2rzv3sz9zOGoRSPgeBVHRhZnBlA==} - engines: {node: '>=14.0.0'} - - '@remix-run/server-runtime@2.12.0': - resolution: {integrity: sha512-o9ukOr3XKmyY8UufTrDdkgD3fiy+z+f4qEzvCQnvC0+EasCyN9hb1Vbui6Koo/5HKvahC4Ga8RcWyvhykKrG3g==} - engines: {node: '>=18.0.0'} - peerDependencies: - typescript: ^5.1.0 - peerDependenciesMeta: - typescript: - optional: true - - '@remix-run/web-blob@3.1.0': - resolution: {integrity: sha512-owGzFLbqPH9PlKb8KvpNJ0NO74HWE2euAn61eEiyCXX/oteoVzTVSN8mpLgDjaxBf2btj5/nUllSUgpyd6IH6g==} - - '@remix-run/web-fetch@4.4.2': - resolution: {integrity: sha512-jgKfzA713/4kAW/oZ4bC3MoLWyjModOVDjFPNseVqcJKSafgIscrYL9G50SurEYLswPuoU3HzSbO0jQCMYWHhA==} - engines: {node: ^10.17 || >=12.3} - - '@remix-run/web-file@3.1.0': - resolution: {integrity: sha512-dW2MNGwoiEYhlspOAXFBasmLeYshyAyhIdrlXBi06Duex5tDr3ut2LFKVj7tyHLmn8nnNwFf1BjNbkQpygC2aQ==} - - '@remix-run/web-form-data@3.1.0': - resolution: {integrity: sha512-NdeohLMdrb+pHxMQ/Geuzdp0eqPbea+Ieo8M8Jx2lGC6TBHsgHzYcBvr0LyPdPVycNRDEpWpiDdCOdCryo3f9A==} - - '@remix-run/web-stream@1.1.0': - resolution: {integrity: sha512-KRJtwrjRV5Bb+pM7zxcTJkhIqWWSy+MYsIxHK+0m5atcznsf15YwUBWHWulZerV2+vvHH1Lp1DD7pw6qKW8SgA==} - - '@rollup/rollup-android-arm-eabi@4.21.2': - resolution: {integrity: sha512-fSuPrt0ZO8uXeS+xP3b+yYTCBUd05MoSp2N/MFOgjhhUhMmchXlpTQrTpI8T+YAwAQuK7MafsCOxW7VrPMrJcg==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.21.2': - resolution: {integrity: sha512-xGU5ZQmPlsjQS6tzTTGwMsnKUtu0WVbl0hYpTPauvbRAnmIvpInhJtgjj3mcuJpEiuUw4v1s4BimkdfDWlh7gA==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.21.2': - resolution: {integrity: sha512-99AhQ3/ZMxU7jw34Sq8brzXqWH/bMnf7ZVhvLk9QU2cOepbQSVTns6qoErJmSiAvU3InRqC2RRZ5ovh1KN0d0Q==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.21.2': - resolution: {integrity: sha512-ZbRaUvw2iN/y37x6dY50D8m2BnDbBjlnMPotDi/qITMJ4sIxNY33HArjikDyakhSv0+ybdUxhWxE6kTI4oX26w==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-linux-arm-gnueabihf@4.21.2': - resolution: {integrity: sha512-ztRJJMiE8nnU1YFcdbd9BcH6bGWG1z+jP+IPW2oDUAPxPjo9dverIOyXz76m6IPA6udEL12reYeLojzW2cYL7w==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.21.2': - resolution: {integrity: sha512-flOcGHDZajGKYpLV0JNc0VFH361M7rnV1ee+NTeC/BQQ1/0pllYcFmxpagltANYt8FYf9+kL6RSk80Ziwyhr7w==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.21.2': - resolution: {integrity: sha512-69CF19Kp3TdMopyteO/LJbWufOzqqXzkrv4L2sP8kfMaAQ6iwky7NoXTp7bD6/irKgknDKM0P9E/1l5XxVQAhw==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.21.2': - resolution: {integrity: sha512-48pD/fJkTiHAZTnZwR0VzHrao70/4MlzJrq0ZsILjLW/Ab/1XlVUStYyGt7tdyIiVSlGZbnliqmult/QGA2O2w==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-powerpc64le-gnu@4.21.2': - resolution: {integrity: sha512-cZdyuInj0ofc7mAQpKcPR2a2iu4YM4FQfuUzCVA2u4HI95lCwzjoPtdWjdpDKyHxI0UO82bLDoOaLfpZ/wviyQ==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.21.2': - resolution: {integrity: sha512-RL56JMT6NwQ0lXIQmMIWr1SW28z4E4pOhRRNqwWZeXpRlykRIlEpSWdsgNWJbYBEWD84eocjSGDu/XxbYeCmwg==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.21.2': - resolution: {integrity: sha512-PMxkrWS9z38bCr3rWvDFVGD6sFeZJw4iQlhrup7ReGmfn7Oukrr/zweLhYX6v2/8J6Cep9IEA/SmjXjCmSbrMQ==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.21.2': - resolution: {integrity: sha512-B90tYAUoLhU22olrafY3JQCFLnT3NglazdwkHyxNDYF/zAxJt5fJUB/yBoWFoIQ7SQj+KLe3iL4BhOMa9fzgpw==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.21.2': - resolution: {integrity: sha512-7twFizNXudESmC9oneLGIUmoHiiLppz/Xs5uJQ4ShvE6234K0VB1/aJYU3f/4g7PhssLGKBVCC37uRkkOi8wjg==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-win32-arm64-msvc@4.21.2': - resolution: {integrity: sha512-9rRero0E7qTeYf6+rFh3AErTNU1VCQg2mn7CQcI44vNUWM9Ze7MSRS/9RFuSsox+vstRt97+x3sOhEey024FRQ==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.21.2': - resolution: {integrity: sha512-5rA4vjlqgrpbFVVHX3qkrCo/fZTj1q0Xxpg+Z7yIo3J2AilW7t2+n6Q8Jrx+4MrYpAnjttTYF8rr7bP46BPzRw==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.21.2': - resolution: {integrity: sha512-6UUxd0+SKomjdzuAcp+HAmxw1FlGBnl1v2yEPSabtx4lBfdXHDVsW7+lQkgz9cNFJGY3AWR7+V8P5BqkD9L9nA==} - cpu: [x64] - os: [win32] - - '@sinclair/typebox@0.27.8': - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - - '@types/cookie@0.6.0': - resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} - - '@types/estree@1.0.5': - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - - '@types/istanbul-lib-coverage@2.0.6': - resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/node@20.16.5': - resolution: {integrity: sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==} - - '@types/semver@7.5.8': - resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - - '@typescript-eslint/eslint-plugin@5.62.0': - resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - '@typescript-eslint/parser': ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/parser@5.62.0': - resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/scope-manager@5.62.0': - resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@typescript-eslint/type-utils@5.62.0': - resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: '*' - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/types@5.62.0': - resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@typescript-eslint/typescript-estree@5.62.0': - resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/utils@5.62.0': - resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - - '@typescript-eslint/visitor-keys@5.62.0': - resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@ungap/structured-clone@1.2.0': - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - - '@vitest/coverage-v8@1.0.0-beta.3': - resolution: {integrity: sha512-ewUkoelUzU3lBxWiv53lMzfgAZzz9OSyveb4ngIIP+I2/zqNA2IGhhHrFgFL4AqSoOBD1W2mUoUO4noaUrP2Wg==} - peerDependencies: - vitest: ^1.0.0-0 - - '@vitest/expect@1.6.0': - resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==} - - '@vitest/runner@1.6.0': - resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==} - - '@vitest/snapshot@1.6.0': - resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==} - - '@vitest/spy@1.6.0': - resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==} - - '@vitest/utils@1.6.0': - resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==} - - '@web3-storage/multipart-parser@1.0.0': - resolution: {integrity: sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw==} - - '@zxing/text-encoding@0.9.0': - resolution: {integrity: sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==} - - abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} - engines: {node: '>=0.4.0'} - - acorn@8.12.1: - resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} - engines: {node: '>=0.4.0'} - hasBin: true - - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - - assertion-error@1.1.0: - resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} - - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - base32-decode@1.0.0: - resolution: {integrity: sha512-KNWUX/R7wKenwE/G/qFMzGScOgVntOmbE27vvc6GrniDGYb6a5+qWcuoXl8WIOQL7q0TpK7nZDm1Y04Yi3Yn5g==} - - base32-encode@2.0.0: - resolution: {integrity: sha512-mlmkfc2WqdDtMl/id4qm3A7RjW6jxcbAoMjdRmsPiwQP0ufD4oXItYMnPgVHe80lnAIy+1xwzhHE1s4FoIceSw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - - call-bind@1.0.7: - resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} - engines: {node: '>= 0.4'} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - chai@4.5.0: - resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} - engines: {node: '>=4'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - check-error@1.0.3: - resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - confbox@0.1.7: - resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - cookie-signature@1.2.1: - resolution: {integrity: sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw==} - engines: {node: '>=6.6.0'} - - cookie@0.6.0: - resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} - engines: {node: '>= 0.6'} - - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - - data-uri-to-buffer@3.0.1: - resolution: {integrity: sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==} - engines: {node: '>= 6'} - - debug@4.3.7: - resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - deep-eql@4.1.4: - resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} - engines: {node: '>=6'} - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - - es-define-property@1.0.0: - resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - esbuild@0.18.20: - resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} - engines: {node: '>=12'} - hasBin: true - - esbuild@0.21.5: - resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} - engines: {node: '>=12'} - hasBin: true - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - eslint-config-prettier@8.10.0: - resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' - - eslint-plugin-prettier@4.2.1: - resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} - engines: {node: '>=12.0.0'} - peerDependencies: - eslint: '>=7.28.0' - eslint-config-prettier: '*' - prettier: '>=2.0.0' - peerDependenciesMeta: - eslint-config-prettier: - optional: true - - eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint@8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true - - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - - execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-diff@1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - - fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} - - flatted@3.3.1: - resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - - for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - get-func-name@2.0.2: - resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - - get-intrinsic@1.2.4: - resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} - engines: {node: '>= 0.4'} - - get-stream@8.0.1: - resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} - engines: {node: '>=16'} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - - globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - - gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} - - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-proto@1.0.3: - resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} - engines: {node: '>= 0.4'} - - has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - - human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} - - husky@8.0.3: - resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==} - engines: {node: '>=14'} - hasBin: true - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - is-arguments@1.1.1: - resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} - engines: {node: '>= 0.4'} - - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-generator-function@1.0.10: - resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} - engines: {node: '>= 0.4'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - - is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - is-typed-array@1.1.13: - resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} - engines: {node: '>= 0.4'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} - - istanbul-lib-report@3.0.1: - resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} - engines: {node: '>=10'} - - istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} - engines: {node: '>=10'} - - istanbul-reports@3.1.7: - resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} - engines: {node: '>=8'} - - jose@5.8.0: - resolution: {integrity: sha512-E7CqYpL/t7MMnfGnK/eg416OsFCVUrU/Y3Vwe7QjKhu/BkS1Ms455+2xsqZQVN57/U2MHMBvEb5SrmAZWAIntA==} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-tokens@9.0.0: - resolution: {integrity: sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==} - - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - local-pkg@0.5.0: - resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==} - engines: {node: '>=14'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - - loupe@2.3.7: - resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} - - magic-string@0.30.11: - resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} - - make-dir@4.0.0: - resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} - engines: {node: '>=10'} - - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - mlly@1.7.1: - resolution: {integrity: sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==} - - mrmime@1.0.1: - resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} - engines: {node: '>=10'} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - natural-compare-lite@1.4.0: - resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - npm-run-path@5.3.0: - resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-limit@5.0.0: - resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} - engines: {node: '>=18'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - - path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - - pathe@1.1.2: - resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} - - pathval@1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} - - picocolors@1.1.0: - resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} - - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - pkg-types@1.2.0: - resolution: {integrity: sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA==} - - possible-typed-array-names@1.0.0: - resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} - engines: {node: '>= 0.4'} - - postcss@8.4.45: - resolution: {integrity: sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==} - engines: {node: ^10 || ^12 || >=14} - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - prettier-linter-helpers@1.0.0: - resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} - engines: {node: '>=6.0.0'} - - prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} - hasBin: true - - pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - react-dom@18.3.1: - resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} - peerDependencies: - react: ^18.3.1 - - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - - react-router-dom@6.26.2: - resolution: {integrity: sha512-z7YkaEW0Dy35T3/QKPYB1LjMK2R1fxnHO8kWpUMTBdfVzZrWOiY9a7CtN8HqdWtDUWd5FY6Dl8HFsqVwH4uOtQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - react: '>=16.8' - react-dom: '>=16.8' - - react-router@6.26.2: - resolution: {integrity: sha512-tvN1iuT03kHgOFnLPfLJ8V95eijteveqdOSk+srqfePtQvqCExB8eHOYnlilbOcyJyKnYkr1vJvf7YqotAJu1A==} - engines: {node: '>=14.0.0'} - peerDependencies: - react: '>=16.8' - - react@18.3.1: - resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} - engines: {node: '>=0.10.0'} - - remix-auth@3.7.0: - resolution: {integrity: sha512-2QVjp2nJVaYxuFBecMQwzixCO7CLSssttLBU5eVlNcNlVeNMmY1g7OkmZ1Ogw9sBcoMXZ18J7xXSK0AISVFcfQ==} - peerDependencies: - '@remix-run/react': ^1.0.0 || ^2.0.0 - '@remix-run/server-runtime': ^1.0.0 || ^2.0.0 - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - - rollup@3.29.4: - resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} - engines: {node: '>=14.18.0', npm: '>=8.0.0'} - hasBin: true - - rollup@4.21.2: - resolution: {integrity: sha512-e3TapAgYf9xjdLvKQCkQTnbTKd4a6jwlpQSJJFokHGaX2IVjoEqkIIhiQfqsi0cdwlOD+tQGuOd5AJkc5RngBw==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} - - semver@7.6.3: - resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} - engines: {node: '>=10'} - hasBin: true - - set-cookie-parser@2.7.0: - resolution: {integrity: sha512-lXLOiqpkUumhRdFF3k1osNXCy9akgx/dyPZ5p8qAg9seJzXr5ZrlqZuWIMuY6ejOsVLE6flJ5/h3lsn57fQ/PQ==} - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - source-map@0.7.4: - resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} - engines: {node: '>= 8'} - - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - - std-env@3.7.0: - resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} - - stream-slice@0.1.2: - resolution: {integrity: sha512-QzQxpoacatkreL6jsxnVb7X5R/pGw9OUv2qWTYWnmLpg4NdN31snPy/f3TdQE1ZUXaThRvj1Zw4/OGg0ZkaLMA==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - strip-literal@2.1.0: - resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} - - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - - tiny-invariant@1.3.3: - resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinypool@0.8.4: - resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} - engines: {node: '>=14.0.0'} - - tinyspy@2.2.1: - resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} - engines: {node: '>=14.0.0'} - - to-data-view@2.0.0: - resolution: {integrity: sha512-RGEM5KqlPHr+WVTPmGNAXNeFEmsBnlkxXaIfEpUYV0AST2Z5W1EGq9L/MENFrMMmL2WQr1wjkmZy/M92eKhjYA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - tsconfck@3.1.3: - resolution: {integrity: sha512-ulNZP1SVpRDesxeMLON/LtWM8HIgAJEIVpVVhBM6gsmvQ8+Rh+ZG7FWGvHh7Ah3pRABwVJWklWCr/BTZSv0xnQ==} - engines: {node: ^18 || >=20} - hasBin: true - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - - tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - - tsutils@3.21.0: - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' - - turbo-stream@2.4.0: - resolution: {integrity: sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==} - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - type-detect@4.1.0: - resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} - engines: {node: '>=4'} - - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - - typescript@5.6.2: - resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} - engines: {node: '>=14.17'} - hasBin: true - - ufo@1.5.4: - resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} - - undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} - - undici@6.19.8: - resolution: {integrity: sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==} - engines: {node: '>=18.17'} - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - util@0.12.5: - resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} - - uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true - - v8-to-istanbul@9.3.0: - resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} - engines: {node: '>=10.12.0'} - - vite-node@1.6.0: - resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - - vite-tsconfig-paths@4.3.2: - resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==} - peerDependencies: - vite: '*' - peerDependenciesMeta: - vite: - optional: true - - vite@4.5.3: - resolution: {integrity: sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==} - engines: {node: ^14.18.0 || >=16.0.0} - hasBin: true - peerDependencies: - '@types/node': '>= 14' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - - vite@5.4.3: - resolution: {integrity: sha512-IH+nl64eq9lJjFqU+/yrRnrHPVTlgy42/+IzbOdaFDVlyLgI/wDlf+FCobXLX1cT0X5+7LMyH1mIy2xJdLfo8Q==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - - vitest@1.6.0: - resolution: {integrity: sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 1.6.0 - '@vitest/ui': 1.6.0 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - web-encoding@1.1.5: - resolution: {integrity: sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==} - - web-streams-polyfill@3.3.3: - resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} - engines: {node: '>= 8'} - - which-typed-array@1.1.15: - resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} - engines: {node: '>= 0.4'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - yocto-queue@1.1.1: - resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==} - engines: {node: '>=12.20'} - -snapshots: - - '@ampproject/remapping@2.3.0': - dependencies: - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 - - '@bcoe/v8-coverage@0.2.3': {} - - '@epic-web/totp@2.0.0': - dependencies: - base32-decode: 1.0.0 - base32-encode: 2.0.0 - - '@esbuild/aix-ppc64@0.21.5': - optional: true - - '@esbuild/android-arm64@0.18.20': - optional: true - - '@esbuild/android-arm64@0.21.5': - optional: true - - '@esbuild/android-arm@0.18.20': - optional: true - - '@esbuild/android-arm@0.21.5': - optional: true - - '@esbuild/android-x64@0.18.20': - optional: true - - '@esbuild/android-x64@0.21.5': - optional: true - - '@esbuild/darwin-arm64@0.18.20': - optional: true - - '@esbuild/darwin-arm64@0.21.5': - optional: true - - '@esbuild/darwin-x64@0.18.20': - optional: true - - '@esbuild/darwin-x64@0.21.5': - optional: true - - '@esbuild/freebsd-arm64@0.18.20': - optional: true - - '@esbuild/freebsd-arm64@0.21.5': - optional: true - - '@esbuild/freebsd-x64@0.18.20': - optional: true - - '@esbuild/freebsd-x64@0.21.5': - optional: true - - '@esbuild/linux-arm64@0.18.20': - optional: true - - '@esbuild/linux-arm64@0.21.5': - optional: true - - '@esbuild/linux-arm@0.18.20': - optional: true - - '@esbuild/linux-arm@0.21.5': - optional: true - - '@esbuild/linux-ia32@0.18.20': - optional: true - - '@esbuild/linux-ia32@0.21.5': - optional: true - - '@esbuild/linux-loong64@0.18.20': - optional: true - - '@esbuild/linux-loong64@0.21.5': - optional: true - - '@esbuild/linux-mips64el@0.18.20': - optional: true - - '@esbuild/linux-mips64el@0.21.5': - optional: true - - '@esbuild/linux-ppc64@0.18.20': - optional: true - - '@esbuild/linux-ppc64@0.21.5': - optional: true - - '@esbuild/linux-riscv64@0.18.20': - optional: true - - '@esbuild/linux-riscv64@0.21.5': - optional: true - - '@esbuild/linux-s390x@0.18.20': - optional: true - - '@esbuild/linux-s390x@0.21.5': - optional: true - - '@esbuild/linux-x64@0.18.20': - optional: true - - '@esbuild/linux-x64@0.21.5': - optional: true - - '@esbuild/netbsd-x64@0.18.20': - optional: true - - '@esbuild/netbsd-x64@0.21.5': - optional: true - - '@esbuild/openbsd-x64@0.18.20': - optional: true - - '@esbuild/openbsd-x64@0.21.5': - optional: true - - '@esbuild/sunos-x64@0.18.20': - optional: true - - '@esbuild/sunos-x64@0.21.5': - optional: true - - '@esbuild/win32-arm64@0.18.20': - optional: true - - '@esbuild/win32-arm64@0.21.5': - optional: true - - '@esbuild/win32-ia32@0.18.20': - optional: true - - '@esbuild/win32-ia32@0.21.5': - optional: true - - '@esbuild/win32-x64@0.18.20': - optional: true - - '@esbuild/win32-x64@0.21.5': - optional: true - - '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': - dependencies: - eslint: 8.57.0 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.11.0': {} - - '@eslint/eslintrc@2.1.4': - dependencies: - ajv: 6.12.6 - debug: 4.3.7 - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.2 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@8.57.0': {} - - '@humanwhocodes/config-array@0.11.14': - dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.7 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/object-schema@2.0.3': {} - - '@istanbuljs/schema@0.1.3': {} - - '@jest/schemas@29.6.3': - dependencies: - '@sinclair/typebox': 0.27.8 - - '@jridgewell/gen-mapping@0.3.5': - dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.25 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/set-array@1.2.1': {} - - '@jridgewell/sourcemap-codec@1.5.0': {} - - '@jridgewell/trace-mapping@0.3.25': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 - - '@remix-run/node@2.12.0(typescript@5.6.2)': - dependencies: - '@remix-run/server-runtime': 2.12.0(typescript@5.6.2) - '@remix-run/web-fetch': 4.4.2 - '@web3-storage/multipart-parser': 1.0.0 - cookie-signature: 1.2.1 - source-map-support: 0.5.21 - stream-slice: 0.1.2 - undici: 6.19.8 - optionalDependencies: - typescript: 5.6.2 - - '@remix-run/react@2.12.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': - dependencies: - '@remix-run/router': 1.19.2 - '@remix-run/server-runtime': 2.12.0(typescript@5.6.2) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-router: 6.26.2(react@18.3.1) - react-router-dom: 6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - turbo-stream: 2.4.0 - optionalDependencies: - typescript: 5.6.2 - - '@remix-run/router@1.19.2': {} - - '@remix-run/server-runtime@2.12.0(typescript@5.6.2)': - dependencies: - '@remix-run/router': 1.19.2 - '@types/cookie': 0.6.0 - '@web3-storage/multipart-parser': 1.0.0 - cookie: 0.6.0 - set-cookie-parser: 2.7.0 - source-map: 0.7.4 - turbo-stream: 2.4.0 - optionalDependencies: - typescript: 5.6.2 - - '@remix-run/web-blob@3.1.0': - dependencies: - '@remix-run/web-stream': 1.1.0 - web-encoding: 1.1.5 - - '@remix-run/web-fetch@4.4.2': - dependencies: - '@remix-run/web-blob': 3.1.0 - '@remix-run/web-file': 3.1.0 - '@remix-run/web-form-data': 3.1.0 - '@remix-run/web-stream': 1.1.0 - '@web3-storage/multipart-parser': 1.0.0 - abort-controller: 3.0.0 - data-uri-to-buffer: 3.0.1 - mrmime: 1.0.1 - - '@remix-run/web-file@3.1.0': - dependencies: - '@remix-run/web-blob': 3.1.0 - - '@remix-run/web-form-data@3.1.0': - dependencies: - web-encoding: 1.1.5 - - '@remix-run/web-stream@1.1.0': - dependencies: - web-streams-polyfill: 3.3.3 - - '@rollup/rollup-android-arm-eabi@4.21.2': - optional: true - - '@rollup/rollup-android-arm64@4.21.2': - optional: true - - '@rollup/rollup-darwin-arm64@4.21.2': - optional: true - - '@rollup/rollup-darwin-x64@4.21.2': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.21.2': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.21.2': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.21.2': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.21.2': - optional: true - - '@rollup/rollup-linux-powerpc64le-gnu@4.21.2': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.21.2': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.21.2': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.21.2': - optional: true - - '@rollup/rollup-linux-x64-musl@4.21.2': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.21.2': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.21.2': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.21.2': - optional: true - - '@sinclair/typebox@0.27.8': {} - - '@types/cookie@0.6.0': {} - - '@types/estree@1.0.5': {} - - '@types/istanbul-lib-coverage@2.0.6': {} - - '@types/json-schema@7.0.15': {} - - '@types/node@20.16.5': - dependencies: - undici-types: 6.19.8 - - '@types/semver@7.5.8': {} - - '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.2))(eslint@8.57.0)(typescript@5.6.2)': - dependencies: - '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.6.2) - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.0)(typescript@5.6.2) - '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.6.2) - debug: 4.3.7 - eslint: 8.57.0 - graphemer: 1.4.0 - ignore: 5.3.2 - natural-compare-lite: 1.4.0 - semver: 7.6.3 - tsutils: 3.21.0(typescript@5.6.2) - optionalDependencies: - typescript: 5.6.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.6.2)': - dependencies: - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.6.2) - debug: 4.3.7 - eslint: 8.57.0 - optionalDependencies: - typescript: 5.6.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@5.62.0': - dependencies: - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/visitor-keys': 5.62.0 - - '@typescript-eslint/type-utils@5.62.0(eslint@8.57.0)(typescript@5.6.2)': - dependencies: - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.6.2) - '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.6.2) - debug: 4.3.7 - eslint: 8.57.0 - tsutils: 3.21.0(typescript@5.6.2) - optionalDependencies: - typescript: 5.6.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@5.62.0': {} - - '@typescript-eslint/typescript-estree@5.62.0(typescript@5.6.2)': - dependencies: - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.7 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.6.3 - tsutils: 3.21.0(typescript@5.6.2) - optionalDependencies: - typescript: 5.6.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.6.2)': - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.6.2) - eslint: 8.57.0 - eslint-scope: 5.1.1 - semver: 7.6.3 - transitivePeerDependencies: - - supports-color - - typescript - - '@typescript-eslint/visitor-keys@5.62.0': - dependencies: - '@typescript-eslint/types': 5.62.0 - eslint-visitor-keys: 3.4.3 - - '@ungap/structured-clone@1.2.0': {} - - '@vitest/coverage-v8@1.0.0-beta.3(vitest@1.6.0(@types/node@20.16.5))': - dependencies: - '@ampproject/remapping': 2.3.0 - '@bcoe/v8-coverage': 0.2.3 - istanbul-lib-coverage: 3.2.2 - istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.7 - magic-string: 0.30.11 - picocolors: 1.1.0 - std-env: 3.7.0 - test-exclude: 6.0.0 - v8-to-istanbul: 9.3.0 - vitest: 1.6.0(@types/node@20.16.5) - transitivePeerDependencies: - - supports-color - - '@vitest/expect@1.6.0': - dependencies: - '@vitest/spy': 1.6.0 - '@vitest/utils': 1.6.0 - chai: 4.5.0 - - '@vitest/runner@1.6.0': - dependencies: - '@vitest/utils': 1.6.0 - p-limit: 5.0.0 - pathe: 1.1.2 - - '@vitest/snapshot@1.6.0': - dependencies: - magic-string: 0.30.11 - pathe: 1.1.2 - pretty-format: 29.7.0 - - '@vitest/spy@1.6.0': - dependencies: - tinyspy: 2.2.1 - - '@vitest/utils@1.6.0': - dependencies: - diff-sequences: 29.6.3 - estree-walker: 3.0.3 - loupe: 2.3.7 - pretty-format: 29.7.0 - - '@web3-storage/multipart-parser@1.0.0': {} - - '@zxing/text-encoding@0.9.0': - optional: true - - abort-controller@3.0.0: - dependencies: - event-target-shim: 5.0.1 - - acorn-jsx@5.3.2(acorn@8.12.1): - dependencies: - acorn: 8.12.1 - - acorn-walk@8.3.4: - dependencies: - acorn: 8.12.1 - - acorn@8.12.1: {} - - ajv@6.12.6: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ansi-regex@5.0.1: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@5.2.0: {} - - argparse@2.0.1: {} - - array-union@2.1.0: {} - - assertion-error@1.1.0: {} - - available-typed-arrays@1.0.7: - dependencies: - possible-typed-array-names: 1.0.0 - - balanced-match@1.0.2: {} - - base32-decode@1.0.0: {} - - base32-encode@2.0.0: - dependencies: - to-data-view: 2.0.0 - - brace-expansion@1.1.11: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - buffer-from@1.1.2: {} - - cac@6.7.14: {} - - call-bind@1.0.7: - dependencies: - es-define-property: 1.0.0 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.2.4 - set-function-length: 1.2.2 - - callsites@3.1.0: {} - - chai@4.5.0: - dependencies: - assertion-error: 1.1.0 - check-error: 1.0.3 - deep-eql: 4.1.4 - get-func-name: 2.0.2 - loupe: 2.3.7 - pathval: 1.1.1 - type-detect: 4.1.0 - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - check-error@1.0.3: - dependencies: - get-func-name: 2.0.2 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - concat-map@0.0.1: {} - - confbox@0.1.7: {} - - convert-source-map@2.0.0: {} - - cookie-signature@1.2.1: {} - - cookie@0.6.0: {} - - cross-spawn@7.0.3: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - data-uri-to-buffer@3.0.1: {} - - debug@4.3.7: - dependencies: - ms: 2.1.3 - - deep-eql@4.1.4: - dependencies: - type-detect: 4.1.0 - - deep-is@0.1.4: {} - - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.0 - es-errors: 1.3.0 - gopd: 1.0.1 - - diff-sequences@29.6.3: {} - - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - - es-define-property@1.0.0: - dependencies: - get-intrinsic: 1.2.4 - - es-errors@1.3.0: {} - - esbuild@0.18.20: - optionalDependencies: - '@esbuild/android-arm': 0.18.20 - '@esbuild/android-arm64': 0.18.20 - '@esbuild/android-x64': 0.18.20 - '@esbuild/darwin-arm64': 0.18.20 - '@esbuild/darwin-x64': 0.18.20 - '@esbuild/freebsd-arm64': 0.18.20 - '@esbuild/freebsd-x64': 0.18.20 - '@esbuild/linux-arm': 0.18.20 - '@esbuild/linux-arm64': 0.18.20 - '@esbuild/linux-ia32': 0.18.20 - '@esbuild/linux-loong64': 0.18.20 - '@esbuild/linux-mips64el': 0.18.20 - '@esbuild/linux-ppc64': 0.18.20 - '@esbuild/linux-riscv64': 0.18.20 - '@esbuild/linux-s390x': 0.18.20 - '@esbuild/linux-x64': 0.18.20 - '@esbuild/netbsd-x64': 0.18.20 - '@esbuild/openbsd-x64': 0.18.20 - '@esbuild/sunos-x64': 0.18.20 - '@esbuild/win32-arm64': 0.18.20 - '@esbuild/win32-ia32': 0.18.20 - '@esbuild/win32-x64': 0.18.20 - - esbuild@0.21.5: - optionalDependencies: - '@esbuild/aix-ppc64': 0.21.5 - '@esbuild/android-arm': 0.21.5 - '@esbuild/android-arm64': 0.21.5 - '@esbuild/android-x64': 0.21.5 - '@esbuild/darwin-arm64': 0.21.5 - '@esbuild/darwin-x64': 0.21.5 - '@esbuild/freebsd-arm64': 0.21.5 - '@esbuild/freebsd-x64': 0.21.5 - '@esbuild/linux-arm': 0.21.5 - '@esbuild/linux-arm64': 0.21.5 - '@esbuild/linux-ia32': 0.21.5 - '@esbuild/linux-loong64': 0.21.5 - '@esbuild/linux-mips64el': 0.21.5 - '@esbuild/linux-ppc64': 0.21.5 - '@esbuild/linux-riscv64': 0.21.5 - '@esbuild/linux-s390x': 0.21.5 - '@esbuild/linux-x64': 0.21.5 - '@esbuild/netbsd-x64': 0.21.5 - '@esbuild/openbsd-x64': 0.21.5 - '@esbuild/sunos-x64': 0.21.5 - '@esbuild/win32-arm64': 0.21.5 - '@esbuild/win32-ia32': 0.21.5 - '@esbuild/win32-x64': 0.21.5 - - escape-string-regexp@4.0.0: {} - - eslint-config-prettier@8.10.0(eslint@8.57.0): - dependencies: - eslint: 8.57.0 - - eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8): - dependencies: - eslint: 8.57.0 - prettier: 2.8.8 - prettier-linter-helpers: 1.0.0 - optionalDependencies: - eslint-config-prettier: 8.10.0(eslint@8.57.0) - - eslint-scope@5.1.1: - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - - eslint-scope@7.2.2: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint@8.57.0: - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@eslint-community/regexpp': 4.11.0 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.0 - '@humanwhocodes/config-array': 0.11.14 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.7 - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - - espree@9.6.1: - dependencies: - acorn: 8.12.1 - acorn-jsx: 5.3.2(acorn@8.12.1) - eslint-visitor-keys: 3.4.3 - - esquery@1.6.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@4.3.0: {} - - estraverse@5.3.0: {} - - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.5 - - esutils@2.0.3: {} - - event-target-shim@5.0.1: {} - - execa@8.0.1: - dependencies: - cross-spawn: 7.0.3 - get-stream: 8.0.1 - human-signals: 5.0.0 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.3.0 - onetime: 6.0.0 - signal-exit: 4.1.0 - strip-final-newline: 3.0.0 - - fast-deep-equal@3.1.3: {} - - fast-diff@1.3.0: {} - - fast-glob@3.3.2: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fastq@1.17.1: - dependencies: - reusify: 1.0.4 - - file-entry-cache@6.0.1: - dependencies: - flat-cache: 3.2.0 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@3.2.0: - dependencies: - flatted: 3.3.1 - keyv: 4.5.4 - rimraf: 3.0.2 - - flatted@3.3.1: {} - - for-each@0.3.3: - dependencies: - is-callable: 1.2.7 - - fs.realpath@1.0.0: {} - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - get-func-name@2.0.2: {} - - get-intrinsic@1.2.4: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - hasown: 2.0.2 - - get-stream@8.0.1: {} - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - - globals@13.24.0: - dependencies: - type-fest: 0.20.2 - - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - - globrex@0.1.2: {} - - gopd@1.0.1: - dependencies: - get-intrinsic: 1.2.4 - - graphemer@1.4.0: {} - - has-flag@4.0.0: {} - - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.0 - - has-proto@1.0.3: {} - - has-symbols@1.0.3: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.0.3 - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - html-escaper@2.0.2: {} - - human-signals@5.0.0: {} - - husky@8.0.3: {} - - ignore@5.3.2: {} - - import-fresh@3.3.0: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - imurmurhash@0.1.4: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - - is-arguments@1.1.1: - dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 - - is-callable@1.2.7: {} - - is-extglob@2.1.1: {} - - is-generator-function@1.0.10: - dependencies: - has-tostringtag: 1.0.2 - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-number@7.0.0: {} - - is-path-inside@3.0.3: {} - - is-stream@3.0.0: {} - - is-typed-array@1.1.13: - dependencies: - which-typed-array: 1.1.15 - - isexe@2.0.0: {} - - istanbul-lib-coverage@3.2.2: {} - - istanbul-lib-report@3.0.1: - dependencies: - istanbul-lib-coverage: 3.2.2 - make-dir: 4.0.0 - supports-color: 7.2.0 - - istanbul-lib-source-maps@4.0.1: - dependencies: - debug: 4.3.7 - istanbul-lib-coverage: 3.2.2 - source-map: 0.6.1 - transitivePeerDependencies: - - supports-color - - istanbul-reports@3.1.7: - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.1 - - jose@5.8.0: {} - - js-tokens@4.0.0: {} - - js-tokens@9.0.0: {} - - js-yaml@4.1.0: - dependencies: - argparse: 2.0.1 - - json-buffer@3.0.1: {} - - json-schema-traverse@0.4.1: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - local-pkg@0.5.0: - dependencies: - mlly: 1.7.1 - pkg-types: 1.2.0 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash.merge@4.6.2: {} - - loose-envify@1.4.0: - dependencies: - js-tokens: 4.0.0 - - loupe@2.3.7: - dependencies: - get-func-name: 2.0.2 - - magic-string@0.30.11: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 - - make-dir@4.0.0: - dependencies: - semver: 7.6.3 - - merge-stream@2.0.0: {} - - merge2@1.4.1: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - - mimic-fn@4.0.0: {} - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.11 - - mlly@1.7.1: - dependencies: - acorn: 8.12.1 - pathe: 1.1.2 - pkg-types: 1.2.0 - ufo: 1.5.4 - - mrmime@1.0.1: {} - - ms@2.1.3: {} - - nanoid@3.3.7: {} - - natural-compare-lite@1.4.0: {} - - natural-compare@1.4.0: {} - - npm-run-path@5.3.0: - dependencies: - path-key: 4.0.0 - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - onetime@6.0.0: - dependencies: - mimic-fn: 4.0.0 - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-limit@5.0.0: - dependencies: - yocto-queue: 1.1.1 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - path-exists@4.0.0: {} - - path-is-absolute@1.0.1: {} - - path-key@3.1.1: {} - - path-key@4.0.0: {} - - path-type@4.0.0: {} - - pathe@1.1.2: {} - - pathval@1.1.1: {} - - picocolors@1.1.0: {} - - picomatch@2.3.1: {} - - pkg-types@1.2.0: - dependencies: - confbox: 0.1.7 - mlly: 1.7.1 - pathe: 1.1.2 - - possible-typed-array-names@1.0.0: {} - - postcss@8.4.45: - dependencies: - nanoid: 3.3.7 - picocolors: 1.1.0 - source-map-js: 1.2.1 - - prelude-ls@1.2.1: {} - - prettier-linter-helpers@1.0.0: - dependencies: - fast-diff: 1.3.0 - - prettier@2.8.8: {} - - pretty-format@29.7.0: - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.3.1 - - punycode@2.3.1: {} - - queue-microtask@1.2.3: {} - - react-dom@18.3.1(react@18.3.1): - dependencies: - loose-envify: 1.4.0 - react: 18.3.1 - scheduler: 0.23.2 - - react-is@18.3.1: {} - - react-router-dom@6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@remix-run/router': 1.19.2 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-router: 6.26.2(react@18.3.1) - - react-router@6.26.2(react@18.3.1): - dependencies: - '@remix-run/router': 1.19.2 - react: 18.3.1 - - react@18.3.1: - dependencies: - loose-envify: 1.4.0 - - remix-auth@3.7.0(@remix-run/react@2.12.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@remix-run/server-runtime@2.12.0(typescript@5.6.2)): - dependencies: - '@remix-run/react': 2.12.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@remix-run/server-runtime': 2.12.0(typescript@5.6.2) - uuid: 8.3.2 - - resolve-from@4.0.0: {} - - reusify@1.0.4: {} - - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - - rollup@3.29.4: - optionalDependencies: - fsevents: 2.3.3 - - rollup@4.21.2: - dependencies: - '@types/estree': 1.0.5 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.21.2 - '@rollup/rollup-android-arm64': 4.21.2 - '@rollup/rollup-darwin-arm64': 4.21.2 - '@rollup/rollup-darwin-x64': 4.21.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.21.2 - '@rollup/rollup-linux-arm-musleabihf': 4.21.2 - '@rollup/rollup-linux-arm64-gnu': 4.21.2 - '@rollup/rollup-linux-arm64-musl': 4.21.2 - '@rollup/rollup-linux-powerpc64le-gnu': 4.21.2 - '@rollup/rollup-linux-riscv64-gnu': 4.21.2 - '@rollup/rollup-linux-s390x-gnu': 4.21.2 - '@rollup/rollup-linux-x64-gnu': 4.21.2 - '@rollup/rollup-linux-x64-musl': 4.21.2 - '@rollup/rollup-win32-arm64-msvc': 4.21.2 - '@rollup/rollup-win32-ia32-msvc': 4.21.2 - '@rollup/rollup-win32-x64-msvc': 4.21.2 - fsevents: 2.3.3 - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - scheduler@0.23.2: - dependencies: - loose-envify: 1.4.0 - - semver@7.6.3: {} - - set-cookie-parser@2.7.0: {} - - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.2.4 - gopd: 1.0.1 - has-property-descriptors: 1.0.2 - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - siginfo@2.0.0: {} - - signal-exit@4.1.0: {} - - slash@3.0.0: {} - - source-map-js@1.2.1: {} - - source-map-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.6.1: {} - - source-map@0.7.4: {} - - stackback@0.0.2: {} - - std-env@3.7.0: {} - - stream-slice@0.1.2: {} - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-final-newline@3.0.0: {} - - strip-json-comments@3.1.1: {} - - strip-literal@2.1.0: - dependencies: - js-tokens: 9.0.0 - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - test-exclude@6.0.0: - dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 - - text-table@0.2.0: {} - - tiny-invariant@1.3.3: {} - - tinybench@2.9.0: {} - - tinypool@0.8.4: {} - - tinyspy@2.2.1: {} - - to-data-view@2.0.0: {} - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - tsconfck@3.1.3(typescript@5.6.2): - optionalDependencies: - typescript: 5.6.2 - - tslib@1.14.1: {} - - tsutils@3.21.0(typescript@5.6.2): - dependencies: - tslib: 1.14.1 - typescript: 5.6.2 - - turbo-stream@2.4.0: {} - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - type-detect@4.1.0: {} - - type-fest@0.20.2: {} - - typescript@5.6.2: {} - - ufo@1.5.4: {} - - undici-types@6.19.8: {} - - undici@6.19.8: {} - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - util@0.12.5: - dependencies: - inherits: 2.0.4 - is-arguments: 1.1.1 - is-generator-function: 1.0.10 - is-typed-array: 1.1.13 - which-typed-array: 1.1.15 - - uuid@8.3.2: {} - - v8-to-istanbul@9.3.0: - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - '@types/istanbul-lib-coverage': 2.0.6 - convert-source-map: 2.0.0 - - vite-node@1.6.0(@types/node@20.16.5): - dependencies: - cac: 6.7.14 - debug: 4.3.7 - pathe: 1.1.2 - picocolors: 1.1.0 - vite: 5.4.3(@types/node@20.16.5) - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - vite-tsconfig-paths@4.3.2(typescript@5.6.2)(vite@4.5.3(@types/node@20.16.5)): - dependencies: - debug: 4.3.7 - globrex: 0.1.2 - tsconfck: 3.1.3(typescript@5.6.2) - optionalDependencies: - vite: 4.5.3(@types/node@20.16.5) - transitivePeerDependencies: - - supports-color - - typescript - - vite@4.5.3(@types/node@20.16.5): - dependencies: - esbuild: 0.18.20 - postcss: 8.4.45 - rollup: 3.29.4 - optionalDependencies: - '@types/node': 20.16.5 - fsevents: 2.3.3 - - vite@5.4.3(@types/node@20.16.5): - dependencies: - esbuild: 0.21.5 - postcss: 8.4.45 - rollup: 4.21.2 - optionalDependencies: - '@types/node': 20.16.5 - fsevents: 2.3.3 - - vitest@1.6.0(@types/node@20.16.5): - dependencies: - '@vitest/expect': 1.6.0 - '@vitest/runner': 1.6.0 - '@vitest/snapshot': 1.6.0 - '@vitest/spy': 1.6.0 - '@vitest/utils': 1.6.0 - acorn-walk: 8.3.4 - chai: 4.5.0 - debug: 4.3.7 - execa: 8.0.1 - local-pkg: 0.5.0 - magic-string: 0.30.11 - pathe: 1.1.2 - picocolors: 1.1.0 - std-env: 3.7.0 - strip-literal: 2.1.0 - tinybench: 2.9.0 - tinypool: 0.8.4 - vite: 5.4.3(@types/node@20.16.5) - vite-node: 1.6.0(@types/node@20.16.5) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 20.16.5 - transitivePeerDependencies: - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - web-encoding@1.1.5: - dependencies: - util: 0.12.5 - optionalDependencies: - '@zxing/text-encoding': 0.9.0 - - web-streams-polyfill@3.3.3: {} - - which-typed-array@1.1.15: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-tostringtag: 1.0.2 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - why-is-node-running@2.3.0: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - - word-wrap@1.2.5: {} - - wrappy@1.0.2: {} - - yocto-queue@0.1.0: {} - - yocto-queue@1.1.1: {} diff --git a/src/index.ts b/src/index.ts index 3483c1e..04d05d3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,114 +1,302 @@ +import { Strategy } from 'remix-auth/strategy' import { generateTOTP, verifyTOTP } from '@epic-web/totp' -import * as jose from 'jose' import { Cookie, SetCookie } from '@mjackson/headers' - +import * as jose from 'jose' +import { redirect } from './utils.js' import { generateSecret, - assertTOTPData, - asJweKey, - coerceToOptionalNonEmptyString, coerceToOptionalString, coerceToOptionalTotpSessionData, + coerceToOptionalNonEmptyString, + assertTOTPData, + asJweKey, } from './utils.js' +import { STRATEGY_NAME, FORM_FIELDS, ERRORS } from './constants.js' -import { - STRATEGY_NAME, - FORM_FIELDS, - SESSION_KEYS, - ERRORS, -} from './constants.js' -import { redirect } from './lib/redirect.js' -import { Strategy } from 'remix-auth/strategy' - +/** + * The TOTP JWE data containing the secret. + */ export interface TOTPData { + /** + * The TOTP secret. + */ secret: string + + /** + * The time the TOTP was generated. + */ createdAt: number } +/** + * The TOTP data stored in the session. + */ +// TODO: This may require a rename. export interface TOTPSessionData { + /** + * The TOTP JWE of TOTPData. + */ jwe: string + + /** + * The number of attempts the user tried to verify the TOTP. + * @default 0 + */ attempts: number } +/** + * The TOTP generation configuration. + */ export interface TOTPGenerationOptions { + /** + * The secret used to generate the TOTP. + * It should be Base32 encoded (Feel free to use: https://npm.im/thirty-two). + * + * @default random Base32 secret. + */ secret?: string + + /** + * The algorithm used to generate the TOTP. + * @default 'SHA1' + */ algorithm?: string + + /** + * The character set used to generate the TOTP. + * @default 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' + */ charSet?: string + + /** + * The number of digits used to generate the TOTP. + * @default 6 + */ digits?: number + + /** + * The number of seconds the TOTP will be valid. + * @default 60 + */ period?: number + + /** + * The max number of attempts the user can try to verify the TOTP. + * @default 3 + */ maxAttempts?: number } +/** + * The send TOTP configuration. + */ export interface SendTOTPOptions { + /** + * The email address provided by the user. + */ email: string + + /** + * The decrypted TOTP code. + */ code: string + + /** + * The Magic Link URL. + */ magicLink: string + + /** + * The request to generate the TOTP. + */ request: Request + + /** + * The form data of the request. + */ formData: FormData - context?: unknown } +/** + * The sender email method. + * @param options The send TOTP options. + */ export interface SendTOTP { (options: SendTOTPOptions): Promise } +/** + * The validate email method. + * This can be useful to ensure it's not a disposable email address. + * + * @param email The email address to validate. + */ export interface ValidateEmail { (email: string): Promise } +/** + * The custom errors configuration. + */ export interface CustomErrorsOptions { + /** + * The required email error message. + */ requiredEmail?: string + + /** + * The invalid email error message. + */ invalidEmail?: string + + /** + * The invalid TOTP error message. + */ invalidTotp?: string + + /** + * The expired TOTP error message. + */ expiredTotp?: string + + /** + * The missing session email error message. + */ missingSessionEmail?: string } +/** + * The TOTP Strategy options. + */ export interface TOTPStrategyOptions { + /** + * The secret used to encrypt the TOTP data. + * Must be string of 64 hexadecimal characters. + */ secret: string + + /** + * The maximum age the session can live. + * @default undefined + */ maxAge?: number + + /** + * The TOTP generation configuration. + */ totpGeneration?: TOTPGenerationOptions + + /** + * The URL path for the Magic Link. + * @default '/magic-link' + */ magicLinkPath?: string + + /** + * The custom errors configuration. + */ customErrors?: CustomErrorsOptions + + /** + * The form input name used to get the email address. + * @default "email" + */ emailFieldKey?: string + + /** + * The form input name used to get the TOTP. + * @default "code" + */ codeFieldKey?: string + + /** + * The session key that stores the email address. + * @default "auth:email" + */ + // TODO: Do we require this anymore? sessionEmailKey?: string + + /** + * The session key that stores the signed TOTP. + * @default "auth:totp" + */ + // TODO: Do we require this anymore? sessionTotpKey?: string + + /** + * The send TOTP method. + */ sendTOTP: SendTOTP + + /** + * The validate email method. + */ validateEmail?: ValidateEmail + + /** + * The success redirect URL. + */ successRedirect: string + + /** + * The failure redirect URL. + */ failureRedirect: string } +/** + * The verify method callback. + * Returns the user for the email to be stored in the session. + */ export interface TOTPVerifyParams { + /** + * The email address provided by the user. + */ email: string + + /** + * The formData object from the Request. + */ formData?: FormData + + /** + * The Request object. + */ request: Request - context?: unknown } /** - * A simple store that keeps TOTP-related state in a cookie. - * Stores email, TOTP data, and a possible error message. + * A store class that manages TOTP-related state in a cookie. + * Handles email, TOTP session data, and error messages. */ class TOTPStore { private email?: string private totp?: TOTPSessionData private error?: { message: string } + /** The name of the cookie used to store TOTP data. */ static COOKIE_NAME = '_totp' + /** + * Creates a new TOTPStore instance. + * @param cookie - The Cookie instance used to manage cookie data. + */ constructor(private cookie: Cookie) { const raw = this.cookie.get(TOTPStore.COOKIE_NAME) if (raw) { const params = new URLSearchParams(raw) this.email = params.get('email') || undefined + const totpRaw = params.get('totp') if (totpRaw) { try { this.totp = JSON.parse(totpRaw) - } catch {} + } catch { + // Silently handle invalid JSON in the TOTP data. + } } + const err = params.get('error') if (err) { this.error = { message: err } @@ -116,31 +304,60 @@ class TOTPStore { } } - static fromRequest(request: Request) { + /** + * Creates a TOTPStore instance from a Request object. + * @param request - The incoming request object. + * @returns A new TOTPStore instance. + */ + static fromRequest(request: Request): TOTPStore { return new TOTPStore(new Cookie(request.headers.get('cookie') ?? '')) } - getEmail() { + /** + * Gets the stored email address. + * @returns The email address or undefined if not set. + */ + getEmail(): string | undefined { return this.email } - getTOTP() { + /** + * Gets the stored TOTP session data. + * @returns The TOTP session data or undefined if not set. + */ + getTOTP(): TOTPSessionData | undefined { return this.totp } - getError() { + /** + * Gets the stored error message. + * @returns The error object or undefined if no error exists. + */ + getError(): { message: string } | undefined { return this.error } - setEmail(email: string | undefined) { + /** + * Sets the email address in the store. + * @param email - The email address to store or undefined to clear it. + */ + setEmail(email: string | undefined): void { this.email = email } - setTOTP(totp: TOTPSessionData | undefined) { + /** + * Sets the TOTP session data in the store. + * @param totp - The TOTP session data to store or undefined to clear it. + */ + setTOTP(totp: TOTPSessionData | undefined): void { this.totp = totp } - setError(message: string | undefined) { + /** + * Sets an error message in the store. + * @param message - The error message to store or undefined to clear it. + */ + setError(message: string | undefined): void { if (message) { this.error = { message } } else { @@ -148,27 +365,40 @@ class TOTPStore { } } + /** + * Commits the current store state to a cookie string. + * @returns A string representation of the cookie with all current values. + */ commit(): string { const params = new URLSearchParams() - if (this.email) params.set('email', this.email) - if (this.totp) params.set('totp', JSON.stringify(this.totp)) - if (this.error) params.set('error', this.error.message) + + if (this.email) { + params.set('email', this.email) + } + + if (this.totp) { + params.set('totp', JSON.stringify(this.totp)) + } + + if (this.error) { + params.set('error', this.error.message) + } + const setCookie = new SetCookie({ name: TOTPStore.COOKIE_NAME, value: params.toString(), httpOnly: true, + secure: true, path: '/', sameSite: 'Lax', - secure: true, }) + return setCookie.toString() } } export class TOTPStrategy extends Strategy { public name = STRATEGY_NAME - private successRedirect: string - private failureRedirect: string private readonly secret: string private readonly maxAge: number | undefined @@ -178,13 +408,13 @@ export class TOTPStrategy extends Strategy { private readonly customErrors: Required private readonly emailFieldKey: string private readonly codeFieldKey: string - private readonly sessionEmailKey: string - private readonly sessionTotpKey: string private readonly sendTOTP: SendTOTP private readonly validateEmail: ValidateEmail + private readonly successRedirect: string + private readonly failureRedirect: string private readonly _totpGenerationDefaults = { - algorithm: 'SHA-256', - charSet: 'abcdefghijklmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ123456789', + algorithm: 'SHA-256', // More secure than SHA1. + charSet: 'abcdefghijklmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ123456789', // No O or 0 digits: 6, period: 60, maxAttempts: 3, @@ -207,13 +437,10 @@ export class TOTPStrategy extends Strategy { this.magicLinkPath = options.magicLinkPath ?? '/magic-link' this.emailFieldKey = options.emailFieldKey ?? FORM_FIELDS.EMAIL this.codeFieldKey = options.codeFieldKey ?? FORM_FIELDS.CODE - this.sessionEmailKey = options.sessionEmailKey ?? SESSION_KEYS.EMAIL - this.sessionTotpKey = options.sessionTotpKey ?? SESSION_KEYS.TOTP this.sendTOTP = options.sendTOTP this.validateEmail = options.validateEmail ?? this._validateEmailDefault this.successRedirect = options.successRedirect this.failureRedirect = options.failureRedirect - this.totpGeneration = { ...this._totpGenerationDefaults, ...options.totpGeneration, @@ -223,19 +450,34 @@ export class TOTPStrategy extends Strategy { ...options.customErrors, } } - - async authenticate( - request: Request, - ): Promise { + + /** + * Authenticates a user using TOTP. + * + * If the user is already authenticated, simply returns the user. + * + * | Method | Email | Code | Sess. Email | Sess. TOTP | Action/Logic | + * |--------|-------|------|-------------|------------|------------------------------------------| + * | POST | ✓ | - | - | - | Generate/send TOTP using form email. | + * | POST | ✗ | ✗ | ✓ | - | Generate/send TOTP using session email. | + * | POST | ✗ | ✓ | ✓ | ✓ | Validate form TOTP code. | + * | GET | - | - | ✓ | ✓ | Validate magic link TOTP. | + * + * @param {Request} request - The request object. + * @param {SessionStorage} sessionStorage - The session storage instance. + * @param {AuthenticateOptions} options - The authentication options. successRedirect is required. + * @returns {Promise} The authenticated user. + */ + async authenticate(request: Request): Promise { if (!this.secret) throw new Error(ERRORS.REQUIRED_ENV_SECRET) if (!this.successRedirect) throw new Error(ERRORS.REQUIRED_SUCCESS_REDIRECT_URL) if (!this.failureRedirect) throw new Error(ERRORS.REQUIRED_FAILURE_REDIRECT_URL) - // Retrieve the TOTP store from cookies + // Retrieve the TOTP store from request. const store = TOTPStore.fromRequest(request) - // If you previously stored a user in session, you'd need a separate cookie or logic. - // For minimal changes, we assume there's no pre-authenticated user: + // Assume no pre-authenticated user for simplicity. + // If previously user were stored in session, a separate cookie or logic is required. const user: User | null = null if (user) return user @@ -251,7 +493,10 @@ export class TOTPStrategy extends Strategy { try { if (email) { + // Generate the TOTP. const { code, jwe, magicLink } = await this._generateTOTP({ email, request }) + + // Send the TOTP to the user. await this.sendTOTP({ email, code, @@ -267,47 +512,71 @@ export class TOTPStrategy extends Strategy { throw redirect(this.successRedirect, { headers: { + // TODO: add a way to handle maxAge. 'Set-Cookie': store.commit(), }, }) } + // Get the TOTP code, either from form data or magic link. const code = formDataCode ?? this._getMagicLinkCode(request) + if (code) { if (!sessionEmail) throw new Error(this.customErrors.missingSessionEmail) if (!sessionTotp) throw new Error(this.customErrors.expiredTotp) + + // Validate the TOTP. await this._validateTOTP({ code, sessionTotp, store }) - // Clear TOTP data since user verified successfully + // Clear TOTP data since user verified successfully. store.setEmail(undefined) store.setTOTP(undefined) store.setError(undefined) - // If you want to store authenticated user, you'd do it with another cookie here - // e.g. store user session with your own logic + // TODO: Store the user in session (Optional) + // ... throw redirect(this.successRedirect, { headers: { + // TODO: add a way to handle maxAge. 'Set-Cookie': store.commit(), }, }) } - throw new Error(this.customErrors.requiredEmail) - } catch (throwable) { - if (throwable instanceof Response) throw throwable - if (throwable instanceof Error) { - store.setError(throwable.message) + } catch (err: unknown) { + if (err instanceof Response) throw err + if (err instanceof Error) { + store.setError(err.message) throw redirect(this.failureRedirect, { headers: { + // TODO: add a way to handle maxAge. 'Set-Cookie': store.commit(), }, }) } - throw throwable + throw err + } + } + + /** + * Reads the form data from the request. + * @param request - The request object. + * @returns The form data. + */ + private async _readFormData(request: Request) { + if (request.method !== 'POST') { + return new FormData() } + return await request.formData() } + /** + * Validates the TOTP. + * @param code - The TOTP code. + * @param sessionTotp - The TOTP session data. + * @param store - The TOTP store. + */ private async _validateTOTP({ code, sessionTotp, @@ -318,6 +587,7 @@ export class TOTPStrategy extends Strategy { store: TOTPStore }) { try { + // https://github.com/panva/jose/blob/main/docs/functions/jwe_compact_decrypt.compactDecrypt.md const { plaintext } = await jose.compactDecrypt( sessionTotp.jwe, asJweKey(this.secret), @@ -325,10 +595,20 @@ export class TOTPStrategy extends Strategy { const totpData = JSON.parse(new TextDecoder().decode(plaintext)) assertTOTPData(totpData) - if (Date.now() - totpData.createdAt > this.totpGeneration.period * 1000) { + // Check if the TOTP is expired. + const dateNow = Date.now() + const isExpired = dateNow - totpData.createdAt > this.totpGeneration.period * 1000 + if (isExpired) { throw new Error(this.customErrors.expiredTotp) } - if (!await verifyTOTP({ ...this.totpGeneration, secret: totpData.secret, otp: code })) { + + // Check if the TOTP is valid. + const isValid = await verifyTOTP({ + ...this.totpGeneration, + secret: totpData.secret, + otp: code, + }) + if (!isValid) { throw new Error(this.customErrors.invalidTotp) } } catch (error) { @@ -337,6 +617,7 @@ export class TOTPStrategy extends Strategy { store.setError(this.customErrors.expiredTotp) } else { sessionTotp.attempts += 1 + // Check if the user has reached the max number of attempts. if (sessionTotp.attempts >= this.totpGeneration.maxAttempts) { store.setTOTP(undefined) } else { @@ -344,21 +625,24 @@ export class TOTPStrategy extends Strategy { } store.setError(this.customErrors.invalidTotp) } + + // Redirect to the failure URL with the updated store. throw redirect(this.failureRedirect, { headers: { + // TODO: add a way to handle maxAge + // or it is required on error? 'Set-Cookie': store.commit(), }, }) } } - private async _readFormData(request: Request) { - if (request.method !== 'POST') { - return new FormData() - } - return await request.formData() - } - + /** + * Generates the TOTP. + * @param email - The email address. + * @param request - The request object. + * @returns The TOTP data. + */ private async _generateTOTP({ email, request }: { email: string; request: Request }) { const isValidEmail = await this.validateEmail(email) if (!isValidEmail) throw new Error(this.customErrors.invalidEmail) @@ -367,7 +651,7 @@ export class TOTPStrategy extends Strategy { ...this.totpGeneration, secret: this.totpGeneration.secret ?? generateSecret(), }) - const totpData = { secret, createdAt: Date.now() } + const totpData: TOTPData = { secret, createdAt: Date.now() } const jwe = await new jose.CompactEncrypt( new TextEncoder().encode(JSON.stringify(totpData)), @@ -376,20 +660,31 @@ export class TOTPStrategy extends Strategy { .encrypt(asJweKey(this.secret)) const magicLink = this._generateMagicLink({ code, request }) - return { code, jwe, magicLink } + + return { + code, + jwe, + magicLink, + } } + /** + * Generates the magic link. + * @param code - The TOTP code. + * @param request - The request object. + * @returns The magic link. + */ private _generateMagicLink({ code, request }: { code: string; request: Request }) { const url = new URL(this.magicLinkPath ?? '/', new URL(request.url).origin) url.searchParams.set(this.codeFieldKey, code) return url.toString() } - private async _validateEmailDefault(email: string) { - const regexEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/gm - return regexEmail.test(email) - } - + /** + * Gets the magic link code from the request. + * @param request - The request object. + * @returns The magic link code. + */ private _getMagicLinkCode(request: Request) { if (request.method === 'GET') { const url = new URL(request.url) @@ -402,4 +697,14 @@ export class TOTPStrategy extends Strategy { } return undefined } + + /** + * Validates the email format. + * @param email - The email address. + * @returns Whether the email is valid. + */ + private async _validateEmailDefault(email: string) { + const regexEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/gm + return regexEmail.test(email) + } } diff --git a/src/lib/redirect.ts b/src/lib/redirect.ts deleted file mode 100644 index dbbd2c0..0000000 --- a/src/lib/redirect.ts +++ /dev/null @@ -1,14 +0,0 @@ -export function redirect(url: string, init: ResponseInit | number = 302) { - let responseInit = init; - - if (typeof responseInit === "number") { - responseInit = { status: responseInit }; - } else if (typeof responseInit.status === "undefined") { - responseInit.status = 302; - } - - const headers = new Headers(responseInit.headers); - headers.set("Location", url); - - return new Response(null, { ...responseInit, headers }); -} \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts index a28561e..1daa353 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -5,23 +5,11 @@ import base32Encode from 'base32-encode' * TOTP Generation. */ export function generateSecret() { - const randomBytes = new Uint8Array(32); - crypto.getRandomValues(randomBytes); + const randomBytes = new Uint8Array(32) + crypto.getRandomValues(randomBytes) return base32Encode(randomBytes, 'RFC4648').toString() as string } -export function generateMagicLink(options: { - code: string - magicLinkPath: string - param: string - request: Request -}) { - const url = new URL(options.magicLinkPath ?? '/', new URL(options.request.url).origin) - url.searchParams.set(options.param, options.code) - - return url.toString() -} - // https://github.com/sindresorhus/uint8array-extras/blob/main/index.js#L222 const hexToDecimalLookupTable = { 0: 0, @@ -46,27 +34,51 @@ const hexToDecimalLookupTable = { D: 13, E: 14, F: 15, -}; +} function hexToUint8Array(hexString: string) { if (hexString.length % 2 !== 0) { - throw new Error('Invalid Hex string length.'); + throw new Error('Invalid Hex string length.') } - const resultLength = hexString.length / 2; - const bytes = new Uint8Array(resultLength); + const resultLength = hexString.length / 2 + const bytes = new Uint8Array(resultLength) for (let index = 0; index < resultLength; index++) { - const highNibble = hexToDecimalLookupTable[hexString[index * 2] as keyof typeof hexToDecimalLookupTable]; - const lowNibble = hexToDecimalLookupTable[hexString[(index * 2) + 1] as keyof typeof hexToDecimalLookupTable]; + const highNibble = + hexToDecimalLookupTable[ + hexString[index * 2] as keyof typeof hexToDecimalLookupTable + ] + const lowNibble = + hexToDecimalLookupTable[ + hexString[index * 2 + 1] as keyof typeof hexToDecimalLookupTable + ] if (highNibble === undefined || lowNibble === undefined) { - throw new Error(`Invalid Hex character encountered at position ${index * 2}`); + throw new Error(`Invalid Hex character encountered at position ${index * 2}`) } - bytes[index] = (highNibble << 4) | lowNibble; + bytes[index] = (highNibble << 4) | lowNibble + } + + return bytes +} + +/** + * Redirect. + */ +export function redirect(url: string, init: ResponseInit | number = 302) { + let responseInit = init + + if (typeof responseInit === 'number') { + responseInit = { status: responseInit } + } else if (typeof responseInit.status === 'undefined') { + responseInit.status = 302 } - return bytes; + const headers = new Headers(responseInit.headers) + headers.set('Location', url) + + return new Response(null, { ...responseInit, headers }) } /** diff --git a/test/index.spec.ts b/test/index.spec.ts index 0ced9ec..eefb998 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -1,12 +1,10 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ import type { SendTOTPOptions, TOTPStrategyOptions } from '../src/index' - import { describe, test, expect, beforeEach, afterEach, vi } from 'vitest' -import invariant from 'tiny-invariant' - +import { Cookie, SetCookie } from '@mjackson/headers' import { TOTPStrategy } from '../src/index' -import { asJweKey, generateMagicLink } from '../src/utils' +import { asJweKey } from '../src/utils' import { STRATEGY_NAME, FORM_FIELDS, ERRORS } from '../src/constants' - import { SECRET_ENV, HOST_URL, @@ -14,7 +12,6 @@ import { DEFAULT_EMAIL, MAGIC_LINK_PATH, } from './utils' -import { Cookie, SetCookie } from '@mjackson/headers' /** * Mocks. @@ -132,8 +129,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe('/verify') - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe('/verify') + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') const params = new URLSearchParams(raw!) @@ -175,8 +172,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe('/verify') - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe('/verify') + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') const params = new URLSearchParams(raw!) @@ -215,8 +212,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toMatch('/verify') - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toMatch('/verify') + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') const params = new URLSearchParams(raw!) @@ -250,8 +247,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(requestToPopulateSessionEmail).catch((reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe('/verify') - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe('/verify') + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -281,9 +278,9 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch((reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe('/verify') + expect(reason.headers.get('Location')).toBe('/verify') - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -327,8 +324,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(requestToPopulate).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe('/verify') - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe('/verify') + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') const params = new URLSearchParams(raw!) @@ -350,8 +347,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(emptyFormRequest).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe('/verify') - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe('/verify') + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -395,8 +392,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(requestToPopulateEmail).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe('/verify') - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe('/verify') + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -420,8 +417,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(appFormRequest).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe('/verify') - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe('/verify') + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -454,9 +451,9 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe('/login') + expect(reason.headers.get('Location')).toBe('/login') - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -491,9 +488,9 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe('/login') + expect(reason.headers.get('Location')).toBe('/login') - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -529,8 +526,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe('/login') - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe('/login') + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -556,8 +553,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe('/login') - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe('/login') + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -612,8 +609,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe('/verify') - totpCookie = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe('/verify') + totpCookie = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(totpCookie) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -625,9 +622,9 @@ describe('[ TOTP ]', () => { expect(sendTOTP).toHaveBeenCalledTimes(1) expect(sendTOTPOptions).toBeDefined() - invariant(sendTOTPOptions, 'Undefined sendTOTPOptions') + if (!sendTOTPOptions) throw new Error('Undefined sendTOTPOptions.') expect(totpCookie).toBeDefined() - invariant(totpCookie, 'Undefined cookie') + if (!totpCookie) throw new Error('Undefined cookie.') return { strategy, sendTOTPOptions, totpCookie, user } } @@ -662,8 +659,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe(`/account`) - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe(`/account`) + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -706,8 +703,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe(`/verify`) - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe(`/verify`) + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -753,8 +750,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe(`/verify`) - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe(`/verify`) + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -765,6 +762,7 @@ describe('[ TOTP ]', () => { }) test('Should failure redirect on invalid and max TOTP attempts.', async () => { + // eslint-disable-next-line prefer-const let { user, totpCookie, sendTOTPOptions } = await setupGenerateSendTOTP() const strategy = new TOTPStrategy( { @@ -796,8 +794,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe(`/verify`) - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe(`/verify`) + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' totpCookie = setCookieHeader const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') @@ -850,8 +848,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe(`/verify`) - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe(`/verify`) + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -900,8 +898,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe(`/verify`) - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe(`/verify`) + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -932,7 +930,7 @@ describe('[ TOTP ]', () => { }, ) expect(sendTOTPOptions.magicLink).toBeDefined() - invariant(sendTOTPOptions.magicLink, 'Magic link is undefined.') + if (!sendTOTPOptions.magicLink) throw new Error('Magic link is undefined.') const request = new Request(sendTOTPOptions.magicLink, { method: 'GET', headers: { @@ -942,8 +940,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe(`/account`) - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe(`/account`) + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -958,7 +956,7 @@ describe('[ TOTP ]', () => { test('Should failure redirect on invalid magic-link code.', async () => { const { strategy, sendTOTPOptions, totpCookie } = await setupGenerateSendTOTP() expect(sendTOTPOptions.magicLink).toBeDefined() - invariant(sendTOTPOptions.magicLink, 'Magic link is undefined.') + if (!sendTOTPOptions.magicLink) throw new Error('Magic link is undefined.') const request = new Request(sendTOTPOptions.magicLink + 'INVALID', { method: 'GET', headers: { @@ -968,8 +966,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe(`/login`) - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe(`/login`) + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -982,7 +980,7 @@ describe('[ TOTP ]', () => { test('Should failure redirect on expired magic-link.', async () => { const { strategy, sendTOTPOptions, totpCookie } = await setupGenerateSendTOTP() expect(sendTOTPOptions.magicLink).toBeDefined() - invariant(sendTOTPOptions.magicLink, 'Magic link is undefined.') + if (!sendTOTPOptions.magicLink) throw new Error('Magic link is undefined.') vi.setSystemTime( new Date(Date.now() + 1000 * 60 * (TOTP_GENERATION_DEFAULTS.period + 1)), ) @@ -995,8 +993,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe(`/login`) - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe(`/login`) + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -1009,7 +1007,7 @@ describe('[ TOTP ]', () => { test('Should failure redirect on invalid magic-link path.', async () => { const { strategy, sendTOTPOptions, totpCookie } = await setupGenerateSendTOTP() expect(sendTOTPOptions.magicLink).toBeDefined() - invariant(sendTOTPOptions.magicLink, 'Magic link is undefined.') + if (!sendTOTPOptions.magicLink) throw new Error('Magic link is undefined.') expect(sendTOTPOptions.magicLink).toMatch(MAGIC_LINK_PATH) const request = new Request( sendTOTPOptions.magicLink.replace(MAGIC_LINK_PATH, '/invalid-magic-link'), @@ -1023,8 +1021,8 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe(`/login`) - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + expect(reason.headers.get('Location')).toBe(`/login`) + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -1036,7 +1034,7 @@ describe('[ TOTP ]', () => { }) test('Should failure redirect on missing email.', async () => { - const { strategy, sendTOTPOptions, totpCookie } = await setupGenerateSendTOTP() + const { strategy, totpCookie } = await setupGenerateSendTOTP() const modifiedCookie = new Cookie(totpCookie) const raw = modifiedCookie.get('_totp') expect(raw).toBeDefined() @@ -1062,9 +1060,9 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe(`/login`) + expect(reason.headers.get('Location')).toBe(`/login`) - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -1076,7 +1074,7 @@ describe('[ TOTP ]', () => { }) test('Should failure redirect on stale magic-link.', async () => { - let { strategy, sendTOTPOptions, totpCookie } = await setupGenerateSendTOTP() + const { strategy, totpCookie } = await setupGenerateSendTOTP() const modifiedCookie = new Cookie(totpCookie) const raw = modifiedCookie.get('_totp') expect(raw).toBeDefined() @@ -1102,9 +1100,9 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe(`/login`) + expect(reason.headers.get('Location')).toBe(`/login`) - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') expect(raw).toBeDefined() @@ -1116,6 +1114,7 @@ describe('[ TOTP ]', () => { }) test('Should failure redirect on magic-link invalid and max TOTP attempts.', async () => { + // eslint-disable-next-line prefer-const let { user, totpCookie, sendTOTPOptions } = await setupGenerateSendTOTP() const strategy = new TOTPStrategy( { @@ -1135,7 +1134,7 @@ describe('[ TOTP ]', () => { }, ) expect(sendTOTPOptions.magicLink).toBeDefined() - invariant(sendTOTPOptions.magicLink, 'Magic link is undefined.') + if (!sendTOTPOptions.magicLink) throw new Error('Magic link is undefined.') for (let i = 0; i <= TOTP_GENERATION_DEFAULTS.maxAttempts; i++) { const request = new Request(sendTOTPOptions.magicLink + 'INVALID', { @@ -1148,9 +1147,9 @@ describe('[ TOTP ]', () => { await strategy.authenticate(request).catch(async (reason) => { if (reason instanceof Response) { expect(reason.status).toBe(302) - expect(reason.headers.get('location')).toBe(`/verify`) + expect(reason.headers.get('Location')).toBe(`/verify`) - const setCookieHeader = reason.headers.get('set-cookie') ?? '' + const setCookieHeader = reason.headers.get('Set-Cookie') ?? '' totpCookie = setCookieHeader const cookie = new Cookie(setCookieHeader) const raw = cookie.get('_totp') @@ -1176,25 +1175,45 @@ describe('[ TOTP ]', () => { describe('[ Utils ]', () => { test('Should use the origin from the request for the magic-link.', async () => { const samples: Array<[string, string]> = [ - ['http://localhost/login', 'http://localhost/magic-link?code=U2N2EY'], - ['http://localhost:3000/login', 'http://localhost:3000/magic-link?code=U2N2EY'], - ['http://127.0.0.1/login', 'http://127.0.0.1/magic-link?code=U2N2EY'], - ['http://127.0.0.1:3000/login', 'http://127.0.0.1:3000/magic-link?code=U2N2EY'], - ['http://localhost:8788/signin', 'http://localhost:8788/magic-link?code=U2N2EY'], - ['https://host.com/login', 'https://host.com/magic-link?code=U2N2EY'], - ['https://host.com:3000/login', 'https://host.com:3000/magic-link?code=U2N2EY'], + ['http://localhost/login', 'http://localhost/magic-link\\?code='], + ['http://localhost:3000/login', 'http://localhost:3000/magic-link\\?code='], + ['http://127.0.0.1/login', 'http://127\\.0\\.0\\.1/magic-link\\?code='], + ['http://127.0.0.1:3000/login', 'http://127\\.0\\.0\\.1:3000/magic-link\\?code='], + ['http://localhost:8788/signin', 'http://localhost:8788/magic-link\\?code='], + ['https://host.com/login', 'https://host\\.com/magic-link\\?code='], + ['https://host.com:3000/login', 'https://host\\.com:3000/magic-link\\?code='], ] - for (const [requestUrl, magicLinkUrl] of samples) { - const request = new Request(requestUrl) - expect( - generateMagicLink({ - magicLinkPath: '/magic-link', - param: 'code', - code: 'U2N2EY', - request, - }), - ).toBe(magicLinkUrl) + for (const [requestUrl, magicLinkBase] of samples) { + let capturedMagicLink: string | undefined + + // Mock sendTOTP to capture the generated magic link. + sendTOTP.mockImplementation(async (options: SendTOTPOptions) => { + capturedMagicLink = options.magicLink + }) + + const strategy = new TOTPStrategy( + { + ...BASE_STRATEGY_OPTIONS, + successRedirect: '/verify', + failureRedirect: '/login', + }, + verify, + ) + + const formData = new FormData() + formData.append(FORM_FIELDS.EMAIL, DEFAULT_EMAIL) + const request = new Request(requestUrl, { + method: 'POST', + body: formData, + }) + + await strategy.authenticate(request).catch(() => { + // We expect this to throw since it redirects. + expect(capturedMagicLink).toBeDefined() + const regex = new RegExp(`^${magicLinkBase}[A-Za-z0-9]+$`) + expect(capturedMagicLink).toMatch(regex) + }) } }) diff --git a/test/utils.ts b/test/utils.ts index 206b7f2..24a9fc7 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -5,8 +5,8 @@ import type { TOTPGenerationOptions } from '../src' */ export const SECRET_ENV = 'b2FE35059924CDBF5B52A84765B8B010F5291993A9BC39410139D4F511006034' -export const HOST_URL = 'https://prodserver.com' -export const DEFAULT_EMAIL = 'user@gmail.com' +export const HOST_URL = 'https://example.com' +export const DEFAULT_EMAIL = 'user@email.com' export const MAGIC_LINK_PATH = '/magic-link' /** @@ -17,7 +17,7 @@ export const AUTH_OPTIONS = { sessionKey: 'user', sessionErrorKey: 'error', sessionStrategyKey: 'strategy', -} +} as const export const TOTP_GENERATION_DEFAULTS: Required< Pick diff --git a/vitest-setup.ts b/vitest-setup.ts deleted file mode 100644 index c923c00..0000000 --- a/vitest-setup.ts +++ /dev/null @@ -1,7 +0,0 @@ - - -/** - * Remix relies on browser API's such as fetch that are not natively available in Node.js, - * you may find that unit tests fail without these globals, when running with tools such as Jest. - */ -// installGlobals() diff --git a/vitest.config.ts b/vitest.config.ts index a3a1497..af887e0 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -16,9 +16,6 @@ export default defineConfig({ // Environment. environment: 'node', - // Path to setup files. They will be run before each test file. - setupFiles: ['./vitest-setup.ts'], - // Excludes files from test. exclude: ['node_modules'],