diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 000000000..24d5e769f --- /dev/null +++ b/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: [["@babel/preset-env", { targets: { node: "current" } }]], +}; diff --git a/examples/typescript/passkey/.eslintrc.cjs b/examples/typescript/passkey/.eslintrc.cjs new file mode 100644 index 000000000..d6c953795 --- /dev/null +++ b/examples/typescript/passkey/.eslintrc.cjs @@ -0,0 +1,18 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parser: '@typescript-eslint/parser', + plugins: ['react-refresh'], + rules: { + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, +} diff --git a/examples/typescript/passkey/.gitignore b/examples/typescript/passkey/.gitignore new file mode 100644 index 000000000..a547bf36d --- /dev/null +++ b/examples/typescript/passkey/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/examples/typescript/passkey/README.md b/examples/typescript/passkey/README.md new file mode 100644 index 000000000..0d6babedd --- /dev/null +++ b/examples/typescript/passkey/README.md @@ -0,0 +1,30 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: + +- Configure the top-level `parserOptions` property like this: + +```js +export default { + // other rules... + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['./tsconfig.json', './tsconfig.node.json'], + tsconfigRootDir: __dirname, + }, +} +``` + +- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` +- Optionally add `plugin:@typescript-eslint/stylistic-type-checked` +- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list diff --git a/examples/typescript/passkey/index.html b/examples/typescript/passkey/index.html new file mode 100644 index 000000000..e4b78eae1 --- /dev/null +++ b/examples/typescript/passkey/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/examples/typescript/passkey/package.json b/examples/typescript/passkey/package.json new file mode 100644 index 000000000..a3a212ccf --- /dev/null +++ b/examples/typescript/passkey/package.json @@ -0,0 +1,33 @@ +{ + "name": "passkey", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "elliptic": "^6.5.6", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "peerDependencies": { + "@aptos-labs/ts-sdk": "link:../../.." + }, + "devDependencies": { + "@types/elliptic": "^6.4.18", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.13.1", + "@typescript-eslint/parser": "^7.13.1", + "@vitejs/plugin-react": "^4.3.1", + "eslint": "^8.57.0", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-react-refresh": "^0.4.7", + "typescript": "^5.2.2", + "vite": "^5.3.1" + } +} diff --git a/examples/typescript/passkey/pnpm-lock.yaml b/examples/typescript/passkey/pnpm-lock.yaml new file mode 100644 index 000000000..32a06a860 --- /dev/null +++ b/examples/typescript/passkey/pnpm-lock.yaml @@ -0,0 +1,2228 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@aptos-labs/ts-sdk': + specifier: link:../../.. + version: link:../../.. + elliptic: + specifier: ^6.5.6 + version: 6.5.6 + react: + specifier: ^18.3.1 + version: 18.3.1 + react-dom: + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) + devDependencies: + '@types/elliptic': + specifier: ^6.4.18 + version: 6.4.18 + '@types/react': + specifier: ^18.3.3 + version: 18.3.3 + '@types/react-dom': + specifier: ^18.3.0 + version: 18.3.0 + '@typescript-eslint/eslint-plugin': + specifier: ^7.13.1 + version: 7.16.0(@typescript-eslint/parser@7.16.0(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3) + '@typescript-eslint/parser': + specifier: ^7.13.1 + version: 7.16.0(eslint@8.57.0)(typescript@5.5.3) + '@vitejs/plugin-react': + specifier: ^4.3.1 + version: 4.3.1(vite@5.3.3(@types/node@20.14.12)) + eslint: + specifier: ^8.57.0 + version: 8.57.0 + eslint-plugin-react-hooks: + specifier: ^4.6.2 + version: 4.6.2(eslint@8.57.0) + eslint-plugin-react-refresh: + specifier: ^0.4.7 + version: 0.4.7(eslint@8.57.0) + typescript: + specifier: ^5.2.2 + version: 5.5.3 + vite: + specifier: ^5.3.1 + version: 5.3.3(@types/node@20.14.12) + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@babel/code-frame@7.24.7': + resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.24.7': + resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.24.7': + resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.24.7': + resolution: {integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.24.7': + resolution: {integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-environment-visitor@7.24.7': + resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-function-name@7.24.7': + resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-hoist-variables@7.24.7': + resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.24.7': + resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.24.7': + resolution: {integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.24.7': + resolution: {integrity: sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-simple-access@7.24.7': + resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-split-export-declaration@7.24.7': + resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.24.7': + resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.24.7': + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.24.7': + resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.24.7': + resolution: {integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.24.7': + resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.24.7': + resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.24.7': + resolution: {integrity: sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.24.7': + resolution: {integrity: sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.24.7': + resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.24.7': + resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.24.7': + resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==} + engines: {node: '>=6.9.0'} + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@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.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + 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.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + 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.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + 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.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + 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.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + 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.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@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.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + 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.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 + + '@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.4.15': + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + + '@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'} + + '@rollup/rollup-android-arm-eabi@4.18.1': + resolution: {integrity: sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.18.1': + resolution: {integrity: sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.18.1': + resolution: {integrity: sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.18.1': + resolution: {integrity: sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-linux-arm-gnueabihf@4.18.1': + resolution: {integrity: sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.18.1': + resolution: {integrity: sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.18.1': + resolution: {integrity: sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.18.1': + resolution: {integrity: sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': + resolution: {integrity: sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.18.1': + resolution: {integrity: sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.18.1': + resolution: {integrity: sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.18.1': + resolution: {integrity: sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.18.1': + resolution: {integrity: sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.18.1': + resolution: {integrity: sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.18.1': + resolution: {integrity: sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.18.1': + resolution: {integrity: sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==} + cpu: [x64] + os: [win32] + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.6.8': + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.6': + resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + + '@types/bn.js@5.1.5': + resolution: {integrity: sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==} + + '@types/elliptic@6.4.18': + resolution: {integrity: sha512-UseG6H5vjRiNpQvrhy4VF/JXdA3V/Fp5amvveaL+fs28BZ6xIKJBPnUPRlEaZpysD9MbpfaLi8lbl7PGUAkpWw==} + + '@types/estree@1.0.5': + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + + '@types/node@20.14.12': + resolution: {integrity: sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==} + + '@types/prop-types@15.7.12': + resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} + + '@types/react-dom@18.3.0': + resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} + + '@types/react@18.3.3': + resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} + + '@typescript-eslint/eslint-plugin@7.16.0': + resolution: {integrity: sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + '@typescript-eslint/parser': ^7.0.0 + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@7.16.0': + resolution: {integrity: sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/scope-manager@7.16.0': + resolution: {integrity: sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/type-utils@7.16.0': + resolution: {integrity: sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/types@7.16.0': + resolution: {integrity: sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/typescript-estree@7.16.0': + resolution: {integrity: sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/utils@7.16.0': + resolution: {integrity: sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + + '@typescript-eslint/visitor-keys@7.16.0': + resolution: {integrity: sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@ungap/structured-clone@1.2.0': + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + + '@vitejs/plugin-react@4.3.1': + resolution: {integrity: sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.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@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + 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'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + bn.js@4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + browserslist@4.23.1: + resolution: {integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001640: + resolution: {integrity: sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + debug@4.3.5: + resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + 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'} + + electron-to-chromium@1.4.820: + resolution: {integrity: sha512-kK/4O/YunacfboFEk/BDf7VO1HoPmDudLTJAU9NmXIOSjsV7qVIX3OrI4REZo0VmdqhcpUcncQc6N8Q3aEXlHg==} + + elliptic@6.5.6: + resolution: {integrity: sha512-mpzdtpeCLuS3BmE3pO3Cpp5bbjlOPY2Q0PgoF+Od1XZrHLYI28Xe3ossCmYCQt11FQKEYd9+PF8jymTvtWJSHQ==} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-plugin-react-hooks@4.6.2: + resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + + eslint-plugin-react-refresh@0.4.7: + resolution: {integrity: sha512-yrj+KInFmwuQS2UQcg1SF83ha1tuHC1jMQbRNyuWtlEzzKRDgAl7L4Yp4NlDUZTZNlWvHEzOtJhMi40R7JxcSw==} + peerDependencies: + eslint: '>=7' + + 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@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + 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==} + + 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] + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + 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@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + 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'} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + + ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + 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-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + 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'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + 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==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + 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'} + + 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 + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.7: + resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} + engines: {node: '>=8.6'} + + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + 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-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-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + postcss@8.4.39: + resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.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-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} + engines: {node: '>=0.10.0'} + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.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@4.18.1: + resolution: {integrity: sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==} + 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@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.6.2: + resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} + engines: {node: '>=10'} + hasBin: true + + 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'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + engines: {node: '>=0.10.0'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-api-utils@1.3.0: + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + typescript@5.5.3: + resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + update-browserslist-db@1.1.0: + resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + vite@5.3.3: + resolution: {integrity: sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==} + 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: '*' + 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 + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + 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==} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@babel/code-frame@7.24.7': + dependencies: + '@babel/highlight': 7.24.7 + picocolors: 1.0.1 + + '@babel/compat-data@7.24.7': {} + + '@babel/core@7.24.7': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/helpers': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/template': 7.24.7 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + convert-source-map: 2.0.0 + debug: 4.3.5 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.24.7': + dependencies: + '@babel/types': 7.24.7 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + + '@babel/helper-compilation-targets@7.24.7': + dependencies: + '@babel/compat-data': 7.24.7 + '@babel/helper-validator-option': 7.24.7 + browserslist: 4.23.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-environment-visitor@7.24.7': + dependencies: + '@babel/types': 7.24.7 + + '@babel/helper-function-name@7.24.7': + dependencies: + '@babel/template': 7.24.7 + '@babel/types': 7.24.7 + + '@babel/helper-hoist-variables@7.24.7': + dependencies: + '@babel/types': 7.24.7 + + '@babel/helper-module-imports@7.24.7': + dependencies: + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.24.7(@babel/core@7.24.7)': + dependencies: + '@babel/core': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.24.7': {} + + '@babel/helper-simple-access@7.24.7': + dependencies: + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-split-export-declaration@7.24.7': + dependencies: + '@babel/types': 7.24.7 + + '@babel/helper-string-parser@7.24.7': {} + + '@babel/helper-validator-identifier@7.24.7': {} + + '@babel/helper-validator-option@7.24.7': {} + + '@babel/helpers@7.24.7': + dependencies: + '@babel/template': 7.24.7 + '@babel/types': 7.24.7 + + '@babel/highlight@7.24.7': + dependencies: + '@babel/helper-validator-identifier': 7.24.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.1 + + '@babel/parser@7.24.7': + dependencies: + '@babel/types': 7.24.7 + + '@babel/plugin-transform-react-jsx-self@7.24.7(@babel/core@7.24.7)': + dependencies: + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + + '@babel/plugin-transform-react-jsx-source@7.24.7(@babel/core@7.24.7)': + dependencies: + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + + '@babel/template@7.24.7': + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 + + '@babel/traverse@7.24.7': + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-hoist-variables': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 + debug: 4.3.5 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.24.7': + dependencies: + '@babel/helper-string-parser': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + to-fast-properties: 2.0.0 + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.21.5': + 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.5 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.1 + 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.5 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/object-schema@2.0.3': {} + + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.4.15': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + + '@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 + + '@rollup/rollup-android-arm-eabi@4.18.1': + optional: true + + '@rollup/rollup-android-arm64@4.18.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.18.1': + optional: true + + '@rollup/rollup-darwin-x64@4.18.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.18.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.18.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.18.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.18.1': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.18.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.18.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.18.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.18.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.18.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.18.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.18.1': + optional: true + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.6 + + '@types/babel__generator@7.6.8': + dependencies: + '@babel/types': 7.24.7 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 + + '@types/babel__traverse@7.20.6': + dependencies: + '@babel/types': 7.24.7 + + '@types/bn.js@5.1.5': + dependencies: + '@types/node': 20.14.12 + + '@types/elliptic@6.4.18': + dependencies: + '@types/bn.js': 5.1.5 + + '@types/estree@1.0.5': {} + + '@types/node@20.14.12': + dependencies: + undici-types: 5.26.5 + + '@types/prop-types@15.7.12': {} + + '@types/react-dom@18.3.0': + dependencies: + '@types/react': 18.3.3 + + '@types/react@18.3.3': + dependencies: + '@types/prop-types': 15.7.12 + csstype: 3.1.3 + + '@typescript-eslint/eslint-plugin@7.16.0(@typescript-eslint/parser@7.16.0(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3)': + dependencies: + '@eslint-community/regexpp': 4.11.0 + '@typescript-eslint/parser': 7.16.0(eslint@8.57.0)(typescript@5.5.3) + '@typescript-eslint/scope-manager': 7.16.0 + '@typescript-eslint/type-utils': 7.16.0(eslint@8.57.0)(typescript@5.5.3) + '@typescript-eslint/utils': 7.16.0(eslint@8.57.0)(typescript@5.5.3) + '@typescript-eslint/visitor-keys': 7.16.0 + eslint: 8.57.0 + graphemer: 1.4.0 + ignore: 5.3.1 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@7.16.0(eslint@8.57.0)(typescript@5.5.3)': + dependencies: + '@typescript-eslint/scope-manager': 7.16.0 + '@typescript-eslint/types': 7.16.0 + '@typescript-eslint/typescript-estree': 7.16.0(typescript@5.5.3) + '@typescript-eslint/visitor-keys': 7.16.0 + debug: 4.3.5 + eslint: 8.57.0 + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@7.16.0': + dependencies: + '@typescript-eslint/types': 7.16.0 + '@typescript-eslint/visitor-keys': 7.16.0 + + '@typescript-eslint/type-utils@7.16.0(eslint@8.57.0)(typescript@5.5.3)': + dependencies: + '@typescript-eslint/typescript-estree': 7.16.0(typescript@5.5.3) + '@typescript-eslint/utils': 7.16.0(eslint@8.57.0)(typescript@5.5.3) + debug: 4.3.5 + eslint: 8.57.0 + ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@7.16.0': {} + + '@typescript-eslint/typescript-estree@7.16.0(typescript@5.5.3)': + dependencies: + '@typescript-eslint/types': 7.16.0 + '@typescript-eslint/visitor-keys': 7.16.0 + debug: 4.3.5 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.2 + ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@7.16.0(eslint@8.57.0)(typescript@5.5.3)': + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@typescript-eslint/scope-manager': 7.16.0 + '@typescript-eslint/types': 7.16.0 + '@typescript-eslint/typescript-estree': 7.16.0(typescript@5.5.3) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/visitor-keys@7.16.0': + dependencies: + '@typescript-eslint/types': 7.16.0 + eslint-visitor-keys: 3.4.3 + + '@ungap/structured-clone@1.2.0': {} + + '@vitejs/plugin-react@4.3.1(vite@5.3.3(@types/node@20.14.12))': + dependencies: + '@babel/core': 7.24.7 + '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.24.7) + '@types/babel__core': 7.20.5 + react-refresh: 0.14.2 + vite: 5.3.3(@types/node@20.14.12) + transitivePeerDependencies: + - supports-color + + acorn-jsx@5.3.2(acorn@8.12.1): + 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@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + array-union@2.1.0: {} + + balanced-match@1.0.2: {} + + bn.js@4.12.0: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + brorand@1.1.0: {} + + browserslist@4.23.1: + dependencies: + caniuse-lite: 1.0.30001640 + electron-to-chromium: 1.4.820 + node-releases: 2.0.14 + update-browserslist-db: 1.1.0(browserslist@4.23.1) + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001640: {} + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + cross-spawn@7.0.3: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.1.3: {} + + debug@4.3.5: + dependencies: + ms: 2.1.2 + + deep-is@0.1.4: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + electron-to-chromium@1.4.820: {} + + elliptic@6.5.6: + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + 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 + + escalade@3.1.2: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@4.0.0: {} + + eslint-plugin-react-hooks@4.6.2(eslint@8.57.0): + dependencies: + eslint: 8.57.0 + + eslint-plugin-react-refresh@0.4.7(eslint@8.57.0): + dependencies: + eslint: 8.57.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.5 + 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.1 + 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@5.3.0: {} + + esutils@2.0.3: {} + + fast-deep-equal@3.1.3: {} + + 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.7 + + 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: {} + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + gensync@1.0.0-beta.2: {} + + 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@11.12.0: {} + + 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.1 + merge2: 1.4.1 + slash: 3.0.0 + + graphemer@1.4.0: {} + + has-flag@3.0.0: {} + + has-flag@4.0.0: {} + + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + hmac-drbg@1.0.1: + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + ignore@5.3.1: {} + + 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-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-path-inside@3.0.3: {} + + isexe@2.0.0: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsesc@2.5.2: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + 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 + + 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 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + merge2@1.4.1: {} + + micromatch@4.0.7: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + minimalistic-assert@1.0.1: {} + + minimalistic-crypto-utils@1.0.1: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + ms@2.1.2: {} + + nanoid@3.3.7: {} + + natural-compare@1.4.0: {} + + node-releases@2.0.14: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + 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-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-type@4.0.0: {} + + picocolors@1.0.1: {} + + picomatch@2.3.1: {} + + postcss@8.4.39: + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.1 + source-map-js: 1.2.0 + + prelude-ls@1.2.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-refresh@0.14.2: {} + + react@18.3.1: + dependencies: + loose-envify: 1.4.0 + + resolve-from@4.0.0: {} + + reusify@1.0.4: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + rollup@4.18.1: + dependencies: + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.18.1 + '@rollup/rollup-android-arm64': 4.18.1 + '@rollup/rollup-darwin-arm64': 4.18.1 + '@rollup/rollup-darwin-x64': 4.18.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.18.1 + '@rollup/rollup-linux-arm-musleabihf': 4.18.1 + '@rollup/rollup-linux-arm64-gnu': 4.18.1 + '@rollup/rollup-linux-arm64-musl': 4.18.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.18.1 + '@rollup/rollup-linux-riscv64-gnu': 4.18.1 + '@rollup/rollup-linux-s390x-gnu': 4.18.1 + '@rollup/rollup-linux-x64-gnu': 4.18.1 + '@rollup/rollup-linux-x64-musl': 4.18.1 + '@rollup/rollup-win32-arm64-msvc': 4.18.1 + '@rollup/rollup-win32-ia32-msvc': 4.18.1 + '@rollup/rollup-win32-x64-msvc': 4.18.1 + 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@6.3.1: {} + + semver@7.6.2: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + slash@3.0.0: {} + + source-map-js@1.2.0: {} + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-json-comments@3.1.1: {} + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + text-table@0.2.0: {} + + to-fast-properties@2.0.0: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-api-utils@1.3.0(typescript@5.5.3): + dependencies: + typescript: 5.5.3 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@0.20.2: {} + + typescript@5.5.3: {} + + undici-types@5.26.5: {} + + update-browserslist-db@1.1.0(browserslist@4.23.1): + dependencies: + browserslist: 4.23.1 + escalade: 3.1.2 + picocolors: 1.0.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + vite@5.3.3(@types/node@20.14.12): + dependencies: + esbuild: 0.21.5 + postcss: 8.4.39 + rollup: 4.18.1 + optionalDependencies: + '@types/node': 20.14.12 + fsevents: 2.3.3 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrappy@1.0.2: {} + + yallist@3.1.1: {} + + yocto-queue@0.1.0: {} diff --git a/examples/typescript/passkey/public/vite.svg b/examples/typescript/passkey/public/vite.svg new file mode 100644 index 000000000..e7b8dfb1b --- /dev/null +++ b/examples/typescript/passkey/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/typescript/passkey/src/App.css b/examples/typescript/passkey/src/App.css new file mode 100644 index 000000000..b9d355df2 --- /dev/null +++ b/examples/typescript/passkey/src/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/examples/typescript/passkey/src/App.tsx b/examples/typescript/passkey/src/App.tsx new file mode 100644 index 000000000..d7bc511c1 --- /dev/null +++ b/examples/typescript/passkey/src/App.tsx @@ -0,0 +1,218 @@ +import { AccountAddress, Aptos, AptosConfig, Network, Secp256r1PublicKey, postAptosFaucet } from "@aptos-labs/ts-sdk"; +import { useState } from "react"; +import "./App.css"; + +const COIN_STORE = "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>"; + +function App() { + const [credentialId, setCredentialId] = useState(window.localStorage.getItem("credentialId")); + const [publicKey, setPublicKey] = useState(window.localStorage.getItem("publicKey")); + const [recipientAddress, setRecipientAddress] = useState(null); + const [sendAmount, setSendAmount] = useState(0); + const [faucetIsLoading, setFaucetIsLoading] = useState(false); + const [passkeyAddr, setPasskeyAddr] = useState(null); + const [currentNetwork, setCurrentNetwork] = useState(Network.DEVNET); + + const config = new AptosConfig({ network: currentNetwork }); + const aptos = new Aptos(config); + + const rpName = window.location.origin; + const rpID = window.location.hostname; + console.log(rpName, rpID); + + /** + * Prints the balance of an account + * @param aptos + * @param name + * @param address + * @returns {Promise<*>} + * + */ + const balance = async (aptos: Aptos, name: string, address: AccountAddress) => { + type Coin = { coin: { value: string } }; + const resource = await aptos.getAccountResource({ + accountAddress: address, + resourceType: COIN_STORE, + }); + const amount = Number(resource.coin.value); + + console.log(`${name}'s balance is: ${amount}`); + return amount; + }; + + // Create the passkey via credential registration ceremony + const createPasskey = async () => { + const options = await aptos.generateRegistrationOptions({ + rpName, + rpID, + userName: "Andrew", + authenticatorAttachment: "platform", + }); + + const cred = await aptos.registerCredential(options); + console.log(cred); + const pubKey = aptos.parsePublicKey(cred); + const addr = await aptos.getPasskeyAccountAddress({ publicKey: pubKey.toString() }); + + console.log(addr.toString()); + + setCredentialId(cred.rawId); + setPublicKey(aptos.parsePublicKey(cred).toString()); + setPasskeyAddr(addr.toString()); + console.log(cred); + window.localStorage.setItem("credentialId", cred.rawId); + window.localStorage.setItem("publicKey", aptos.parsePublicKey(cred).toString()); + }; + + const fundAccount = async () => { + if (!publicKey) { + alert("No registered publicKey"); + return; + } + + setFaucetIsLoading(true); + + const addr = await aptos.getPasskeyAccountAddress({ publicKey }); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const { data } = await postAptosFaucet }>({ + aptosConfig: config, + path: "fund", + body: { + address: AccountAddress.from(addr).toString(), + amount: 1e9, + }, + originMethod: "fundAccount", + }); + + const txnHash = data.txn_hashes[0]; + + const confirmedTxn = await aptos.waitForTransaction({ transactionHash: txnHash }); + alert("Faucet 1 APT deposited, txn hash: " + confirmedTxn.hash); + + console.log("\n=== Balances ===\n"); + await balance(aptos, "Passkey Account", new AccountAddress(addr.toUint8Array())); + setFaucetIsLoading(false); + }; + + const checkBalance = async () => { + if (!publicKey) { + alert("No registered publicKey"); + return; + } + + const addr = await aptos.getPasskeyAccountAddress({ publicKey }); + + console.log("\n=== Balances ===\n"); + const bal = await balance(aptos, "Passkey Account", new AccountAddress(addr.toUint8Array())); + + window.alert(bal / 1e8 + " APT"); + }; + + /** + * Use the passkey credential registered to the user to sign a coin transfer + */ + const signWithPasskey = async () => { + if (!credentialId) { + alert("No registered credential"); + return; + } + + if (!publicKey) { + alert("No registered publicKey"); + return; + } + + const addr = await aptos.getPasskeyAccountAddress({ publicKey }); + const recipient = AccountAddress.fromString(recipientAddress || "0x1"); + + const txn = await aptos.transferCoinTransaction({ + sender: addr, + recipient: recipient, + amount: sendAmount * 1e8, + }); + + console.log("\n=== Transfer transaction ===\n"); + console.log(credentialId); + console.log(txn); + console.log(publicKey); + console.log(rpID); + const pendingTxn = await aptos.signAndSubmitWithPasskey({ + credentialId: credentialId, + transaction: txn, + publicKey: new Secp256r1PublicKey(publicKey), + rpID, + options: {}, + }); + console.log("PENDING TXN", pendingTxn); + + const committedTxn = await aptos.waitForTransaction({ transactionHash: pendingTxn.hash }); + console.log("COMMITTED TXN", committedTxn); + + // This doesn't work until the indexer works for passkeys + // await aptos.waitForTransaction({ transactionHash: committedTxn.hash }); + // console.log(`Committed transaction: ${committedTxn.hash}`); + }; + + const getAddress = async () => { + if (!credentialId) { + alert("No registered credential"); + return; + } + + if (!publicKey) { + alert("No registered publicKey"); + return; + } + + console.log(publicKey.toString()); + const addr = await aptos.getPasskeyAccountAddress({ publicKey: publicKey }); + setPasskeyAddr(addr.toString()); + + alert(addr); + }; + + const switchNetwork: React.ChangeEventHandler = (event) => { + if (Object.values(Network).includes(event.target.value as Network)) { + setCurrentNetwork(event.target.value as Network); + } else { + alert("Error: Incorrect network selected"); + } + }; + + return ( + <> +

Passkeys Demo

+ {passkeyAddr ?

{"Your address: " + passkeyAddr}

: null} + {passkeyAddr ? ( + + Explorer link + + ) : null} +
+
+ + + + + +
+

Recipient address

+ setRecipientAddress(e.currentTarget.value)} /> +

Send amount (APT)

+ setSendAmount(Number(e.currentTarget.value))} /> +

rpId: {window.location.hostname}

+ +
+ + ); +} + +export default App; diff --git a/examples/typescript/passkey/src/assets/react.svg b/examples/typescript/passkey/src/assets/react.svg new file mode 100644 index 000000000..6c87de9bb --- /dev/null +++ b/examples/typescript/passkey/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/typescript/passkey/src/index.css b/examples/typescript/passkey/src/index.css new file mode 100644 index 000000000..6119ad9a8 --- /dev/null +++ b/examples/typescript/passkey/src/index.css @@ -0,0 +1,68 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/examples/typescript/passkey/src/main.tsx b/examples/typescript/passkey/src/main.tsx new file mode 100644 index 000000000..3d7150da8 --- /dev/null +++ b/examples/typescript/passkey/src/main.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' +import './index.css' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/examples/typescript/passkey/src/recoverPubKey.ts b/examples/typescript/passkey/src/recoverPubKey.ts new file mode 100644 index 000000000..5e6ea913b --- /dev/null +++ b/examples/typescript/passkey/src/recoverPubKey.ts @@ -0,0 +1,65 @@ +import EC from "elliptic"; +const ec = new EC.ec("secp256r1"); + +export async function sha256(message: Uint8Array) { + const hashBuffer = await crypto.subtle.digest("SHA-256", message); + return new Uint8Array(hashBuffer); +} + +export function concatenateUint8Arrays(array1: Uint8Array, array2: Uint8Array) { + const result = new Uint8Array(array1.length + array2.length); + result.set(array1, 0); + result.set(array2, array1.length); + + return result; +} + +export async function recoverPublicKey( + authenticatorData: Uint8Array, + clientDataJSON: Uint8Array, + signature: Uint8Array, +) { + const shaClientDataJSON = await sha256(clientDataJSON); + const message = concatenateUint8Arrays(authenticatorData, shaClientDataJSON); + + const result = await recoverPublicKeyFromMessageAndSignature(message, signature); + return result; +} + +export async function recoverPublicKeyFromMessageAndSignature(message: Uint8Array, signature: Uint8Array) { + // Hash the message + const msgHash = await sha256(message); + + // Assume signature is an object with r and s components + // In real scenarios, ensure to parse the signature from its encoded form + let publicKey; + for (let recoveryId = 0; recoveryId < 2; recoveryId++) { + try { + publicKey = ec.recoverPubKey(msgHash, signature, recoveryId); + // If recovery was successful and publicKey is valid, break out of the loop + if (publicKey) break; + } catch (error) { + // If this recoveryId does not work, catch the error and try the next one + console.error("Recovery with ID", recoveryId, "failed:", error); + } + } + + if (!publicKey) { + throw new Error("Failed to recover public key"); + } + + // Convert the public key to its byte representation + const publicKeyBytes = publicKey.encode("array", false); + console.log(publicKeyBytes); + return publicKeyBytes; +} + +// Example usage (pseudo-code, depends on actual signature format and input) +// const message = 'Your message here'; +// const signature = { r: 'signatureRValue', s: 'signatureSValue' }; +// try { +// const publicKeyBytes = recoverPublicKeyFromSignatureWithoutRecoveryId(message, signature); +// console.log(publicKeyBytes); +// } catch (error) { +// console.error(error); +// } diff --git a/examples/typescript/passkey/src/vite-env.d.ts b/examples/typescript/passkey/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/examples/typescript/passkey/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/typescript/passkey/tsconfig.app.json b/examples/typescript/passkey/tsconfig.app.json new file mode 100644 index 000000000..d739292ae --- /dev/null +++ b/examples/typescript/passkey/tsconfig.app.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/examples/typescript/passkey/tsconfig.json b/examples/typescript/passkey/tsconfig.json new file mode 100644 index 000000000..ea9d0cd82 --- /dev/null +++ b/examples/typescript/passkey/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.node.json" + } + ] +} diff --git a/examples/typescript/passkey/tsconfig.node.json b/examples/typescript/passkey/tsconfig.node.json new file mode 100644 index 000000000..3afdd6e38 --- /dev/null +++ b/examples/typescript/passkey/tsconfig.node.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "strict": true, + "noEmit": true + }, + "include": ["vite.config.ts"] +} diff --git a/examples/typescript/passkey/vite.config.ts b/examples/typescript/passkey/vite.config.ts new file mode 100644 index 000000000..5a33944a9 --- /dev/null +++ b/examples/typescript/passkey/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +}) diff --git a/jest.config.js b/jest.config.js index 7d3ee29f8..82086fa27 100644 --- a/jest.config.js +++ b/jest.config.js @@ -25,4 +25,9 @@ module.exports = { maxWorkers: 4, globalSetup: "./tests/preTest.js", globalTeardown: "./tests/postTest.js", + transform: { + "^.+\\.ts$": "ts-jest", + "^.+\\.js$": "babel-jest", + }, + transformIgnorePatterns: ["node_modules/?!@simplewebauthn"], }; diff --git a/package.json b/package.json index 26cf14142..cdf6942ff 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,8 @@ "@noble/hashes": "^1.4.0", "@scure/bip32": "^1.4.0", "@scure/bip39": "^1.3.0", + "@simplewebauthn/browser": "^10.0.0", + "@simplewebauthn/server": "^10.0.0", "eventemitter3": "^5.0.1", "form-data": "^4.0.0", "js-base64": "^3.7.7", @@ -63,6 +65,7 @@ "poseidon-lite": "^0.2.0" }, "devDependencies": { + "@babel/preset-env": "^7.24.8", "@babel/traverse": "^7.23.6", "@cucumber/cucumber": "^10.8.0", "@graphql-codegen/cli": "^5.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b9508b6ec..70abdc19c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,12 @@ dependencies: '@scure/bip39': specifier: ^1.3.0 version: 1.3.0 + '@simplewebauthn/browser': + specifier: ^10.0.0 + version: 10.0.0 + '@simplewebauthn/server': + specifier: ^10.0.0 + version: 10.0.0 eventemitter3: specifier: ^5.0.1 version: 5.0.1 @@ -40,6 +46,9 @@ dependencies: version: 0.2.0 devDependencies: + '@babel/preset-env': + specifier: ^7.24.8 + version: 7.24.8(@babel/core@7.24.6) '@babel/traverse': specifier: ^7.23.6 version: 7.24.6 @@ -205,11 +214,24 @@ packages: picocolors: 1.0.1 dev: true + /@babel/code-frame@7.24.7: + resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.24.7 + picocolors: 1.0.1 + dev: true + /@babel/compat-data@7.24.6: resolution: {integrity: sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==} engines: {node: '>=6.9.0'} dev: true + /@babel/compat-data@7.24.9: + resolution: {integrity: sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/core@7.24.6: resolution: {integrity: sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ==} engines: {node: '>=6.9.0'} @@ -243,6 +265,16 @@ packages: jsesc: 2.5.2 dev: true + /@babel/generator@7.25.5: + resolution: {integrity: sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.25.4 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + dev: true + /@babel/helper-annotate-as-pure@7.24.6: resolution: {integrity: sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==} engines: {node: '>=6.9.0'} @@ -250,6 +282,23 @@ packages: '@babel/types': 7.24.6 dev: true + /@babel/helper-annotate-as-pure@7.24.7: + resolution: {integrity: sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.9 + dev: true + + /@babel/helper-builder-binary-assignment-operator-visitor@7.24.7: + resolution: {integrity: sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.4 + '@babel/types': 7.24.9 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/helper-compilation-targets@7.24.6: resolution: {integrity: sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==} engines: {node: '>=6.9.0'} @@ -261,6 +310,17 @@ packages: semver: 6.3.1 dev: true + /@babel/helper-compilation-targets@7.24.8: + resolution: {integrity: sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.24.9 + '@babel/helper-validator-option': 7.24.8 + browserslist: 4.23.3 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true + /@babel/helper-create-class-features-plugin@7.24.6(@babel/core@7.24.6): resolution: {integrity: sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA==} engines: {node: '>=6.9.0'} @@ -279,11 +339,65 @@ packages: semver: 6.3.1 dev: true + /@babel/helper-create-class-features-plugin@7.24.8(@babel/core@7.24.6): + resolution: {integrity: sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-member-expression-to-functions': 7.24.8 + '@babel/helper-optimise-call-expression': 7.24.7 + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.6) + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-create-regexp-features-plugin@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.7 + regexpu-core: 5.3.2 + semver: 6.3.1 + dev: true + + /@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.24.6): + resolution: {integrity: sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-compilation-targets': 7.24.8 + '@babel/helper-plugin-utils': 7.24.8 + debug: 4.3.4(supports-color@8.1.1) + lodash.debounce: 4.0.8 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/helper-environment-visitor@7.24.6: resolution: {integrity: sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==} engines: {node: '>=6.9.0'} dev: true + /@babel/helper-environment-visitor@7.24.7: + resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.9 + dev: true + /@babel/helper-function-name@7.24.6: resolution: {integrity: sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==} engines: {node: '>=6.9.0'} @@ -292,6 +406,14 @@ packages: '@babel/types': 7.24.6 dev: true + /@babel/helper-function-name@7.24.7: + resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.24.7 + '@babel/types': 7.24.9 + dev: true + /@babel/helper-hoist-variables@7.24.6: resolution: {integrity: sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==} engines: {node: '>=6.9.0'} @@ -299,6 +421,13 @@ packages: '@babel/types': 7.24.6 dev: true + /@babel/helper-hoist-variables@7.24.7: + resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.9 + dev: true + /@babel/helper-member-expression-to-functions@7.24.6: resolution: {integrity: sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==} engines: {node: '>=6.9.0'} @@ -306,6 +435,16 @@ packages: '@babel/types': 7.24.6 dev: true + /@babel/helper-member-expression-to-functions@7.24.8: + resolution: {integrity: sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.4 + '@babel/types': 7.24.9 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/helper-module-imports@7.24.6: resolution: {integrity: sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==} engines: {node: '>=6.9.0'} @@ -313,6 +452,16 @@ packages: '@babel/types': 7.24.6 dev: true + /@babel/helper-module-imports@7.24.7: + resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.4 + '@babel/types': 7.24.9 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/helper-module-transforms@7.24.6(@babel/core@7.24.6): resolution: {integrity: sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==} engines: {node: '>=6.9.0'} @@ -327,6 +476,22 @@ packages: '@babel/helper-validator-identifier': 7.24.6 dev: true + /@babel/helper-module-transforms@7.24.9(@babel/core@7.24.6): + resolution: {integrity: sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/helper-optimise-call-expression@7.24.6: resolution: {integrity: sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA==} engines: {node: '>=6.9.0'} @@ -334,11 +499,37 @@ packages: '@babel/types': 7.24.6 dev: true + /@babel/helper-optimise-call-expression@7.24.7: + resolution: {integrity: sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.9 + dev: true + /@babel/helper-plugin-utils@7.24.6: resolution: {integrity: sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==} engines: {node: '>=6.9.0'} dev: true + /@babel/helper-plugin-utils@7.24.8: + resolution: {integrity: sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-remap-async-to-generator@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-wrap-function': 7.24.7 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/helper-replace-supers@7.24.6(@babel/core@7.24.6): resolution: {integrity: sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ==} engines: {node: '>=6.9.0'} @@ -351,6 +542,20 @@ packages: '@babel/helper-optimise-call-expression': 7.24.6 dev: true + /@babel/helper-replace-supers@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-member-expression-to-functions': 7.24.8 + '@babel/helper-optimise-call-expression': 7.24.7 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/helper-simple-access@7.24.6: resolution: {integrity: sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==} engines: {node: '>=6.9.0'} @@ -358,6 +563,16 @@ packages: '@babel/types': 7.24.6 dev: true + /@babel/helper-simple-access@7.24.7: + resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.4 + '@babel/types': 7.24.9 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/helper-skip-transparent-expression-wrappers@7.24.6: resolution: {integrity: sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q==} engines: {node: '>=6.9.0'} @@ -365,6 +580,16 @@ packages: '@babel/types': 7.24.6 dev: true + /@babel/helper-skip-transparent-expression-wrappers@7.24.7: + resolution: {integrity: sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.4 + '@babel/types': 7.24.9 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/helper-split-export-declaration@7.24.6: resolution: {integrity: sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==} engines: {node: '>=6.9.0'} @@ -372,21 +597,55 @@ packages: '@babel/types': 7.24.6 dev: true + /@babel/helper-split-export-declaration@7.24.7: + resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.9 + dev: true + /@babel/helper-string-parser@7.24.6: resolution: {integrity: sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==} engines: {node: '>=6.9.0'} dev: true + /@babel/helper-string-parser@7.24.8: + resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-validator-identifier@7.24.6: resolution: {integrity: sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==} engines: {node: '>=6.9.0'} dev: true + /@babel/helper-validator-identifier@7.24.7: + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-validator-option@7.24.6: resolution: {integrity: sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==} engines: {node: '>=6.9.0'} dev: true + /@babel/helper-validator-option@7.24.8: + resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-wrap-function@7.24.7: + resolution: {integrity: sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-function-name': 7.24.7 + '@babel/template': 7.24.7 + '@babel/traverse': 7.25.4 + '@babel/types': 7.24.9 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/helpers@7.24.6: resolution: {integrity: sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA==} engines: {node: '>=6.9.0'} @@ -405,6 +664,16 @@ packages: picocolors: 1.0.1 dev: true + /@babel/highlight@7.24.7: + resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.24.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.1 + dev: true + /@babel/parser@7.24.6: resolution: {integrity: sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==} engines: {node: '>=6.0.0'} @@ -413,6 +682,68 @@ packages: '@babel/types': 7.24.6 dev: true + /@babel/parser@7.24.8: + resolution: {integrity: sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.24.9 + dev: true + + /@babel/parser@7.25.4: + resolution: {integrity: sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.25.4 + dev: true + + /@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/plugin-transform-optional-chaining': 7.24.8(@babel/core@7.24.6) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.24.6): resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} engines: {node: '>=6.9.0'} @@ -440,6 +771,15 @@ packages: '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) dev: true + /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.6): + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + dev: true + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.6): resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: @@ -467,6 +807,34 @@ packages: '@babel/helper-plugin-utils': 7.24.6 dev: true + /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.6): + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.6): + resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.6): + resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + /@babel/plugin-syntax-flow@7.24.6(@babel/core@7.24.6): resolution: {integrity: sha512-gNkksSdV8RbsCoHF9sjVYrHfYACMl/8U32UfUhJ9+84/ASXw8dlx+eHyyF0m6ncQJ9IBSxfuCkB36GJqYdXTOA==} engines: {node: '>=6.9.0'} @@ -487,6 +855,26 @@ packages: '@babel/helper-plugin-utils': 7.24.6 dev: true + /@babel/plugin-syntax-import-assertions@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-import-attributes@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.6): resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: @@ -569,6 +957,16 @@ packages: '@babel/helper-plugin-utils': 7.24.6 dev: true + /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.6): + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.6): resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} @@ -589,6 +987,17 @@ packages: '@babel/helper-plugin-utils': 7.24.6 dev: true + /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.6): + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.8 + dev: true + /@babel/plugin-transform-arrow-functions@7.24.6(@babel/core@7.24.6): resolution: {integrity: sha512-jSSSDt4ZidNMggcLx8SaKsbGNEfIl0PHx/4mFEulorE7bpYLbN0d3pDW3eJ7Y5Z3yPhy3L3NaPCYyTUY7TuugQ==} engines: {node: '>=6.9.0'} @@ -599,18 +1008,609 @@ packages: '@babel/helper-plugin-utils': 7.24.6 dev: true - /@babel/plugin-transform-block-scoped-functions@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-XNW7jolYHW9CwORrZgA/97tL/k05qe/HL0z/qqJq1mdWhwwCM6D4BJBV7wAz9HgFziN5dTOG31znkVIzwxv+vw==} + /@babel/plugin-transform-arrow-functions@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-async-generator-functions@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.6) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-async-to-generator@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.24.7(@babel/core@7.24.6) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-block-scoped-functions@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-XNW7jolYHW9CwORrZgA/97tL/k05qe/HL0z/qqJq1mdWhwwCM6D4BJBV7wAz9HgFziN5dTOG31znkVIzwxv+vw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + dev: true + + /@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-block-scoping@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-S/t1Xh4ehW7sGA7c1j/hiOBLnEYCp/c2sEG4ZkL8kI1xX9tW2pqJTCHKtdhe/jHKt8nG0pFCrDHUXd4DvjHS9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + dev: true + + /@babel/plugin-transform-block-scoping@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-class-properties@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.8(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-class-static-block@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.8(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.6) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-classes@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-+fN+NO2gh8JtRmDSOB6gaCVo36ha8kfCW1nMq2Gc0DABln0VcHN4PrALDvF5/diLzIRKptC7z/d7Lp64zk92Fg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-function-name': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.6) + '@babel/helper-split-export-declaration': 7.24.6 + globals: 11.12.0 + dev: true + + /@babel/plugin-transform-classes@7.24.8(@babel/core@7.24.6): + resolution: {integrity: sha512-VXy91c47uujj758ud9wx+OMgheXm4qJfyhj1P18YvlrQkNOSrwsteHk+EFS3OMGfhMhpZa0A+81eE7G4QC+3CA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-compilation-targets': 7.24.8 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.6) + '@babel/helper-split-export-declaration': 7.24.7 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-computed-properties@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-cRzPobcfRP0ZtuIEkA8QzghoUpSB3X3qSH5W2+FzG+VjWbJXExtx0nbRqwumdBN1x/ot2SlTNQLfBCnPdzp6kg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/template': 7.24.6 + dev: true + + /@babel/plugin-transform-computed-properties@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/template': 7.24.7 + dev: true + + /@babel/plugin-transform-destructuring@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-YLW6AE5LQpk5npNXL7i/O+U9CE4XsBCuRPgyjl1EICZYKmcitV+ayuuUGMJm2lC1WWjXYszeTnIxF/dq/GhIZQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + dev: true + + /@babel/plugin-transform-destructuring@7.24.8(@babel/core@7.24.6): + resolution: {integrity: sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-dotall-regex@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-duplicate-keys@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-dynamic-import@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.6) + dev: true + + /@babel/plugin-transform-exponentiation-operator@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-export-namespace-from@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.6) + dev: true + + /@babel/plugin-transform-flow-strip-types@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-1l8b24NoCpaQ13Vi6FtLG1nv6kNoi8PWvQb1AYO7GHZDpFfBYc3lbXArx1lP2KRt8b4pej1eWc/zrRmsQTfOdQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-flow': 7.24.6(@babel/core@7.24.6) + dev: true + + /@babel/plugin-transform-for-of@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-n3Sf72TnqK4nw/jziSqEl1qaWPbCRw2CziHH+jdRYvw4J6yeCzsj4jdw8hIntOEeDGTmHVe2w4MVL44PN0GMzg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + dev: true + + /@babel/plugin-transform-for-of@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-function-name@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-sOajCu6V0P1KPljWHKiDq6ymgqB+vfo3isUS4McqW1DZtvSVU2v/wuMhmRmkg3sFoq6GMaUUf8W4WtoSLkOV/Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-function-name': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + dev: true + + /@babel/plugin-transform-function-name@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-compilation-targets': 7.24.8 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-json-strings@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.6) + dev: true + + /@babel/plugin-transform-literals@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-f2wHfR2HF6yMj+y+/y07+SLqnOSwRp8KYLpQKOzS58XLVlULhXbiYcygfXQxJlMbhII9+yXDwOUFLf60/TL5tw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + dev: true + + /@babel/plugin-transform-literals@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-logical-assignment-operators@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.6) + dev: true + + /@babel/plugin-transform-member-expression-literals@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-9g8iV146szUo5GWgXpRbq/GALTnY+WnNuRTuRHWWFfWGbP9ukRL0aO/jpu9dmOPikclkxnNsjY8/gsWl6bmZJQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + dev: true + + /@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-modules-amd@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-module-transforms': 7.24.9(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-commonjs@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-JEV8l3MHdmmdb7S7Cmx6rbNEjRCgTQMZxllveHO0mx6uiclB0NflCawlQQ6+o5ZrwjUBYPzHm2XoK4wqGVUFuw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-simple-access': 7.24.6 + dev: true + + /@babel/plugin-transform-modules-commonjs@7.24.8(@babel/core@7.24.6): + resolution: {integrity: sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-module-transforms': 7.24.9(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-simple-access': 7.24.7 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-systemjs@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-hoist-variables': 7.24.7 + '@babel/helper-module-transforms': 7.24.9(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-validator-identifier': 7.24.7 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-umd@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-module-transforms': 7.24.9(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-named-capturing-groups-regex@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-new-target@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-nullish-coalescing-operator@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) + dev: true + + /@babel/plugin-transform-numeric-separator@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.6) + dev: true + + /@babel/plugin-transform-object-rest-spread@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-compilation-targets': 7.24.8 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.6) + dev: true + + /@babel/plugin-transform-object-super@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-N/C76ihFKlZgKfdkEYKtaRUtXZAgK7sOY4h2qrbVbVTXPrKGIi8aww5WGe/+Wmg8onn8sr2ut6FXlsbu/j6JHg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.6) + dev: true + + /@babel/plugin-transform-object-super@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.6) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-optional-catch-binding@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.6) + dev: true + + /@babel/plugin-transform-optional-chaining@7.24.8(@babel/core@7.24.6): + resolution: {integrity: sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-parameters@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-ST7guE8vLV+vI70wmAxuZpIKzVjvFX9Qs8bl5w6tN/6gOypPWUmMQL2p7LJz5E63vEGrDhAiYetniJFyBH1RkA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + dev: true + + /@babel/plugin-transform-parameters@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-private-methods@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.8(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-private-property-in-object@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.24.8(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.6) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-property-literals@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-oARaglxhRsN18OYsnPTpb8TcKQWDYNsPNmTnx5++WOAsUJ0cSC/FZVlIJCKvPbU4yn/UXsS0551CFKJhN0CaMw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + dev: true + + /@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-transform-block-scoping@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-S/t1Xh4ehW7sGA7c1j/hiOBLnEYCp/c2sEG4ZkL8kI1xX9tW2pqJTCHKtdhe/jHKt8nG0pFCrDHUXd4DvjHS9w==} + /@babel/plugin-transform-react-display-name@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-/3iiEEHDsJuj9QU09gbyWGSUxDboFcD7Nj6dnHIlboWSodxXAoaY/zlNMHeYAC0WsERMqgO9a7UaM77CsYgWcg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -619,194 +1619,273 @@ packages: '@babel/helper-plugin-utils': 7.24.6 dev: true - /@babel/plugin-transform-classes@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-+fN+NO2gh8JtRmDSOB6gaCVo36ha8kfCW1nMq2Gc0DABln0VcHN4PrALDvF5/diLzIRKptC7z/d7Lp64zk92Fg==} + /@babel/plugin-transform-react-jsx@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-pCtPHhpRZHfwdA5G1Gpk5mIzMA99hv0R8S/Ket50Rw+S+8hkt3wBWqdqHaPw0CuUYxdshUgsPiLQ5fAs4ASMhw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.6 '@babel/helper-annotate-as-pure': 7.24.6 - '@babel/helper-compilation-targets': 7.24.6 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-function-name': 7.24.6 + '@babel/helper-module-imports': 7.24.6 '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.6) - '@babel/helper-split-export-declaration': 7.24.6 - globals: 11.12.0 + '@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6) + '@babel/types': 7.24.6 dev: true - /@babel/plugin-transform-computed-properties@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-cRzPobcfRP0ZtuIEkA8QzghoUpSB3X3qSH5W2+FzG+VjWbJXExtx0nbRqwumdBN1x/ot2SlTNQLfBCnPdzp6kg==} + /@babel/plugin-transform-regenerator@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/template': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + regenerator-transform: 0.15.2 dev: true - /@babel/plugin-transform-destructuring@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-YLW6AE5LQpk5npNXL7i/O+U9CE4XsBCuRPgyjl1EICZYKmcitV+ayuuUGMJm2lC1WWjXYszeTnIxF/dq/GhIZQ==} + /@babel/plugin-transform-reserved-words@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-transform-flow-strip-types@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-1l8b24NoCpaQ13Vi6FtLG1nv6kNoi8PWvQb1AYO7GHZDpFfBYc3lbXArx1lP2KRt8b4pej1eWc/zrRmsQTfOdQ==} + /@babel/plugin-transform-shorthand-properties@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-xnEUvHSMr9eOWS5Al2YPfc32ten7CXdH7Zwyyk7IqITg4nX61oHj+GxpNvl+y5JHjfN3KXE2IV55wAWowBYMVw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-flow': 7.24.6(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-for-of@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-n3Sf72TnqK4nw/jziSqEl1qaWPbCRw2CziHH+jdRYvw4J6yeCzsj4jdw8hIntOEeDGTmHVe2w4MVL44PN0GMzg==} + /@babel/plugin-transform-shorthand-properties@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-transform-function-name@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-sOajCu6V0P1KPljWHKiDq6ymgqB+vfo3isUS4McqW1DZtvSVU2v/wuMhmRmkg3sFoq6GMaUUf8W4WtoSLkOV/Q==} + /@babel/plugin-transform-spread@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-h/2j7oIUDjS+ULsIrNZ6/TKG97FgmEk1PXryk/HQq6op4XUUUwif2f69fJrzK0wza2zjCS1xhXmouACaWV5uPA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.6 - '@babel/helper-compilation-targets': 7.24.6 - '@babel/helper-function-name': 7.24.6 '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 dev: true - /@babel/plugin-transform-literals@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-f2wHfR2HF6yMj+y+/y07+SLqnOSwRp8KYLpQKOzS58XLVlULhXbiYcygfXQxJlMbhII9+yXDwOUFLf60/TL5tw==} + /@babel/plugin-transform-spread@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-member-expression-literals@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-9g8iV146szUo5GWgXpRbq/GALTnY+WnNuRTuRHWWFfWGbP9ukRL0aO/jpu9dmOPikclkxnNsjY8/gsWl6bmZJQ==} + /@babel/plugin-transform-sticky-regex@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-transform-modules-commonjs@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-JEV8l3MHdmmdb7S7Cmx6rbNEjRCgTQMZxllveHO0mx6uiclB0NflCawlQQ6+o5ZrwjUBYPzHm2XoK4wqGVUFuw==} + /@babel/plugin-transform-template-literals@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-BJbEqJIcKwrqUP+KfUIkxz3q8VzXe2R8Wv8TaNgO1cx+nNavxn/2+H8kp9tgFSOL6wYPPEgFvU6IKS4qoGqhmg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.6 - '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-simple-access': 7.24.6 dev: true - /@babel/plugin-transform-object-super@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-N/C76ihFKlZgKfdkEYKtaRUtXZAgK7sOY4h2qrbVbVTXPrKGIi8aww5WGe/+Wmg8onn8sr2ut6FXlsbu/j6JHg==} + /@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-transform-parameters@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-ST7guE8vLV+vI70wmAxuZpIKzVjvFX9Qs8bl5w6tN/6gOypPWUmMQL2p7LJz5E63vEGrDhAiYetniJFyBH1RkA==} + /@babel/plugin-transform-typeof-symbol@7.24.8(@babel/core@7.24.6): + resolution: {integrity: sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-transform-property-literals@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-oARaglxhRsN18OYsnPTpb8TcKQWDYNsPNmTnx5++WOAsUJ0cSC/FZVlIJCKvPbU4yn/UXsS0551CFKJhN0CaMw==} + /@babel/plugin-transform-unicode-escapes@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-transform-react-display-name@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-/3iiEEHDsJuj9QU09gbyWGSUxDboFcD7Nj6dnHIlboWSodxXAoaY/zlNMHeYAC0WsERMqgO9a7UaM77CsYgWcg==} + /@babel/plugin-transform-unicode-property-regex@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-transform-react-jsx@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-pCtPHhpRZHfwdA5G1Gpk5mIzMA99hv0R8S/Ket50Rw+S+8hkt3wBWqdqHaPw0CuUYxdshUgsPiLQ5fAs4ASMhw==} + /@babel/plugin-transform-unicode-regex@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.6 - '@babel/helper-annotate-as-pure': 7.24.6 - '@babel/helper-module-imports': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6) - '@babel/types': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-transform-shorthand-properties@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-xnEUvHSMr9eOWS5Al2YPfc32ten7CXdH7Zwyyk7IqITg4nX61oHj+GxpNvl+y5JHjfN3KXE2IV55wAWowBYMVw==} + /@babel/plugin-transform-unicode-sets-regex@7.24.7(@babel/core@7.24.6): + resolution: {integrity: sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-transform-spread@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-h/2j7oIUDjS+ULsIrNZ6/TKG97FgmEk1PXryk/HQq6op4XUUUwif2f69fJrzK0wza2zjCS1xhXmouACaWV5uPA==} + /@babel/preset-env@7.24.8(@babel/core@7.24.6): + resolution: {integrity: sha512-vObvMZB6hNWuDxhSaEPTKCwcqkAIuDtE+bQGn4XMXne1DSLzFVY8Vmj1bm+mUQXYNN8NmaQEO+r8MMbzPr1jBQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: + '@babel/compat-data': 7.24.9 '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + '@babel/helper-compilation-targets': 7.24.8 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-validator-option': 7.24.8 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.6) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.6) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.6) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.6) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-import-assertions': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-syntax-import-attributes': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.6) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.6) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-transform-arrow-functions': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-async-generator-functions': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-async-to-generator': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-block-scoped-functions': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-block-scoping': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-class-properties': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-class-static-block': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-classes': 7.24.8(@babel/core@7.24.6) + '@babel/plugin-transform-computed-properties': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-destructuring': 7.24.8(@babel/core@7.24.6) + '@babel/plugin-transform-dotall-regex': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-duplicate-keys': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-dynamic-import': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-exponentiation-operator': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-export-namespace-from': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-for-of': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-function-name': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-json-strings': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-literals': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-logical-assignment-operators': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-member-expression-literals': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-modules-amd': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-modules-commonjs': 7.24.8(@babel/core@7.24.6) + '@babel/plugin-transform-modules-systemjs': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-modules-umd': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-named-capturing-groups-regex': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-new-target': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-nullish-coalescing-operator': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-numeric-separator': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-object-rest-spread': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-object-super': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-optional-catch-binding': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-optional-chaining': 7.24.8(@babel/core@7.24.6) + '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-private-methods': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-private-property-in-object': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-property-literals': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-regenerator': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-reserved-words': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-shorthand-properties': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-spread': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-sticky-regex': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-template-literals': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-typeof-symbol': 7.24.8(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-escapes': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-property-regex': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-regex': 7.24.7(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-sets-regex': 7.24.7(@babel/core@7.24.6) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.6) + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.6) + babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.6) + babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.6) + core-js-compat: 3.37.1 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-template-literals@7.24.6(@babel/core@7.24.6): - resolution: {integrity: sha512-BJbEqJIcKwrqUP+KfUIkxz3q8VzXe2R8Wv8TaNgO1cx+nNavxn/2+H8kp9tgFSOL6wYPPEgFvU6IKS4qoGqhmg==} - engines: {node: '>=6.9.0'} + /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.6): + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 dependencies: '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/types': 7.24.6 + esutils: 2.0.3 + dev: true + + /@babel/regjsgen@0.8.0: + resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} dev: true /@babel/runtime@7.24.6: @@ -825,6 +1904,24 @@ packages: '@babel/types': 7.24.6 dev: true + /@babel/template@7.24.7: + resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.24.8 + '@babel/types': 7.24.9 + dev: true + + /@babel/template@7.25.0: + resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.25.4 + '@babel/types': 7.25.4 + dev: true + /@babel/traverse@7.24.6: resolution: {integrity: sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw==} engines: {node: '>=6.9.0'} @@ -843,6 +1940,21 @@ packages: - supports-color dev: true + /@babel/traverse@7.25.4: + resolution: {integrity: sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.5 + '@babel/parser': 7.25.4 + '@babel/template': 7.25.0 + '@babel/types': 7.25.4 + debug: 4.3.4(supports-color@8.1.1) + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/types@7.24.6: resolution: {integrity: sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==} engines: {node: '>=6.9.0'} @@ -852,6 +1964,24 @@ packages: to-fast-properties: 2.0.0 dev: true + /@babel/types@7.24.9: + resolution: {integrity: sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.24.8 + '@babel/helper-validator-identifier': 7.24.7 + to-fast-properties: 2.0.0 + dev: true + + /@babel/types@7.25.4: + resolution: {integrity: sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.24.8 + '@babel/helper-validator-identifier': 7.24.7 + to-fast-properties: 2.0.0 + dev: true + /@bcoe/v8-coverage@0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true @@ -1969,6 +3099,10 @@ packages: graphql: 16.8.1 dev: true + /@hexagon/base64@1.1.28: + resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==} + dev: false + /@humanwhocodes/config-array@0.11.14: resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -2279,6 +3413,10 @@ packages: resolution: {integrity: sha512-gbkePEBupNydxCelHCESvFSFM8XPh1Zs/OAVRW/rKpEqPAl5PbOM90Si8mv9bvnR53uPD2s/FiRxdvSejpRJew==} dev: true + /@levischuck/tiny-cbor@0.2.2: + resolution: {integrity: sha512-f5CnPw997Y2GQ8FAvtuVVC19FX8mwNNC+1XJcIi16n/LTJifKO6QBgGLgN3YEmqtGMk17SKSuoWES3imJVxAVw==} + dev: false + /@noble/curves@1.4.0: resolution: {integrity: sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==} dependencies: @@ -2311,13 +3449,48 @@ packages: fastq: 1.17.1 dev: true + /@peculiar/asn1-android@2.3.10: + resolution: {integrity: sha512-z9Rx9cFJv7UUablZISe7uksNbFJCq13hO0yEAOoIpAymALTLlvUOSLnGiQS7okPaM5dP42oTLhezH6XDXRXjGw==} + dependencies: + '@peculiar/asn1-schema': 2.3.8 + asn1js: 3.0.5 + tslib: 2.6.2 + dev: false + + /@peculiar/asn1-ecc@2.3.8: + resolution: {integrity: sha512-Ah/Q15y3A/CtxbPibiLM/LKcMbnLTdUdLHUgdpB5f60sSvGkXzxJCu5ezGTFHogZXWNX3KSmYqilCrfdmBc6pQ==} + dependencies: + '@peculiar/asn1-schema': 2.3.8 + '@peculiar/asn1-x509': 2.3.8 + asn1js: 3.0.5 + tslib: 2.6.2 + dev: false + + /@peculiar/asn1-rsa@2.3.8: + resolution: {integrity: sha512-ES/RVEHu8VMYXgrg3gjb1m/XG0KJWnV4qyZZ7mAg7rrF3VTmRbLxO8mk+uy0Hme7geSMebp+Wvi2U6RLLEs12Q==} + dependencies: + '@peculiar/asn1-schema': 2.3.8 + '@peculiar/asn1-x509': 2.3.8 + asn1js: 3.0.5 + tslib: 2.6.2 + dev: false + /@peculiar/asn1-schema@2.3.8: resolution: {integrity: sha512-ULB1XqHKx1WBU/tTFIA+uARuRoBVZ4pNdOA878RDrRbBfBGcSzi5HBkdScC6ZbHn8z7L8gmKCgPC1LHRrP46tA==} dependencies: asn1js: 3.0.5 pvtsutils: 1.3.5 tslib: 2.6.2 - dev: true + + /@peculiar/asn1-x509@2.3.8: + resolution: {integrity: sha512-voKxGfDU1c6r9mKiN5ZUsZWh3Dy1BABvTM3cimf0tztNwyMJPhiXY94eRTgsMQe6ViLfT6EoXxkWVzcm3mFAFw==} + dependencies: + '@peculiar/asn1-schema': 2.3.8 + asn1js: 3.0.5 + ipaddr.js: 2.2.0 + pvtsutils: 1.3.5 + tslib: 2.6.2 + dev: false /@peculiar/json-schema@1.1.12: resolution: {integrity: sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==} @@ -2495,6 +3668,33 @@ packages: '@scure/base': 1.1.6 dev: false + /@simplewebauthn/browser@10.0.0: + resolution: {integrity: sha512-hG0JMZD+LiLUbpQcAjS4d+t4gbprE/dLYop/CkE01ugU/9sKXflxV5s0DRjdz3uNMFecatRfb4ZLG3XvF8m5zg==} + dependencies: + '@simplewebauthn/types': 10.0.0 + dev: false + + /@simplewebauthn/server@10.0.0: + resolution: {integrity: sha512-w5eIoiF7ltg1sgggjY5Tx654j+DBuyEx2B3869jjmPp0xl2Z4BUP4kJ3yJ6DnZIv+ZYYntT3E6nZXNjPOQbrtw==} + engines: {node: '>=20.0.0'} + dependencies: + '@hexagon/base64': 1.1.28 + '@levischuck/tiny-cbor': 0.2.2 + '@peculiar/asn1-android': 2.3.10 + '@peculiar/asn1-ecc': 2.3.8 + '@peculiar/asn1-rsa': 2.3.8 + '@peculiar/asn1-schema': 2.3.8 + '@peculiar/asn1-x509': 2.3.8 + '@simplewebauthn/types': 10.0.0 + cross-fetch: 4.0.0 + transitivePeerDependencies: + - encoding + dev: false + + /@simplewebauthn/types@10.0.0: + resolution: {integrity: sha512-SFXke7xkgPRowY2E+8djKbdEznTVnD5R6GO7GPTthpHrokLvNKw8C3lFZypTxLI7KkCfGPfhtqB3d7OVGGa9jQ==} + dev: false + /@sinclair/typebox@0.27.8: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} dev: true @@ -3219,7 +4419,6 @@ packages: pvtsutils: 1.3.5 pvutils: 1.1.3 tslib: 2.6.2 - dev: true /assertion-error-formatter@3.0.0: resolution: {integrity: sha512-6YyAVLrEze0kQ7CmJfUgrLHb+Y7XghmL2Ie7ijVa2Y9ynP3LV+VDiwFk62Dn0qtqbmY0BT0ss6p1xxpiF2PYbQ==} @@ -3301,6 +4500,42 @@ packages: '@types/babel__traverse': 7.20.6 dev: true + /babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.6): + resolution: {integrity: sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/compat-data': 7.24.9 + '@babel/core': 7.24.6 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.6) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.6): + resolution: {integrity: sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.6) + core-js-compat: 3.37.1 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.24.6): + resolution: {integrity: sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.6) + transitivePeerDependencies: + - supports-color + dev: true + /babel-plugin-syntax-trailing-function-commas@7.0.0-beta.0: resolution: {integrity: sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ==} dev: true @@ -3814,6 +5049,12 @@ packages: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} dev: true + /core-js-compat@3.37.1: + resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==} + dependencies: + browserslist: 4.23.0 + dev: true + /cosmiconfig@8.3.6(typescript@5.4.5): resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} engines: {node: '>=14'} @@ -3861,6 +5102,14 @@ packages: - encoding dev: true + /cross-fetch@4.0.0: + resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + dev: false + /cross-inspect@1.0.0: resolution: {integrity: sha512-4PFfn4b5ZN6FMNGSZlyb7wUhuN8wvj8t/VQHZdM4JsDcruGJ8L2kf9zao98QIrBPFCpdk27qst/AGTl7pL3ypQ==} engines: {node: '>=16.0.0'} @@ -5173,6 +6422,11 @@ packages: loose-envify: 1.4.0 dev: true + /ipaddr.js@2.2.0: + resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==} + engines: {node: '>= 10'} + dev: false + /is-absolute@1.0.0: resolution: {integrity: sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==} engines: {node: '>=0.10.0'} @@ -5920,6 +7174,11 @@ packages: argparse: 2.0.1 dev: true + /jsesc@0.5.0: + resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} + hasBin: true + dev: true + /jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} @@ -6083,6 +7342,10 @@ packages: p-locate: 5.0.0 dev: true + /lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + dev: true + /lodash.includes@4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} dev: true @@ -6369,7 +7632,6 @@ packages: optional: true dependencies: whatwg-url: 5.0.0 - dev: true /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -6786,12 +8048,10 @@ packages: resolution: {integrity: sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==} dependencies: tslib: 2.6.2 - dev: true /pvutils@1.1.3: resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==} engines: {node: '>=6.0.0'} - dev: true /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -6852,10 +8112,27 @@ packages: deprecated: This version has a critical bug in fallback handling. Please upgrade to reflect-metadata@0.2.2 or newer. dev: true + /regenerate-unicode-properties@10.1.1: + resolution: {integrity: sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==} + engines: {node: '>=4'} + dependencies: + regenerate: 1.4.2 + dev: true + + /regenerate@1.4.2: + resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + dev: true + /regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} dev: true + /regenerator-transform@0.15.2: + resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} + dependencies: + '@babel/runtime': 7.24.6 + dev: true + /regexp-match-indices@1.0.2: resolution: {integrity: sha512-DwZuAkt8NF5mKwGGER1EGh2PRqyvhRhhLviH+R8y8dIuaQROlUfXjt4s9ZTXstIsSkptf06BSvwcEmmfheJJWQ==} dependencies: @@ -6877,6 +8154,25 @@ packages: set-function-name: 2.0.2 dev: true + /regexpu-core@5.3.2: + resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} + engines: {node: '>=4'} + dependencies: + '@babel/regjsgen': 0.8.0 + regenerate: 1.4.2 + regenerate-unicode-properties: 10.1.1 + regjsparser: 0.9.1 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.1.0 + dev: true + + /regjsparser@0.9.1: + resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} + hasBin: true + dependencies: + jsesc: 0.5.0 + dev: true + /relay-runtime@12.0.0: resolution: {integrity: sha512-QU6JKr1tMsry22DXNy9Whsq5rmvwr3LSZiiWV/9+DFpuTWvp+WFhobWMc8TC4OjKFfNhEZy7mOiqUAn5atQtug==} dependencies: @@ -7565,7 +8861,6 @@ packages: /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - dev: true /tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} @@ -7695,7 +8990,6 @@ packages: /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - dev: true /tsup@8.0.2(ts-node@10.9.2)(typescript@5.4.5): resolution: {integrity: sha512-NY8xtQXdH7hDUAZwcQdY/Vzlw9johQsaqf7iwZ6g1DOUlFYQ5/AtVAjTvihhEyeRlGo4dLRVHtrRaL35M1daqQ==} @@ -7867,6 +9161,29 @@ packages: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} dev: true + /unicode-canonical-property-names-ecmascript@2.0.0: + resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} + engines: {node: '>=4'} + dev: true + + /unicode-match-property-ecmascript@2.0.0: + resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} + engines: {node: '>=4'} + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.0 + unicode-property-aliases-ecmascript: 2.1.0 + dev: true + + /unicode-match-property-value-ecmascript@2.1.0: + resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} + engines: {node: '>=4'} + dev: true + + /unicode-property-aliases-ecmascript@2.1.0: + resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} + engines: {node: '>=4'} + dev: true + /unixify@1.0.0: resolution: {integrity: sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg==} engines: {node: '>=0.10.0'} @@ -8005,7 +9322,6 @@ packages: /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - dev: true /webidl-conversions@4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} @@ -8060,7 +9376,6 @@ packages: dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 - dev: true /whatwg-url@7.1.0: resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} diff --git a/src/account/SingleKeyAccount.ts b/src/account/SingleKeyAccount.ts index a76b9b04f..74d2cd437 100644 --- a/src/account/SingleKeyAccount.ts +++ b/src/account/SingleKeyAccount.ts @@ -1,10 +1,17 @@ -import { AccountAuthenticatorSingleKey } from "../transactions/authenticator/account"; -import { type HexInput, SigningScheme, SigningSchemeInput } from "../types"; import { AccountAddress, AccountAddressInput } from "../core/accountAddress"; -import { AnyPublicKey, AnySignature, Ed25519PrivateKey, PrivateKey, Secp256k1PrivateKey } from "../core/crypto"; -import type { Account } from "./Account"; +import { + AnyPublicKey, + AnySignature, + Ed25519PrivateKey, + PrivateKey, + Secp256k1PrivateKey, + Secp256r1PrivateKey, +} from "../core/crypto"; +import { AccountAuthenticatorSingleKey } from "../transactions/authenticator/account"; import { generateSigningMessageForTransaction } from "../transactions/transactionBuilder/signingMessage"; import { AnyRawTransaction } from "../transactions/types"; +import { type HexInput, SigningScheme, SigningSchemeInput } from "../types"; +import type { Account } from "./Account"; export interface SingleKeySignerConstructorArgs { privateKey: PrivateKey; @@ -68,6 +75,9 @@ export class SingleKeyAccount implements Account { case SigningSchemeInput.Secp256k1Ecdsa: privateKey = Secp256k1PrivateKey.generate(); break; + case SigningSchemeInput.Secp256r1Ecdsa: + privateKey = Secp256r1PrivateKey.generate(); + break; default: throw new Error(`Unsupported signature scheme ${scheme}`); } @@ -94,6 +104,9 @@ export class SingleKeyAccount implements Account { case SigningSchemeInput.Secp256k1Ecdsa: privateKey = Secp256k1PrivateKey.fromDerivationPath(path, mnemonic); break; + case SigningSchemeInput.Secp256r1Ecdsa: + privateKey = Secp256r1PrivateKey.fromDerivationPath(path, mnemonic); + break; default: throw new Error(`Unsupported signature scheme ${scheme}`); } diff --git a/src/api/aptos.ts b/src/api/aptos.ts index 23aa9c927..b377925ac 100644 --- a/src/api/aptos.ts +++ b/src/api/aptos.ts @@ -1,7 +1,9 @@ +import { Passkey } from "./passkey"; // Copyright © Aptos Foundation // SPDX-License-Identifier: Apache-2.0 import { Account } from "./account"; +import { ANS } from "./ans"; import { AptosConfig } from "./aptosConfig"; import { Coin } from "./coin"; import { DigitalAsset } from "./digitalAsset"; @@ -9,12 +11,11 @@ import { Event } from "./event"; import { Faucet } from "./faucet"; import { FungibleAsset } from "./fungibleAsset"; import { General } from "./general"; -import { ANS } from "./ans"; -import { Staking } from "./staking"; -import { Transaction } from "./transaction"; -import { Table } from "./table"; import { Keyless } from "./keyless"; import { AptosObject } from "./object"; +import { Staking } from "./staking"; +import { Table } from "./table"; +import { Transaction } from "./transaction"; /** * This class is the main entry point into Aptos's @@ -46,6 +47,8 @@ export class Aptos { readonly general: General; + readonly passkey: Passkey; + readonly staking: Staking; readonly transaction: Transaction; @@ -66,6 +69,7 @@ export class Aptos { this.faucet = new Faucet(this.config); this.fungibleAsset = new FungibleAsset(this.config); this.general = new General(this.config); + this.passkey = new Passkey(this.config); this.staking = new Staking(this.config); this.transaction = new Transaction(this.config); this.table = new Table(this.config); @@ -85,6 +89,7 @@ export interface Aptos Faucet, FungibleAsset, General, + Passkey, Keyless, Staking, Table, @@ -120,6 +125,7 @@ applyMixin(Aptos, Event, "event"); applyMixin(Aptos, Faucet, "faucet"); applyMixin(Aptos, FungibleAsset, "fungibleAsset"); applyMixin(Aptos, General, "general"); +applyMixin(Aptos, Passkey, "passkey"); applyMixin(Aptos, Staking, "staking"); applyMixin(Aptos, Transaction, "transaction"); applyMixin(Aptos, Table, "table"); diff --git a/src/api/passkey.ts b/src/api/passkey.ts new file mode 100644 index 000000000..07a04e618 --- /dev/null +++ b/src/api/passkey.ts @@ -0,0 +1,138 @@ +/* eslint-disable class-methods-use-this */ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +import type { PublicKeyCredentialCreationOptionsJSON, RegistrationResponseJSON } from "@simplewebauthn/server/esm/deps"; +import { AccountAddress, PublicKey } from "../core"; +import { + generateRegistrationOptions, + getPasskeyAccountAddress, + parsePublicKey, + registerCredential, + signAndSubmitWithPasskey, + signWithPasskey, +} from "../internal/passkey"; +import { AccountAuthenticator, AnyRawTransaction } from "../transactions"; +import { HexInput, PendingTransactionResponse } from "../types"; +import { AllowCredentialOption } from "../types/passkey"; +import { AptosConfig } from "./aptosConfig"; + +/** + * A class for all `Passkeys` related operations on Aptos on the browser. + */ +export class Passkey { + readonly config: AptosConfig; + + constructor(config: AptosConfig) { + this.config = config; + } + + /** + * Given a credentialId and a transaction, it prompts the client to sign the transaction then submits it. + * + * @param args.credentialId The credential ID of the passkey + * @param args.publicKey The public key associated with the passkey + * @param args.transaction The transaction to sign + * @param args.rpID The relying party ID + * @param args.timeout The timeout for the operation + * @param args.options The options for the operation + * @returns The pending transaction response + */ + async signAndSubmitWithPasskey(args: { + credentialId: string | Uint8Array; + publicKey: PublicKey; + transaction: AnyRawTransaction; + rpID: string; + timeout?: number; + options?: { + allowCredentials?: AllowCredentialOption[]; + }; + }): Promise { + return signAndSubmitWithPasskey({ aptosConfig: this.config, ...args }); + } + + /** + * Given a credentialId and a transaction, it prompts the client to sign the transaction. + * + * @param args.credentialId The credential ID of the passkey + * @param args.publicKey The public key associated with the passkey + * @param args.transaction The transaction to sign + * @param args.rpID The relying party ID + * @param args.timeout The timeout for the operation + * @param args.options The options for the operation + * @returns The account authenticator + */ + + async signWithPasskey(args: { + credentialId: string | Uint8Array; + publicKey: PublicKey; + transaction: AnyRawTransaction; + rpID: string; + timeout?: number; + options?: { + allowCredentials?: AllowCredentialOption[]; + }; + }): Promise { + return signWithPasskey({ ...args }); + } + + /** + * Given a public key, it returns the account address associated with the passkey. + * @param args.publicKey The public key associated with the passkey + * @returns The account address + */ + + async getPasskeyAccountAddress(args: { publicKey: HexInput }): Promise { + return getPasskeyAccountAddress(args); + } + + /** + * Generates registration options for a passkey. + * @param args.rpName The relying party name + * @param args.rpID The relying party ID + * @param args.userName The user name + * @param args.userID The user ID + * @param args.challenge The challenge + * @param args.userDisplayName The user display name + * @param args.timeout The timeout for the operation + * @param args.attestationType The attestation type + * @param args.authenticatorAttachment The authenticator attachment + * @returns The registration options + */ + + async generateRegistrationOptions(args: { + rpName: string; + rpID: string; + userName: string; + userID?: Uint8Array; + challenge?: string | Uint8Array; + userDisplayName?: string; + timeout?: number; + attestationType?: AttestationConveyancePreference; + authenticatorAttachment?: AuthenticatorAttachment; + }): Promise { + return generateRegistrationOptions(args); + } + + /** + * Registers a credential for a passkey. + * @param creationOptionsJSON + * @returns The registration response + */ + + async registerCredential( + creationOptionsJSON: PublicKeyCredentialCreationOptionsJSON, + ): Promise { + return registerCredential(creationOptionsJSON); + } + + /** + * Parses the public key from a registration response. + * @param response The registration response + * @returns The public key + */ + + parsePublicKey(response: RegistrationResponseJSON): PublicKey { + return parsePublicKey(response); + } +} diff --git a/src/core/crypto/index.ts b/src/core/crypto/index.ts index 6b3c87573..95260f941 100644 --- a/src/core/crypto/index.ts +++ b/src/core/crypto/index.ts @@ -2,13 +2,15 @@ // SPDX-License-Identifier: Apache-2.0 export * from "./ed25519"; +export * from "./ephemeral"; export * from "./hdKey"; +export * from "./keyless"; export * from "./multiEd25519"; export * from "./multiKey"; -export * from "./ephemeral"; -export * from "./keyless"; export * from "./privateKey"; export * from "./publicKey"; export * from "./secp256k1"; +export * from "./secp256r1"; export * from "./signature"; export * from "./singleKey"; +export * from "./webauthn"; diff --git a/src/core/crypto/secp256r1.ts b/src/core/crypto/secp256r1.ts new file mode 100644 index 000000000..3dbb0ff48 --- /dev/null +++ b/src/core/crypto/secp256r1.ts @@ -0,0 +1,475 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +import { p256, secp256r1 } from "@noble/curves/p256"; +import { sha256 } from "@noble/hashes/sha256"; +import { HDKey } from "@scure/bip32"; +import { bufferToBase64URLString } from "@simplewebauthn/browser"; +import { Deserializer, Serializable, Serializer } from "../../bcs"; +import { AnyPublicKeyVariant, HexInput, SigningScheme } from "../../types"; +import { AuthenticationKey } from "../authenticationKey"; +import { Hex } from "../hex"; +import { isValidBIP44Path, mnemonicToSeed } from "./hdKey"; +import { PrivateKey } from "./privateKey"; +import { AccountPublicKey, PublicKey, VerifySignatureArgs } from "./publicKey"; +import { Signature } from "./signature"; +import { convertSigningMessage } from "./utils"; +import type { WebAuthnSignature } from "./webauthn"; + +export interface RecoverPasskeyPublicKeyArgsInput { + authenticatorData: Uint8Array; + clientDataJSON: Uint8Array; + signature: Uint8Array; +} + +/** + * Recover Passkey Public Key Args + * + * + */ +export type RecoverPasskeyPublicKeyArgs = [RecoverPasskeyPublicKeyArgsInput, RecoverPasskeyPublicKeyArgsInput]; + +export interface RecoverPublicKeyArgsInput { + message: Uint8Array; + signature: Uint8Array; +} + +export type RecoverPublicKeyArgs = [RecoverPublicKeyArgsInput, RecoverPublicKeyArgsInput] +/** + * Represents the Secp256r1 public key + * + * Secp256r1 authentication key is represented in the SDK as `AnyPublicKey`. It is used to verify WebAuthnSignatures. + */ +export class Secp256r1PublicKey extends AccountPublicKey { + // Secp256r1 ecdsa public keys contain a prefix indicating compression and two 32-byte coordinates. + static readonly LENGTH: number = 65; + + // Hex value of the public key + private readonly key: Hex; + + /** + * Create a new PublicKey instance from a Uint8Array or String. + * + * @param hexInput A HexInput (string or Uint8Array) + */ + constructor(hexInput: HexInput) { + super(); + + const hex = Hex.fromHexInput(hexInput); + if (hex.toUint8Array().length !== Secp256r1PublicKey.LENGTH) { + throw new Error(`PublicKey length should be ${Secp256r1PublicKey.LENGTH}`); + } + this.key = hex; + } + + /** + * Get the public key in bytes (Uint8Array). + * + * @returns Uint8Array representation of the public key + */ + toUint8Array(): Uint8Array { + return this.key.toUint8Array(); + } + + /** + * Get the public key as a hex string with the 0x prefix. + * + * @returns string representation of the public key + */ + toString(): string { + return this.key.toString(); + } + + /** + * Verifies a signed data with a public key + * + * @param args.message message + * @param args.signature The signature + * @returns true if the signature is valid + */ + verifySignature(args: VerifySignatureArgs): boolean { + const { message, signature } = args; + if (!(signature instanceof Secp256r1Signature)) { + return false; + } + + const messageToVerify = convertSigningMessage(message); + const messageBytes = Hex.fromHexInput(messageToVerify).toUint8Array(); + const messageShaBytes = sha256(messageBytes); + const signatureBytes = signature.toUint8Array(); + return p256.verify(signatureBytes, messageShaBytes, this.toUint8Array()); + } + + /** + * Verifies a signed data with a public key + * + * @param args.message message + * @param args.signature The signature + * @returns true if the signature is valid + */ + verifyWebAuthnSignature(args: { message: HexInput; signature: WebAuthnSignature }): boolean { + const { message, signature } = args; + + if (!(signature.paar.signature.signature instanceof Secp256r1Signature)) { + throw new Error("Attestation signature is not a Secp256r1Signature"); + } + + // Check challenge + const { challenge } = signature.getCollectedClientData(); + + const messageBase64URLString = bufferToBase64URLString(Hex.fromHexInput(message).toUint8Array()); + if (challenge !== messageBase64URLString) { + return false; + } + + // Get verification data. + const verificationData = signature.getVerificationData(); + + // Verify the the signature is the signed verification data. + return this.verifySignature({ message: verificationData, signature: signature.paar.signature.signature }); + } + + authKey(): AuthenticationKey { + const serializer = new Serializer(); + serializer.serializeU32AsUleb128(AnyPublicKeyVariant.Secp256r1); + serializer.serializeFixedBytes(this.bcsToBytes()); + return AuthenticationKey.fromSchemeAndBytes({ + scheme: SigningScheme.SingleKey, + input: serializer.toUint8Array(), + }); + } + + serialize(serializer: Serializer): void { + serializer.serializeBytes(this.key.toUint8Array()); + } + + static deserialize(deserializer: Deserializer): Secp256r1PublicKey { + const bytes = deserializer.deserializeBytes(); + return new Secp256r1PublicKey(bytes); + } + + static load(deserializer: Deserializer): Secp256r1PublicKey { + const bytes = deserializer.deserializeBytes(); + return new Secp256r1PublicKey(bytes); + } + + static isInstance(publicKey: PublicKey): publicKey is Secp256r1PublicKey { + return "key" in publicKey && (publicKey.key as any)?.data?.length === Secp256r1PublicKey.LENGTH; + } + + /** + * Recover Secp256r1 Ecdsa Public Key from Passkey Signature + * + * @param args RecoverPasskeyPublicKeyArgsInput + * @returns Secp256r1PublicKey[] + * + * @see https://github.com/ethereum/js-ethereum-cryptography/blob/9faadf5f1dda4aa95cc675d927281862ac7bf7e7/src/secp256k1-compat.ts#L47 + */ + static async recoverPasskeyPublicKey({ + clientDataJSON, + authenticatorData, + signature, + }: RecoverPasskeyPublicKeyArgsInput): Promise { + const shaClientDataJSON = sha256(clientDataJSON); + + // Construct verificationData, where verificationData is defined as + // verificationData = authenticator_data || sha256(clientDataJson) + // https://www.w3.org/TR/webauthn-3/#sctn-verifying-assertion + const verificationData = new Uint8Array([...authenticatorData, ...shaClientDataJSON]); + return await Secp256r1PublicKey.recoverPublicKey({ message: verificationData, signature }); + } + + /** + * Recover Secp256r1 Ecdsa Public Key from Passkey Signature + * + * @param args RecoverPasskeyPublicKeyArgs + * @returns Secp256r1PublicKey + * + * @see https://github.com/ethereum/js-ethereum-cryptography/blob/9faadf5f1dda4aa95cc675d927281862ac7bf7e7/src/secp256k1-compat.ts#L47 + */ + static async recoverPasskeyPublicKeyFromTwoSignatures( + args: RecoverPasskeyPublicKeyArgs, + ): Promise { + let publicKeys: HexInput[] = []; + + for (const { authenticatorData, clientDataJSON, signature } of args) { + let recoveredPublicKeys = await Secp256r1PublicKey.recoverPasskeyPublicKey({ + clientDataJSON, + authenticatorData, + signature, + }); + recoveredPublicKeys.map((publicKey) => publicKeys.push(publicKey.toString())); + } + + // Public Key needs to appear more than once in the list + const commonKeys = [...new Set(publicKeys.filter((item, i, arr) => arr.indexOf(item) !== i))]; + return commonKeys.map((key) => new Secp256r1PublicKey(key)); + } + + /** + * Recover Secp256r1 Ecdsa Public Key from Signature + * + * @param authenticatorData authenticatorData + * @param clientDataJSON clientDataJSON + * @param signature signature + * @returns Secp256r1PublicKey + * + * @see https://github.com/ethereum/js-ethereum-cryptography/blob/9faadf5f1dda4aa95cc675d927281862ac7bf7e7/src/secp256k1-compat.ts#L47 + */ + static async recoverPublicKey({ message, signature }: RecoverPublicKeyArgsInput): Promise { + const publicKeys: Secp256r1PublicKey[] = []; + const msgHash = sha256(message); + const sig = secp256r1.Signature.fromCompact(signature); + + // TODO Double check recovery bit logic + // Cycle through all potential recovery bits (0, 1, 2, 3) + // to recover the one that is correct for the given signature + for (let recid = 0; recid < 4; recid++) { + try { + let publicKey = sig.addRecoveryBit(recid).recoverPublicKey(msgHash); + let secp256r1PublicKey = new Secp256r1PublicKey(publicKey.toRawBytes(false)); + + // If the Public Key verifies the signature correctly, add it to the publicKeys + if (p256.verify(signature, msgHash, secp256r1PublicKey.toUint8Array())) { + publicKeys.push(secp256r1PublicKey); + } + } catch (err) { + // Ignore and continue + } + } + + return publicKeys; + } + + /** + * Recover Secp256r1 Ecdsa Public Key from Signature + * + * @returns Secp256r1PublicKey + * + * @see https://github.com/ethereum/js-ethereum-cryptography/blob/9faadf5f1dda4aa95cc675d927281862ac7bf7e7/src/secp256k1-compat.ts#L47 + * @param args {RecoverPublicKeyArgs} + */ + static async recoverPublicKeyFromTwoSignatures(args: RecoverPublicKeyArgs): Promise { + let publicKeys: HexInput[] = []; + + for (const { message, signature } of args) { + let recoveredPublicKeys = await Secp256r1PublicKey.recoverPublicKey({ message, signature }); + recoveredPublicKeys.map((publicKey) => publicKeys.push(publicKey.toString())); + } + + // Public Key needs to appear more than once in the list + const commonKeys = [...new Set(publicKeys.filter((item, i, arr) => arr.indexOf(item) !== i))]; + return commonKeys.map((key) => new Secp256r1PublicKey(key)); + } +} + +/** + * A Secp256r1 ecdsa private key - this is only used for test purposes as signing is done via passkeys + */ +export class Secp256r1PrivateKey extends Serializable implements PrivateKey { + /** + * Length of Secp256r1 ecdsa private key + */ + static readonly LENGTH: number = 32; + + /** + * The private key bytes + * @private + */ + private readonly key: Hex; + + /** + * Create a new PrivateKey instance from a Uint8Array or String. + * + * @param hexInput A HexInput (string or Uint8Array) + */ + constructor(hexInput: HexInput) { + super(); + + const privateKeyHex = Hex.fromHexInput(hexInput); + if (privateKeyHex.toUint8Array().length !== Secp256r1PrivateKey.LENGTH) { + throw new Error(`PrivateKey length should be ${Secp256r1PrivateKey.LENGTH}`); + } + + this.key = privateKeyHex; + } + + /** + * Derives a private key from a mnemonic seed phrase. + * + * @param path the BIP44 path + * @param mnemonics the mnemonic seed phrase + * + * @returns The generated key + */ + static fromDerivationPath(path: string, mnemonics: string): Secp256r1PrivateKey { + if (!isValidBIP44Path(path)) { + throw new Error(`Invalid derivation path ${path}`); + } + return Secp256r1PrivateKey.fromDerivationPathInner(path, mnemonicToSeed(mnemonics)); + } + + /** + * A private inner function so we can separate from the main fromDerivationPath() method + * to add tests to verify we create the keys correctly. + * + * @param path the BIP44 path + * @param seed the seed phrase created by the mnemonics + * + * @returns The generated key + */ + private static fromDerivationPathInner(path: string, seed: Uint8Array): Secp256r1PrivateKey { + const { privateKey } = HDKey.fromMasterSeed(seed).derive(path); + // library returns privateKey as Uint8Array | null + if (privateKey === null) { + throw new Error("Invalid key"); + } + + return new Secp256r1PrivateKey(privateKey); + } + + /** + * Get the private key in bytes (Uint8Array). + * + * @returns + */ + toUint8Array(): Uint8Array { + return this.key.toUint8Array(); + } + + /** + * Get the private key as a hex string with the 0x prefix. + * + * @returns string representation of the private key + */ + toString(): string { + return this.key.toString(); + } + + /** + * Sign the given message with the private key. + * + * @param message in HexInput format + * @returns Signature + */ + sign(message: HexInput): Secp256r1Signature { + const messageToSign = convertSigningMessage(message); + const messageBytes = Hex.fromHexInput(messageToSign); + const messageHashBytes = sha256(messageBytes.toUint8Array()); + const signature = p256.sign(messageHashBytes, this.key.toUint8Array()); + return new Secp256r1Signature(signature.toCompactRawBytes()); + } + + /** + * Sign the given message with the private key. + * + * Note: This does not generate a signingMessage or transform the value. + * Useful for mocking how a Platform Authenticator signs a message + * with a WebAuthn credential + * + * @param message in HexInput format + * @returns Signature + */ + signArbitraryMessage(message: HexInput): Secp256r1Signature { + const messageBytes = Hex.fromHexInput(message); + const messageHashBytes = sha256(messageBytes.toUint8Array()); + // NOTE if you change to preHash here you will also need to update the verify() function parameters + const signature = p256.sign(messageHashBytes, this.key.toUint8Array(), { lowS: true }); + return new Secp256r1Signature(signature.toCompactRawBytes()); + } + + serialize(serializer: Serializer): void { + serializer.serializeBytes(this.toUint8Array()); + } + + static deserialize(deserializer: Deserializer): Secp256r1PrivateKey { + const bytes = deserializer.deserializeBytes(); + return new Secp256r1PrivateKey(bytes); + } + + /** + * Generate a new random private key. + * + * @returns Secp256r1PrivateKey + */ + static generate(): Secp256r1PrivateKey { + const hexInput = p256.utils.randomPrivateKey(); + return new Secp256r1PrivateKey(hexInput); + } + + /** + * Derive the Secp256r1PublicKey from this private key. + * + * @returns Secp256r1PublicKey + */ + publicKey(): Secp256r1PublicKey { + const bytes = p256.getPublicKey(this.key.toUint8Array(), false); + return new Secp256r1PublicKey(bytes); + } +} + +/** + * A signature of a message signed using an Secp256r1 ecdsa private key + */ +export class Secp256r1Signature extends Signature { + /** + * Secp256r1 ecdsa signatures are 256-bit. + */ + static readonly LENGTH = 64; + + /** + * The signature bytes + * @private + */ + private readonly data: Hex; + + /** + * Create a new Signature instance from a Uint8Array or String. It will convert the signature to its canonical if needed. + * + * @param hexInput A HexInput (string or Uint8Array) + */ + constructor(hexInput: HexInput) { + super(); + + const data = Hex.fromHexInput(hexInput); + if (data.toUint8Array().length !== Secp256r1Signature.LENGTH) { + throw new Error( + `Signature length should be ${Secp256r1Signature.LENGTH}, recieved ${data.toUint8Array().length}`, + ); + } + const signature = p256.Signature.fromCompact(data.toUint8Array()).normalizeS().toCompactRawBytes(); + this.data = Hex.fromHexInput(signature); + } + + /** + * Get the signature in bytes (Uint8Array). + * + * @returns Uint8Array representation of the signature + */ + toUint8Array(): Uint8Array { + return this.data.toUint8Array(); + } + + /** + * Get the signature as a hex string with the 0x prefix. + * + * @returns string representation of the signature + */ + toString(): string { + return this.data.toString(); + } + + serialize(serializer: Serializer): void { + serializer.serializeBytes(this.data.toUint8Array()); + } + + static deserialize(deserializer: Deserializer): Secp256r1Signature { + const hex = deserializer.deserializeBytes(); + return new Secp256r1Signature(hex); + } + + static load(deserializer: Deserializer): Secp256r1Signature { + const bytes = deserializer.deserializeBytes(); + return new Secp256r1Signature(bytes); + } +} diff --git a/src/core/crypto/singleKey.ts b/src/core/crypto/singleKey.ts index 72f34a761..93ebec87e 100644 --- a/src/core/crypto/singleKey.ts +++ b/src/core/crypto/singleKey.ts @@ -2,10 +2,12 @@ import { Deserializer, Serializer } from "../../bcs"; import { AnyPublicKeyVariant, AnySignatureVariant, SigningScheme as AuthenticationKeyScheme } from "../../types"; import { AuthenticationKey } from "../authenticationKey"; import { Ed25519PublicKey, Ed25519Signature } from "./ed25519"; +import { KeylessPublicKey, KeylessSignature } from "./keyless"; import { AccountPublicKey, PublicKey, VerifySignatureArgs } from "./publicKey"; import { Secp256k1PublicKey, Secp256k1Signature } from "./secp256k1"; -import { KeylessPublicKey, KeylessSignature } from "./keyless"; +import { Secp256r1PublicKey, Secp256r1Signature } from "./secp256r1"; import { Signature } from "./signature"; +import { WebAuthnSignature } from "./webauthn"; /** * Represents any public key supported by Aptos. @@ -37,6 +39,8 @@ export class AnyPublicKey extends AccountPublicKey { this.variant = AnyPublicKeyVariant.Secp256k1; } else if (publicKey instanceof KeylessPublicKey) { this.variant = AnyPublicKeyVariant.Keyless; + } else if (publicKey instanceof Secp256r1PublicKey) { + this.variant = AnyPublicKeyVariant.Secp256r1; } else { throw new Error("Unsupported public key type"); } @@ -91,6 +95,9 @@ export class AnyPublicKey extends AccountPublicKey { case AnyPublicKeyVariant.Keyless: publicKey = KeylessPublicKey.deserialize(deserializer); break; + case AnyPublicKeyVariant.Secp256r1: + publicKey = Secp256r1PublicKey.deserialize(deserializer); + break; default: throw new Error(`Unknown variant index for AnyPublicKey: ${variantIndex}`); } @@ -150,6 +157,10 @@ export class AnySignature extends Signature { this.variant = AnySignatureVariant.Secp256k1; } else if (signature instanceof KeylessSignature) { this.variant = AnySignatureVariant.Keyless; + } else if (signature instanceof WebAuthnSignature) { + this.variant = AnySignatureVariant.WebAuthn; + } else if (signature instanceof Secp256r1Signature) { + this.variant = AnySignatureVariant.Secp256r1; } else { throw new Error("Unsupported signature type"); } @@ -191,6 +202,12 @@ export class AnySignature extends Signature { case AnySignatureVariant.Keyless: signature = KeylessSignature.deserialize(deserializer); break; + case AnySignatureVariant.WebAuthn: + signature = WebAuthnSignature.deserialize(deserializer); + break; + case AnySignatureVariant.Secp256r1: + signature = Secp256r1Signature.deserialize(deserializer); + break; default: throw new Error(`Unknown variant index for AnySignature: ${variantIndex}`); } diff --git a/src/core/crypto/webauthn.ts b/src/core/crypto/webauthn.ts new file mode 100644 index 000000000..b0aead1fb --- /dev/null +++ b/src/core/crypto/webauthn.ts @@ -0,0 +1,155 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +import { sha256 } from "@noble/hashes/sha256"; +import { Deserializer, Serializer } from "../../bcs"; +import { AssertionSignatureVariant, HexInput } from "../../types"; +import { Hex } from "../hex"; +import { Secp256r1Signature } from "./secp256r1"; +import { Signature } from "./signature"; + +export class AssertionSignature extends Signature { + public readonly signature: Signature; + + constructor(signature: Signature) { + super(); + this.signature = signature; + } + + /** + * Get the signature in bytes (Uint8Array). + * + * @returns Uint8Array representation of the signature + */ + toUint8Array(): Uint8Array { + return this.signature.toUint8Array(); + } + + /** + * Get the signature as a hex string with the 0x prefix. + * + * @returns string representation of the signature + */ + toString(): string { + return this.signature.toString(); + } + + serialize(serializer: Serializer): void { + if (this.signature instanceof Secp256r1Signature) { + serializer.serializeU32AsUleb128(AssertionSignatureVariant.Secp256r1); + this.signature.serialize(serializer); + } else { + throw new Error("Unknown signature type for AssertionSignature"); + } + } + + static deserialize(deserializer: Deserializer): AssertionSignature { + const index = deserializer.deserializeUleb128AsU32(); + switch (index) { + case AssertionSignatureVariant.Secp256r1: + return new AssertionSignature(Secp256r1Signature.load(deserializer)); + default: + throw new Error(`Unknown variant index for AssertionSignature: ${index}`); + } + } +} + +export class PartialAuthenticatorAssertionResponse { + readonly signature: AssertionSignature; + + readonly authenticatorData: Uint8Array; + + readonly clientDataJSON: Uint8Array; + + constructor(signature: Signature, authenticatorData: HexInput, clientDataJSON: HexInput) { + this.signature = new AssertionSignature(signature); + + this.authenticatorData = Hex.fromHexInput(authenticatorData).toUint8Array(); + + this.clientDataJSON = Hex.fromHexInput(clientDataJSON).toUint8Array(); + } +} + +export type ClientDataJSON = { + type: string; + challenge: string; + origin: string; + crossOrigin?: boolean; + tokenBinding?: { + id?: string; + status: "present" | "supported" | "not-supported"; + }; +}; + +/** + * A signature of WebAuthn transaction + */ +export class WebAuthnSignature extends Signature { + /** + * The signature bytes + */ + readonly paar: PartialAuthenticatorAssertionResponse; + + /** + * Create a new Signature instance from a Uint8Array or String. + * + * @param hexInput A HexInput (string or Uint8Array) + */ + constructor(signature: Signature, authenticatorData: HexInput, clientDataJSON: HexInput) { + super(); + + this.paar = new PartialAuthenticatorAssertionResponse(signature, authenticatorData, clientDataJSON); + } + + /** + * Get the signature in bytes (Uint8Array). + * + * @returns Uint8Array representation of the signature + */ + toUint8Array(): Uint8Array { + return this.paar.signature.toUint8Array(); + } + + /** + * Get the signature as a hex string with the 0x prefix. + * + * @returns string representation of the signature + */ + toString(): string { + return this.paar.toString(); + } + + getCollectedClientData(): ClientDataJSON { + const utf8Decoder = new TextDecoder("utf-8"); + const decodedClientData = utf8Decoder.decode(this.paar.clientDataJSON); + return JSON.parse(decodedClientData); + } + + getVerificationData(): Uint8Array { + const clientDataJSONHash = sha256(this.paar.clientDataJSON); + const mergedArray = new Uint8Array(clientDataJSONHash.length + this.paar.authenticatorData.length); + mergedArray.set(this.paar.authenticatorData); + mergedArray.set(clientDataJSONHash, this.paar.authenticatorData.length); + return mergedArray; + } + + serialize(serializer: Serializer): void { + this.paar.signature.serialize(serializer); + serializer.serializeBytes(this.paar.authenticatorData); + serializer.serializeBytes(this.paar.clientDataJSON); + } + + static deserialize(deserializer: Deserializer): WebAuthnSignature { + const sig = AssertionSignature.deserialize(deserializer); + const authData = deserializer.deserializeBytes(); + const clientDataJSON = deserializer.deserializeBytes(); + return new WebAuthnSignature(sig.signature, authData, clientDataJSON); + } + + static load(deserializer: Deserializer): WebAuthnSignature { + const sig = AssertionSignature.deserialize(deserializer); + const authData = deserializer.deserializeBytes(); + const clientDataJSON = deserializer.deserializeBytes(); + return new WebAuthnSignature(sig.signature, authData, clientDataJSON); + } +} diff --git a/src/internal/account.ts b/src/internal/account.ts index 1a831399b..d71a64547 100644 --- a/src/internal/account.ts +++ b/src/internal/account.ts @@ -8,12 +8,18 @@ * account namespace and without having a dependency cycle error. */ +import { Account } from "../account"; import { AptosConfig } from "../api/aptosConfig"; import { AptosApiError, getAptosFullNode, paginateWithCursor } from "../client"; +import { + AuthenticationKey, + Ed25519PrivateKey, + Secp256k1PrivateKey, + Secp256r1PrivateKey, + createObjectAddress, +} from "../core"; import { AccountAddress, AccountAddressInput } from "../core/accountAddress"; -import { Account } from "../account"; import { AnyPublicKey, Ed25519PublicKey, PrivateKey } from "../core/crypto"; -import { queryIndexer } from "./general"; import { AccountData, GetAccountCoinsDataResponse, @@ -35,27 +41,27 @@ import { GetAccountCoinsCountQuery, GetAccountCoinsDataQuery, GetAccountCollectionsWithOwnedTokensQuery, - GetObjectDataQuery, GetAccountOwnedTokensFromCollectionQuery, GetAccountOwnedTokensQuery, GetAccountTokensCountQuery, GetAccountTransactionsCountQuery, + GetObjectDataQuery, } from "../types/generated/operations"; import { GetAccountCoinsCount, GetAccountCoinsData, GetAccountCollectionsWithOwnedTokens, - GetObjectData, GetAccountOwnedTokens, GetAccountOwnedTokensFromCollection, GetAccountTokensCount, GetAccountTransactionsCount, + GetObjectData, } from "../types/generated/queries"; -import { memoizeAsync } from "../utils/memoize"; -import { Secp256k1PrivateKey, AuthenticationKey, Ed25519PrivateKey, createObjectAddress } from "../core"; import { CurrentFungibleAssetBalancesBoolExp } from "../types/generated/types"; -import { getTableItem } from "./table"; import { APTOS_COIN } from "../utils"; +import { memoizeAsync } from "../utils/memoize"; +import { queryIndexer } from "./general"; +import { getTableItem } from "./table"; export async function getInfo(args: { aptosConfig: AptosConfig; @@ -562,6 +568,13 @@ export async function deriveAccountFromPrivateKey(args: { return Account.fromPrivateKey({ privateKey, address }); } + if (privateKey instanceof Secp256r1PrivateKey) { + // private key is secp256r1, therefore we know it for sure uses a single signer key + const authKey = AuthenticationKey.fromPublicKey({ publicKey }); + const address = authKey.derivedAddress(); + return Account.fromPrivateKey({ privateKey, address }); + } + if (privateKey instanceof Ed25519PrivateKey) { // lookup single sender ed25519 const singleSenderTransactionAuthenticatorAuthKey = AuthenticationKey.fromPublicKey({ diff --git a/src/internal/passkey.ts b/src/internal/passkey.ts new file mode 100644 index 000000000..4d4a9d9f1 --- /dev/null +++ b/src/internal/passkey.ts @@ -0,0 +1,359 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +/** + * This file contains the underlying implementations for exposed API surface in + * the {@link api/passkey}. By moving the methods out into a separate file, + * other namespaces and processes can access these methods without depending on the entire + * faucet namespace and without having a dependency cycle error. + */ +import { bufferToBase64URLString, startAuthentication, startRegistration } from "@simplewebauthn/browser"; +import { + VerifiedAuthenticationResponse, + VerifiedRegistrationResponse, + generateAuthenticationOptions as _generateAuthenticationOptions, + generateRegistrationOptions as _generateRegistrationOptions, + verifyAuthenticationResponse as _verifyAuthenticationResponse, + verifyRegistrationResponse as _verifyRegistrationResponse, +} from "@simplewebauthn/server"; +import { + AuthenticationResponseJSON, + AuthenticatorDevice, + PublicKeyCredentialCreationOptionsJSON, + PublicKeyCredentialRequestOptionsJSON, + RegistrationResponseJSON, +} from "@simplewebauthn/server/esm/deps"; +import { convertCOSEtoPKCS, cose, isoBase64URL, parseAuthenticatorData } from "@simplewebauthn/server/helpers"; +import { AptosConfig } from "../api/aptosConfig"; +import { AccountAddress, AccountPublicKey, AuthenticationKey, ClientDataJSON, PublicKey } from "../core"; +import { Secp256r1PublicKey } from "../core/crypto/secp256r1"; +import { AccountAuthenticator, AnyRawTransaction, signWithPasskey as _signWithPasskey } from "../transactions"; +import { HexInput, PendingTransactionResponse } from "../types"; +import { AllowCredentialOption } from "../types/passkey"; +import { submitTransaction } from "./transactionSubmission"; + +const supportedAlgorithmIDs = [cose.COSEALG.ES256]; + +export async function generateRegistrationOptions(args: { + rpName: string; + rpID: string; + userID?: Uint8Array; + userName: string; + challenge?: string | Uint8Array; + userDisplayName?: string; + timeout?: number; + attestationType?: AttestationConveyancePreference; + authenticatorAttachment?: AuthenticatorAttachment; +}): Promise { + const { authenticatorAttachment } = args; + const authenticatorSelection: AuthenticatorSelectionCriteria = { + authenticatorAttachment, + residentKey: "required", + userVerification: "required", + }; + + return _generateRegistrationOptions({ + ...args, + authenticatorSelection, + supportedAlgorithmIDs, + }); +} + +export async function registerCredential( + creationOptionsJSON: PublicKeyCredentialCreationOptionsJSON, +): Promise { + return startRegistration(creationOptionsJSON); +} + +export async function verifyRegistrationResponse(args: { + response: RegistrationResponseJSON; + expectedChallenge: string | ((challenge: string) => boolean | Promise); + expectedOrigin: string | string[]; + expectedRPID?: string | string[]; +}): Promise { + return _verifyRegistrationResponse({ + ...args, + requireUserVerification: true, + supportedAlgorithmIDs, + }); +} + +export async function generateAuthenticationOptions(args: { + credentialId: string | Uint8Array; + timeout?: number; + rpID: string; +}): Promise { + const { credentialId } = args; + const allowCredentials: AllowCredentialOption[] = [ + { + id: typeof credentialId !== "string" ? bufferToBase64URLString(credentialId) : credentialId, + }, + ]; + return _generateAuthenticationOptions({ ...args, allowCredentials, userVerification: "required" }); +} + +export async function authenticateCredential( + requestOptionsJSON: PublicKeyCredentialRequestOptionsJSON, +): Promise { + return startAuthentication(requestOptionsJSON); +} + +export async function verifyAuthenticationResponse(args: { + response: AuthenticationResponseJSON; + expectedChallenge: string | ((challenge: string) => boolean | Promise); + expectedOrigin: string | string[]; + expectedRPID: string | string[]; + expectedType?: string | string[]; + authenticator: AuthenticatorDevice; + requireUserVerification?: boolean; + advancedFIDOConfig?: { + userVerification?: UserVerificationRequirement; + }; +}): Promise { + return _verifyAuthenticationResponse({ ...args }); +} + +export function parsePublicKey(response: RegistrationResponseJSON): PublicKey { + const authData = isoBase64URL.toBuffer(response.response.authenticatorData!); + const parsedAuthenticatorData = parseAuthenticatorData(authData); + // Convert from COSE + const publicKey = convertCOSEtoPKCS(parsedAuthenticatorData.credentialPublicKey!); + return new Secp256r1PublicKey(publicKey); +} + +export async function signWithPasskey(args: { + credentialId: string | Uint8Array; + publicKey: PublicKey; + transaction: AnyRawTransaction; + timeout?: number; + rpID: string; + options?: { + allowCredentials?: AllowCredentialOption[]; + }; +}): Promise { + return _signWithPasskey({ ...args }); +} + +export async function signAndSubmitWithPasskey(args: { + aptosConfig: AptosConfig; + credentialId: string | Uint8Array; + publicKey: PublicKey; + transaction: AnyRawTransaction; + timeout?: number; + rpID: string; + options?: { + allowCredentials?: AllowCredentialOption[]; + }; +}): Promise { + const { aptosConfig, transaction } = args; + + const authenticator = await signWithPasskey({ ...args }); + return submitTransaction({ + aptosConfig, + transaction, + senderAuthenticator: authenticator, + }); +} + +export async function getPasskeyAccountAddress(args: { publicKey: HexInput; alg?: number }): Promise { + const { publicKey, alg } = args; + const algorithm = alg ?? cose.COSEALG.ES256; + + let publicKeyObj: AccountPublicKey; + switch (algorithm) { + // ES256, P256, Secp256r1 are all the same thing. + case cose.COSEALG.ES256: + publicKeyObj = new Secp256r1PublicKey(publicKey); + break; + default: + throw new Error("Algorithm is not supported"); + } + const authKey = AuthenticationKey.fromPublicKey({ publicKey: publicKeyObj }); + return AccountAddress.from(authKey.toString()); +} + +/** + * The function `ccd_to_string` is used in + * [`client_data_to_json_bytes`](client_data_to_json_bytes) + * and is defined as: + * + * 1. Let `encoded` be an empty byte string. + * 2. Append 0x22 (") to `encoded`. -> 0x22 is the hexadecimal for a double quote (") + * 3. Invoke `ToString` on the given object to convert it to a string. + * 4. For each code point in the resulting string, if the code point: + * + * -> is in the set {U+0020, U+0021, U+0023–U+005B, U+005D–U+10FFFF} + * Append the UTF-8 encoding of that code point to `encoded`. + * + * -> is U+0022 + * Append 0x5c22 (\") to `encoded`. + * + * -> is U+005C + * Append 0x5c5c (\\) to `encoded`. + * + * -> otherwise + * Append 0x5c75 (\u) to `encoded`, followed by four lower-case hex digits that, + * when interpreted as a base-16 number, represent that code point. + * + * 5. Append 0x22 (") to `encoded`. + * 6. The result of this function is the value of `encoded`. + * + * @see https://www.w3.org/TR/webauthn-3/#ccdtostring + * + * Mimics functionality provided here: + * @see https://github.com/aptos-labs/aptos-core/pull/10755/files#diff-aa8fc08bb2653b4289de532f8454b03f0f04426c63d30f5ccfd34b185e28bb68R314 + */ +export function ccdToString(input: string): Uint8Array { + const encoded: number[] = []; + + // Append 0x22 (") + encoded.push(0x22); + + for (const codePoint of input) { + const code = codePoint.codePointAt(0); + + if (code === undefined) { + continue; + } + + if ((code >= 0x0020 && code <= 0x0021) || (code >= 0x0023 && code <= 0x005B) || (code >= 0x005D && code <= 0x10FFFF)) { + // Append the UTF-8 encoding of the code point + const utf8Bytes = new TextEncoder().encode(codePoint); + encoded.push(...utf8Bytes); + } else if (code === 0x0022) { + // Append 0x5c22 (\") + encoded.push(0x5C, 0x22); + } else if (code === 0x005C) { + // Append 0x5c5c (\\) + encoded.push(0x5C, 0x5C); + } else { + // Append 0x5c75 (\u) followed by four lower-case hex digits + encoded.push(0x5C, 0x75); + const hexDigits = code.toString(16).padStart(4, '0'); + for (const hexByte of hexDigits) { + encoded.push(hexByte.charCodeAt(0)); + } + } + } + + // Append 0x22 (") + encoded.push(0x22); + + return new Uint8Array(encoded); +} + +/** + * This is the custom serialization of [`ClientDataJSON`](ClientDataJSON) + * that is performed by the device authenticator, referenced in the WebAuthn spec, under + * Section §5.8.1.1 Serialization. + * + * This is helpful for ensuring that the serialization of [`CollectedClientData`](CollectedClientData) + * is identical to the device authenticator's output for clientDataJSON in client assertions. + * + * The serialization of the [`ClientDataJSON`](ClientDataJSON) + * is a subset of the algorithm for JSON-serializing + * to bytes. I.e. it produces a valid JSON encoding of the `CollectedClientData` but also provides + * additional structure that may be exploited by verifiers to avoid integrating a full JSON parser. + * While verifiers are recommended to perform standard JSON parsing, they may use the more + * limited algorithm below in contexts where a full JSON parser is too large. This verification + * algorithm requires only base64url encoding, appending of bytestrings (which could be + * implemented by writing into a fixed template), and three conditional checks (assuming that + * inputs are known not to need escaping). + * + * The serialization algorithm works by appending successive byte strings to an, initially empty, + * partial result until the complete result is obtained. + * + * 1. Let result be an empty byte string. + * 2. Append 0x7b2274797065223a ({"type":) to result. + * 3. Append CCDToString(type) to result. + * 4. Append 0x2c226368616c6c656e6765223a (,"challenge":) to result. + * 5. Append CCDToString(challenge) to result. + * 6. Append 0x2c226f726967696e223a (,"origin":) to result. + * 7. Append CCDToString(origin) to result. + * 8. Append 0x2c2263726f73734f726967696e223a (,"crossOrigin":) to result. + * 9. If crossOrigin is not present, or is false: + * 1. Append 0x66616c7365 (false) to result. + * 10. Otherwise: + * 1. Append 0x74727565 (true) to result. + * 11. Create a temporary copy of the CollectedClientData and remove the fields + * type, challenge, origin, and crossOrigin (if present). + * 12. If no fields remain in the temporary copy then: + * 1. Append 0x7d (}) to result. + * 13. Otherwise: + * 1. Invoke serialize JSON to bytes on the temporary copy to produce a byte string remainder. + * (see below for how this is done) + * 2. Append 0x2c (,) to result. + * 3. Remove the leading byte from remainder. + * 4. Append remainder to result. + * 14. The result of the serialization is the value of result. + * + * From step 13.1 + * To serialize a JavaScript value to JSON bytes, given a JavaScript value value: + * 1. Let string be the result of serializing a JavaScript value to a JSON string given value. + * 2. Return the result of running UTF-8 encode on string. + * + * @see https://www.w3.org/TR/webauthn-3/#clientdatajson-serialization + * + * Mimics functionality provided here + * @see https://github.com/aptos-labs/aptos-core/pull/10755/files#diff-aa8fc08bb2653b4289de532f8454b03f0f04426c63d30f5ccfd34b185e28bb68R403 + */ +export function clientDataToJsonBytes(clientDataJSON: ClientDataJSON): Uint8Array { + let result: number[] = []; + + // Append {"type": + result.push(...[0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a]); + + // Append type value + result.push(...ccdToString(clientDataJSON.type)); + + // Append ,"challenge": + result.push(...[0x2c, 0x22, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x22, 0x3a]); + + // Append challenge value + result.push(...ccdToString(clientDataJSON.challenge)); + + // Append ,"origin": + result.push(...[0x2c, 0x22, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x22, 0x3a]); + + // Append origin value + result.push(...ccdToString(clientDataJSON.origin)); + + // Append ,"crossOrigin": + result.push(...[0x2c, 0x22, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x22, 0x3a]); + + if (clientDataJSON.crossOrigin !== undefined) { + if (clientDataJSON.crossOrigin) { + // Append true + result.push(...[0x74, 0x72, 0x75, 0x65]); + } else { + // Append false + result.push(...[0x66, 0x61, 0x6c, 0x73, 0x65]); + } + } else { + // Append false if crossOrigin is not present + result.push(...[0x66, 0x61, 0x6c, 0x73, 0x65]); + } + + // Create a temporary copy of CollectedClientData + // remove the fields type, challenge, origin, crossOrigin (if present), and topOrigin (if present) + // tempCopy is the remaining object + const { type, challenge, origin, crossOrigin, ...tempCopy } = { ...clientDataJSON }; + + // Check if any fields other than type, challenge, origin, and crossOrigin remain in the temporary copy + // TODO Check if undefined values in dictionary should be deleted (e.g., tokenBinding) + if (Object.keys(tempCopy).length === 0) { + // If no fields remain, append } + result.push(0x7d); + } else { + // Otherwise, serialize remaining fields to JSON bytes + const remainder = new TextEncoder().encode(JSON.stringify(tempCopy)); + + // Append , + result.push(0x2c); + + // Remove the leading byte from remainder and append the rest + result.push(...Array.from(remainder).slice(1)); + } + + return new Uint8Array(result); +} diff --git a/src/internal/transactionSubmission.ts b/src/internal/transactionSubmission.ts index 4d149e27f..21ead4bef 100644 --- a/src/internal/transactionSubmission.ts +++ b/src/internal/transactionSubmission.ts @@ -5,37 +5,37 @@ * transaction namespace and without having a dependency cycle error. */ +import { Account, KeylessAccount, MultiKeyAccount } from "../account"; import { AptosConfig } from "../api/aptosConfig"; import { MoveVector, U8 } from "../bcs"; import { postAptosFullNode } from "../client"; -import { Account, KeylessAccount, MultiKeyAccount } from "../account"; import { AccountAddress, AccountAddressInput } from "../core/accountAddress"; import { PrivateKey } from "../core/crypto"; +import { TypeTagU8, TypeTagVector, generateSigningMessageForTransaction } from "../transactions"; import { AccountAuthenticator } from "../transactions/authenticator/account"; +import { MultiAgentTransaction } from "../transactions/instances/multiAgentTransaction"; import { RotationProofChallenge } from "../transactions/instances/rotationProofChallenge"; +import { SimpleTransaction } from "../transactions/instances/simpleTransaction"; import { buildTransaction, - generateTransactionPayload, - generateSignedTransactionForSimulation, generateSignedTransaction, + generateSignedTransactionForSimulation, + generateTransactionPayload, } from "../transactions/transactionBuilder/transactionBuilder"; import { - InputGenerateTransactionData, AnyRawTransaction, - InputSimulateTransactionData, + AnyTransactionPayloadInstance, + EntryFunctionABI, + InputGenerateMultiAgentRawTransactionData, + InputGenerateSingleSignerRawTransactionData, + InputGenerateTransactionData, InputGenerateTransactionOptions, InputGenerateTransactionPayloadDataWithRemoteABI, + InputSimulateTransactionData, InputSubmitTransactionData, - InputGenerateMultiAgentRawTransactionData, - InputGenerateSingleSignerRawTransactionData, - AnyTransactionPayloadInstance, - EntryFunctionABI, } from "../transactions/types"; +import { HexInput, MimeType, PendingTransactionResponse, TransactionResponse, UserTransactionResponse } from "../types"; import { getInfo } from "./account"; -import { UserTransactionResponse, PendingTransactionResponse, MimeType, HexInput, TransactionResponse } from "../types"; -import { TypeTagU8, TypeTagVector, generateSigningMessageForTransaction } from "../transactions"; -import { SimpleTransaction } from "../transactions/instances/simpleTransaction"; -import { MultiAgentTransaction } from "../transactions/instances/multiAgentTransaction"; /** * We are defining function signatures, each with its specific input and output. diff --git a/src/transactions/transactionBuilder/transactionBuilder.ts b/src/transactions/transactionBuilder/transactionBuilder.ts index e777a100e..ac9e598b1 100644 --- a/src/transactions/transactionBuilder/transactionBuilder.ts +++ b/src/transactions/transactionBuilder/transactionBuilder.ts @@ -6,16 +6,25 @@ * It holds different operations to generate a transaction payload, a raw transaction, * and a signed transaction that can be simulated, signed and submitted to chain. */ +import { p256 } from "@noble/curves/p256"; import { sha3_256 as sha3Hash } from "@noble/hashes/sha3"; +import { base64URLStringToBuffer, bufferToBase64URLString, startAuthentication } from "@simplewebauthn/browser"; +import { generateAuthenticationOptions } from "@simplewebauthn/server"; +import { isoBase64URL } from "@simplewebauthn/server/helpers"; import { AptosConfig } from "../../api/aptosConfig"; import { AccountAddress, AccountAddressInput, Hex, PublicKey } from "../../core"; import { AnyPublicKey, AnySignature, KeylessPublicKey, KeylessSignature, Secp256k1PublicKey } from "../../core/crypto"; import { Ed25519PublicKey, Ed25519Signature } from "../../core/crypto/ed25519"; +import { Secp256r1PublicKey, Secp256r1Signature } from "../../core/crypto/secp256r1"; +import { WebAuthnSignature } from "../../core/crypto/webauthn"; import { getInfo } from "../../internal/account"; import { getLedgerInfo } from "../../internal/general"; import { getGasPriceEstimation } from "../../internal/transaction"; +import { HexInput } from "../../types"; +import { AllowCredentialOption } from "../../types/passkey"; import { NetworkToChainId } from "../../utils/apiEndpoints"; import { DEFAULT_MAX_GAS_AMOUNT, DEFAULT_TXN_EXP_SEC_FROM_NOW } from "../../utils/const"; +import { memoizeAsync } from "../../utils/memoize"; import { normalizeBundle } from "../../utils/normalizeBundle"; import { AccountAuthenticator, @@ -42,33 +51,33 @@ import { TransactionPayloadMultiSig, TransactionPayloadScript, } from "../instances"; +import { MultiAgentTransaction } from "../instances/multiAgentTransaction"; import { SignedTransaction } from "../instances/signedTransaction"; +import { SimpleTransaction } from "../instances/simpleTransaction"; import { AnyRawTransaction, AnyTransactionPayloadInstance, EntryFunctionArgumentTypes, + FunctionABI, + InputEntryFunctionDataWithABI, + InputEntryFunctionDataWithRemoteABI, InputGenerateMultiAgentRawTransactionArgs, InputGenerateRawTransactionArgs, InputGenerateSingleSignerRawTransactionArgs, InputGenerateTransactionOptions, + InputGenerateTransactionPayloadDataWithABI, + InputGenerateTransactionPayloadDataWithRemoteABI, + InputMultiSigDataWithABI, + InputMultiSigDataWithRemoteABI, InputScriptData, InputSimulateTransactionData, - InputMultiSigDataWithRemoteABI, - InputEntryFunctionDataWithRemoteABI, - InputGenerateTransactionPayloadDataWithRemoteABI, InputSubmitTransactionData, - InputGenerateTransactionPayloadDataWithABI, - InputEntryFunctionDataWithABI, - InputMultiSigDataWithABI, - InputViewFunctionDataWithRemoteABI, InputViewFunctionDataWithABI, - FunctionABI, + InputViewFunctionDataWithRemoteABI, } from "../types"; -import { convertArgument, fetchEntryFunctionAbi, fetchViewFunctionAbi, standardizeTypeTags } from "./remoteAbi"; -import { memoizeAsync } from "../../utils/memoize"; import { getFunctionParts, isScriptDataInput } from "./helpers"; -import { SimpleTransaction } from "../instances/simpleTransaction"; -import { MultiAgentTransaction } from "../instances/multiAgentTransaction"; +import { convertArgument, fetchEntryFunctionAbi, fetchViewFunctionAbi, standardizeTypeTags } from "./remoteAbi"; +import { generateSigningMessageForTransaction } from "./signingMessage"; /** * We are defining function signatures, each with its specific input and output. @@ -470,6 +479,86 @@ export function getAuthenticatorForSimulation(publicKey: PublicKey) { throw new Error("Unsupported public key"); } +export async function signWithPasskey(args: { + publicKey: PublicKey; + credentialId: string | Uint8Array; + transaction: AnyRawTransaction; + timeout?: number; + rpID: string; + options?: { + allowCredentials?: AllowCredentialOption[]; + }; +}): Promise { + const { credentialId, publicKey, transaction, timeout, rpID, options } = args; + + if (!(publicKey instanceof Secp256r1PublicKey)) { + throw new Error("Unsupported public key for passkey signing."); + } + + const allowCredentials: AllowCredentialOption[] = options?.allowCredentials ?? [ + { + id: typeof credentialId !== "string" ? bufferToBase64URLString(credentialId) : credentialId, + }, + ]; + + // Get the signing message and hash it to create the challenge + const signingMessage = generateSigningMessageForTransaction(transaction); + const challenge = sha3Hash(signingMessage); + + const authOptions = await generateAuthenticationOptions({ + rpID, + allowCredentials, + challenge, + timeout, + userVerification: "required", + }); + const authenticationResponse = await startAuthentication(authOptions); + + const authenticatorAssertionResponse = authenticationResponse.response; + + const { clientDataJSON, authenticatorData, signature } = authenticatorAssertionResponse; + + const signatureCompact = p256.Signature.fromDER( + new Uint8Array(base64URLStringToBuffer(signature)), + ).toCompactRawBytes(); + + const webAuthnSignature = new WebAuthnSignature( + new Secp256r1Signature(signatureCompact), + isoBase64URL.toBuffer(authenticatorData), + isoBase64URL.toBuffer(clientDataJSON), + ); + + return new AccountAuthenticatorSingleKey(new AnyPublicKey(publicKey), new AnySignature(webAuthnSignature)); +} + +/** + * Creates the and returns the Authenticator for passkey signed transactions. + * + * @param args.publicKey The public key of the passkey credential. + * @param args.signature The P256signature which is the signed challenge. + * @param args.authenticatorData The AuthenticatorData of the assertion. + * @param args.clientDataJSON The clientDataJSON of the assertion. + * + * @return The signer AccountAuthenticator + */ +export function getAuthenticatorForWebAuthn(args: { + publicKey: HexInput; + signature: HexInput; + authenticatorData: HexInput; + clientDataJSON: HexInput; +}): AccountAuthenticator { + const { publicKey, signature, authenticatorData, clientDataJSON } = args; + let signatureObj: AnySignature; + if (publicKey instanceof Secp256r1PublicKey) { + signatureObj = new AnySignature(new Secp256r1Signature(signature)); + } else { + throw new Error("Unsupported public key"); + } + const webAuthnSignature = new WebAuthnSignature(signatureObj, authenticatorData, clientDataJSON); + + return new AccountAuthenticatorSingleKey(new AnyPublicKey(publicKey), new AnySignature(webAuthnSignature)); +} + /** * Prepare a transaction to be submitted to chain * diff --git a/src/types/index.ts b/src/types/index.ts index a91953914..7830f2777 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -108,13 +108,16 @@ export enum AccountAuthenticatorVariant { export enum AnyPublicKeyVariant { Ed25519 = 0, Secp256k1 = 1, + Secp256r1 = 2, Keyless = 3, } export enum AnySignatureVariant { Ed25519 = 0, Secp256k1 = 1, + WebAuthn = 2, Keyless = 3, + Secp256r1 = 4, } export enum EphemeralPublicKeyVariant { @@ -133,6 +136,10 @@ export enum ZkpVariant { Groth16 = 0, } +export enum AssertionSignatureVariant { + Secp256r1 = 0, +} + /** * BCS types */ @@ -1140,6 +1147,10 @@ export enum SigningSchemeInput { * For Secp256k1Ecdsa */ Secp256k1Ecdsa = 2, + /** + * For Secp256r1Ecdsa + */ + Secp256r1Ecdsa = 3, } /** @@ -1196,4 +1207,16 @@ export type GenerateAccountWithSingleSignerSecp256k1Key = { legacy?: false; }; -export type GenerateAccount = GenerateAccountWithEd25519 | GenerateAccountWithSingleSignerSecp256k1Key; +/** + * Input type to generate an account using Single Signer + * Secp256r1 + */ +export type GenerateAccountWithSingleSignerSecp256r1Key = { + scheme: SigningSchemeInput.Secp256r1Ecdsa; + legacy?: false; +}; + +export type GenerateAccount = + | GenerateAccountWithEd25519 + | GenerateAccountWithSingleSignerSecp256k1Key + | GenerateAccountWithSingleSignerSecp256r1Key; diff --git a/src/types/passkey.ts b/src/types/passkey.ts new file mode 100644 index 000000000..746c6a5d2 --- /dev/null +++ b/src/types/passkey.ts @@ -0,0 +1,6 @@ +import { AuthenticatorTransportFuture, Base64URLString } from "@simplewebauthn/server/esm/deps"; + +export type AllowCredentialOption = { + id: Base64URLString; + transports?: AuthenticatorTransportFuture[]; +}; diff --git a/tests/e2e/api/account.test.ts b/tests/e2e/api/account.test.ts index 1ed01a66e..cc03ed5b6 100644 --- a/tests/e2e/api/account.test.ts +++ b/tests/e2e/api/account.test.ts @@ -287,6 +287,14 @@ describe("account api", () => { const derivedAccount = await aptos.deriveAccountFromPrivateKey({ privateKey: account.privateKey }); expect(derivedAccount).toStrictEqual(account); }); + test("single sender secp256r1", async () => { + const config = new AptosConfig({ network: Network.LOCAL }); + const aptos = new Aptos(config); + const account = Account.generate({ scheme: SigningSchemeInput.Secp256r1Ecdsa }); + + const derivedAccount = await aptos.deriveAccountFromPrivateKey({ privateKey: account.privateKey }); + expect(derivedAccount).toStrictEqual(account); + }); test("legacy ed25519", async () => { const config = new AptosConfig({ network: Network.LOCAL }); const aptos = new Aptos(config); diff --git a/tests/e2e/api/passkey.test.ts b/tests/e2e/api/passkey.test.ts new file mode 100644 index 000000000..563213401 --- /dev/null +++ b/tests/e2e/api/passkey.test.ts @@ -0,0 +1,237 @@ +/* eslint-disable max-len */ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +import * as browser from "@simplewebauthn/browser"; +import { base64URLStringToBuffer, bufferToBase64URLString } from "@simplewebauthn/browser"; +import { AuthenticationResponseJSON, RegistrationResponseJSON } from "@simplewebauthn/server/esm/deps"; +import { + AccountAddress, + AnyRawTransaction, + ClientDataJSON, + generateSigningMessageForTransaction, + Secp256r1PrivateKey, + Secp256r1PublicKey, +} from "../../../src"; +import { clientDataToJsonBytes, getPasskeyAccountAddress, parsePublicKey } from "../../../src/internal/passkey"; +import { FUND_AMOUNT } from "../../unit/helper"; +import { getAptosClient } from "../helper"; +import { sha3_256 as sha3Hash } from "@noble/hashes/sha3"; +import { sha256 as sha2Hash } from "@noble/hashes/sha2"; +import { decodeClientDataJSON } from "@simplewebauthn/server/helpers"; +import { p256 } from "@noble/curves/p256"; +import { sha256 } from "@noble/hashes/sha256"; + +const PASSKEY_TEST_TIMEOUT = 12000; + +const testCredentialJSONObject = { + id: "ou6iPvirmyfwxymZ-TogFw", + rawId: "ou6iPvirmyfwxymZ-TogFw", + response: { + attestationObject: + "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViUSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NdAAAAALraVWanqkAfvZZFYZpVEg0AEKLuoj74q5sn8Mcpmfk6IBelAQIDJiABIVgg-Aw8wvwYzq8QlltKiXtEQSVa8uHJpJaJ1F9AAoL2Q6ciWCA7Xroa2iNudxIqgFG1IdNGTniiKCIk-hIn2ktswN6p9A", + clientDataJSON: + "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiZ3Jod2t5cVBydTZEamhsZ3hfWFF5NjZmZVNGdl9rZm9raVpsS1FGTGxsTSIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTE3MyIsImNyb3NzT3JpZ2luIjpmYWxzZX0", + transports: ["internal", "hybrid"], + publicKeyAlgorithm: -7, + publicKey: + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE-Aw8wvwYzq8QlltKiXtEQSVa8uHJpJaJ1F9AAoL2Q6c7Xroa2iNudxIqgFG1IdNGTniiKCIk-hIn2ktswN6p9A", + authenticatorData: + "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NdAAAAALraVWanqkAfvZZFYZpVEg0AEKLuoj74q5sn8Mcpmfk6IBelAQIDJiABIVgg-Aw8wvwYzq8QlltKiXtEQSVa8uHJpJaJ1F9AAoL2Q6ciWCA7Xroa2iNudxIqgFG1IdNGTniiKCIk-hIn2ktswN6p9A", + }, + type: "public-key", + clientExtensionResults: { + credProps: { + rk: true, + authenticatorDisplayName: "1Password", + }, + }, + authenticatorAttachment: "platform", +} as RegistrationResponseJSON; + +const testAuthenticationResponseObject = { + id: "ou6iPvirmyfwxymZ-TogFw", + rawId: "ou6iPvirmyfwxymZ-TogFw", + response: { + authenticatorData: "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MdAAAAAA", + clientDataJSON: + "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoib2U1MlRmWXNYYlNuOVNxamQtdUtka2dMOWZBQjdLc3VlbFUwTmwtWm54USIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTE3MyIsImNyb3NzT3JpZ2luIjpmYWxzZX0", + signature: "MEYCIQDO-9LxaDNBEBa4pyquUcyuhsegDWM_aR5-wpLIjQT4hwIhAI8yK8ZAxWtRfkDNFxkwZm4SC-yhHCLMjgtwcbdHzG3_", + userHandle: "tsSuOOp-4_KUAp9B7-M_EPFwl3giI4cdOzvFiUbDoMM", + }, + type: "public-key", + clientExtensionResults: {}, + authenticatorAttachment: "platform", +} as AuthenticationResponseJSON; + +function concatenateUint8Arrays(arr1: Uint8Array, arr2: Uint8Array) { + // Create a new Uint8Array with the combined length of arr1 and arr2 + const concatenated = new Uint8Array(arr1.length + arr2.length); + + // Copy the first array into the beginning of the new array + concatenated.set(arr1, 0); + + // Copy the second array into the new array, starting at the index after the end of the first array + concatenated.set(arr2, arr1.length); + + return concatenated; +} + +interface MockTestAuthenticationResponseObjectArgs { + transaction: AnyRawTransaction; + privateKey: Secp256r1PrivateKey; +} + +export interface GenerateVerificationDataArgs { + authenticatorData: Uint8Array; + clientDataJSON: Uint8Array; +} + +/** + * Construct verificationData, where verificationData is defined as + * verificationData = authenticator_data || sha256(clientDataJson) + */ +export function generateVerificationData({ authenticatorData, clientDataJSON }: GenerateVerificationDataArgs) { + // SHA2-256 digest of clientDataJSONBytes + const clientDataJsonDigest = sha2Hash(clientDataJSON); + + // Binary concatenation of authenticatorData and SHA2-256(clientDataJson) (ORDER MATTERS) + return new Uint8Array([...authenticatorData, ...clientDataJsonDigest]); +} + +/** + * This function simulates what a Platform Authenticator would do + * for a WebAuthn Assertion. The function includes the logic for both + * constructing the challenge and signing the verificationData. + * + * Given a transaction, this function will construct a clientDataJSON, where clientDataJson is defined as + * clientDataJson = { ...fields, challenge: SHA3-256(signing_message(transaction)) } + * + * Then it will construct verificationData, where verificationData is defined as + * verificationData = authenticator_data || sha256(clientDataJson) + * + * Then, given a privateKey, it will sign verificationData and return a signature + * + * Lastly it returns a mock AuthenticatorAssertionResponse response. Note the fields that matter + * for signature verification are the following: + * - signature + * - clientDataJSON + * - authenticatorData + * + * These are used to construct the `PartialAuthenticatorAssertionResponse` + * + * To learn more + * @see https://www.w3.org/TR/webauthn-3/#sctn-op-get-assertion + */ +const mockTestAuthenticationResponseObject = ({ + transaction, + privateKey, +}: MockTestAuthenticationResponseObjectArgs) => { + const signingMessage = generateSigningMessageForTransaction(transaction); + const challengeBytes = sha3Hash(signingMessage); + + const clientDataJSON: ClientDataJSON = { + ...decodeClientDataJSON(testAuthenticationResponseObject.response.clientDataJSON), + challenge: bufferToBase64URLString(challengeBytes), + }; + + const clientDataJSONBytes = clientDataToJsonBytes(clientDataJSON); + const clientDataJSONBase64Url = bufferToBase64URLString(clientDataJSONBytes); + + // AuthenticatorData bytes + const authenticatorData = new Uint8Array( + base64URLStringToBuffer(testAuthenticationResponseObject.response.authenticatorData), + ); + + const verificationData = generateVerificationData({ + authenticatorData, + clientDataJSON: clientDataJSONBytes, + }); + + // Signature over concat(authenticatorDataBytes || clientDataJson) where || is defined as concatenation + const assertionResponseRawSignature = privateKey.signArbitraryMessage(verificationData); + + // Authenticators return ASN.1 DER encoded signatures for Secp256r1, not compact + const assertionResponseDerSignature = p256.Signature.fromCompact( + assertionResponseRawSignature.toUint8Array(), + ).toDERRawBytes(); + const assertionResponseSignatureBase64Url = bufferToBase64URLString(assertionResponseDerSignature); + + return { + ...testAuthenticationResponseObject, + response: { + ...testAuthenticationResponseObject.response, + signature: assertionResponseSignatureBase64Url, + clientDataJSON: clientDataJSONBase64Url, + }, + } as AuthenticationResponseJSON; +}; + +const { aptos } = getAptosClient(); + +describe("passkey api", () => { + describe("passkey account", () => { + test("get passkey account pubkey and address", async () => { + const pubKey = parsePublicKey(testCredentialJSONObject); + const address = await getPasskeyAccountAddress({ publicKey: pubKey.toString() }); + expect(pubKey.toString()).toBe( + "0x04f80c3cc2fc18ceaf10965b4a897b4441255af2e1c9a49689d45f400282f643a73b5eba1ada236e77122a8051b521d3464e78a2282224fa1227da4b6cc0dea9f4", + ); + expect(address.toString()).toBe("0x5f48dc0b134ef412f1e740deb9795a099a416c4a56d145ff0786234517d525e8"); + }); + }); + + describe("passkey sign", () => { + test( + "sign with passkey", + async () => { + const spy = jest.spyOn(browser, "startAuthentication"); + + // Note that this private key and corresponding public key will differ + // from the key present in testCredentialJSONObject + const privateKey = Secp256r1PrivateKey.generate(); + const publicKey = privateKey.publicKey(); + const address = await getPasskeyAccountAddress({ publicKey: publicKey.toUint8Array() }); + + await aptos.fundAccount({ accountAddress: address, amount: 10 * FUND_AMOUNT }); + const txn = await aptos.transferCoinTransaction({ + sender: address, + recipient: AccountAddress.fromString("0x1"), + amount: FUND_AMOUNT, + }); + + const mockedResponse = mockTestAuthenticationResponseObject({ transaction: txn, privateKey }); + spy.mockReturnValue(Promise.resolve(mockedResponse)); + + const clientDataBytes = new Uint8Array(base64URLStringToBuffer(mockedResponse.response.clientDataJSON)); + const signature = p256.Signature.fromDER( + new Uint8Array(base64URLStringToBuffer(mockedResponse.response.signature)), + ).toCompactRawBytes(); + const authenticatorData = new Uint8Array(base64URLStringToBuffer(mockedResponse.response.authenticatorData)); + + // Test Passkey Public Key Recovery Works as Expected + const recoveredPublicKey = await Secp256r1PublicKey.recoverPasskeyPublicKey(authenticatorData); + expect(recoveredPublicKey?.toString()).toEqual(publicKey.toString()); + + const p256PublicKey = p256.getPublicKey(privateKey.toUint8Array()); + const verificationData = generateVerificationData({ authenticatorData, clientDataJSON: clientDataBytes }); + + // Sanity check to make sure signature and verificationData were created correctly + const verification = p256.verify(signature, sha256(verificationData), p256PublicKey); + expect(verification).toBeTruthy(); + + const pendingTxn = await aptos.signAndSubmitWithPasskey({ + credentialId: testCredentialJSONObject.id, + transaction: txn, + publicKey, + rpID: "localhost", + options: {}, + }); + + await aptos.waitForTransaction({ transactionHash: pendingTxn.hash }); + spy.mockRestore(); + }, + PASSKEY_TEST_TIMEOUT, + ); + }); +}); diff --git a/tests/e2e/transaction/transactionBuilder.test.ts b/tests/e2e/transaction/transactionBuilder.test.ts index 7060d58b3..aeb5f0f67 100644 --- a/tests/e2e/transaction/transactionBuilder.test.ts +++ b/tests/e2e/transaction/transactionBuilder.test.ts @@ -3,29 +3,29 @@ import { Account, - Deserializer, - U64, AccountAddress, - EntryFunctionABI, - parseTypeTag, AccountAuthenticator, AccountAuthenticatorEd25519, - FeePayerRawTransaction, - MultiAgentRawTransaction, - RawTransaction, - TransactionPayloadEntryFunction, - TransactionPayloadMultiSig, - TransactionPayloadScript, buildTransaction, deriveTransactionType, + Deserializer, + EntryFunctionABI, + FeePayerRawTransaction, generateRawTransaction, generateSignedTransaction, generateSignedTransactionForSimulation, generateTransactionPayload, generateTransactionPayloadWithABI, - SignedTransaction, generateUserTransactionHash, KeylessPublicKey, + MultiAgentRawTransaction, + parseTypeTag, + RawTransaction, + SignedTransaction, + TransactionPayloadEntryFunction, + TransactionPayloadMultiSig, + TransactionPayloadScript, + U64, } from "../../../src"; import { FUND_AMOUNT, longTestTimeout } from "../../unit/helper"; import { EPHEMERAL_KEY_PAIR } from "../api/keyless.test"; diff --git a/tests/unit/account.test.ts b/tests/unit/account.test.ts index 766bb5610..fe98d83ff 100644 --- a/tests/unit/account.test.ts +++ b/tests/unit/account.test.ts @@ -4,26 +4,30 @@ import { Account, AccountAddress, + AnyPublicKey, + SigningScheme as AuthenticationKeyScheme, + Ed25519Account, Ed25519PrivateKey, Ed25519PublicKey, + MultiKey, + MultiKeyAccount, Secp256k1PrivateKey, Secp256k1PublicKey, - SigningScheme as AuthenticationKeyScheme, + Secp256r1PrivateKey, + Secp256r1PublicKey, SigningSchemeInput, - AnyPublicKey, - Ed25519Account, SingleKeyAccount, - MultiKey, - MultiKeyAccount, } from "../../src"; import { ed25519, + Ed25519WalletTestObject, secp256k1TestObject, secp256k1WalletTestObject, + secp256r1TestObject, + secp256r1WalletTestObject, singleSignerED25519, wallet, - Ed25519WalletTestObject, } from "./helper"; describe("Account", () => { @@ -49,6 +53,13 @@ describe("Account", () => { expect(secpAccount.publicKey).toBeInstanceOf(AnyPublicKey); expect(secpAccount.signingScheme).toEqual(AuthenticationKeyScheme.SingleKey); }); + it("should create an instance of Account when Secp256r1 scheme is specified", () => { + // Account with SingleKey Secp256r1 scheme + const secpAccount = Account.generate({ scheme: SigningSchemeInput.Secp256r1Ecdsa }); + expect(secpAccount).toBeInstanceOf(SingleKeyAccount); + expect(secpAccount.publicKey).toBeInstanceOf(AnyPublicKey); + expect(secpAccount.signingScheme).toEqual(AuthenticationKeyScheme.SingleKey); + }); }); describe("fromPrivateKeyAndAddress", () => { it("derives the correct account from a legacy ed25519 private key", () => { @@ -91,6 +102,20 @@ describe("Account", () => { expect(newAccount.publicKey.publicKey.toString()).toEqual(publicKey); expect(newAccount.accountAddress.toString()).toEqual(address); }); + + it("derives the correct account from a single signer secp256r1 private key", () => { + const { privateKey: privateKeyBytes, publicKey, address } = secp256r1WalletTestObject; + const privateKey = new Secp256r1PrivateKey(privateKeyBytes); + const accountAddress = AccountAddress.from(address); + const newAccount = Account.fromPrivateKey({ privateKey, address: accountAddress }); + expect(newAccount).toBeInstanceOf(SingleKeyAccount); + expect(newAccount.publicKey).toBeInstanceOf(AnyPublicKey); + expect(newAccount.publicKey.publicKey).toBeInstanceOf(Secp256r1PublicKey); + expect(newAccount.privateKey).toBeInstanceOf(Secp256r1PrivateKey); + expect(newAccount.privateKey.toString()).toEqual(privateKey.toString()); + expect(newAccount.publicKey.publicKey.toString()).toEqual(publicKey); + expect(newAccount.accountAddress.toString()).toEqual(address); + }); }); describe("fromPrivateKey", () => { @@ -131,6 +156,19 @@ describe("Account", () => { expect(newAccount.publicKey.publicKey.toString()).toEqual(new Secp256k1PublicKey(publicKey).toString()); expect(newAccount.accountAddress.toString()).toEqual(address); }); + + it("derives the correct account from a single signer secp256r1 private key", () => { + const { privateKey: privateKeyBytes, publicKey, address } = secp256r1TestObject; + const privateKey = new Secp256r1PrivateKey(privateKeyBytes); + const newAccount = Account.fromPrivateKey({ privateKey }); + expect(newAccount).toBeInstanceOf(SingleKeyAccount); + expect(newAccount.publicKey).toBeInstanceOf(AnyPublicKey); + expect((newAccount.publicKey as AnyPublicKey).publicKey).toBeInstanceOf(Secp256r1PublicKey); + expect(newAccount.privateKey).toBeInstanceOf(Secp256r1PrivateKey); + expect(newAccount.privateKey.toString()).toEqual(privateKey.toString()); + expect(newAccount.publicKey.publicKey.toString()).toEqual(new Secp256r1PublicKey(publicKey).toString()); + expect(newAccount.accountAddress.toString()).toEqual(address); + }); }); describe("fromDerivationPath", () => { it("should create a new account from bip44 path and mnemonics with legacy Ed25519", async () => { @@ -163,6 +201,16 @@ describe("Account", () => { }); expect(newAccount.accountAddress.toString()).toEqual(address); }); + + it("should create a new account from bip44 path and mnemonics with single signer secp256r1", () => { + const { mnemonic, address, path } = secp256r1WalletTestObject; + const newAccount = Account.fromDerivationPath({ + path, + mnemonic, + scheme: SigningSchemeInput.Secp256r1Ecdsa, + }); + expect(newAccount.accountAddress.toString()).toEqual(address); + }); }); describe("sign and verify", () => { @@ -181,6 +229,21 @@ describe("Account", () => { expect(secpAccount.verifySignature({ message: stringMessage, signature: signature2 })).toBeTruthy(); }); + it("signs a message with single signer Secp256r1 scheme and verifies successfully", () => { + const { privateKey: privateKeyBytes, address, signatureHex, messageEncoded, stringMessage } = secp256r1TestObject; + const privateKey = new Secp256r1PrivateKey(privateKeyBytes); + const accountAddress = AccountAddress.from(address); + const secpAccount = Account.fromPrivateKey({ privateKey, address: accountAddress }); + // verifies an encoded message + const signature1 = secpAccount.sign(messageEncoded); + expect(signature1.signature.toString()).toEqual(signatureHex); + expect(secpAccount.verifySignature({ message: messageEncoded, signature: signature1 })).toBeTruthy(); + // verifies a string message + const signature2 = secpAccount.sign(stringMessage); + expect(signature2.signature.toString()).toEqual(signatureHex); + expect(secpAccount.verifySignature({ message: stringMessage, signature: signature2 })).toBeTruthy(); + }); + it("signs a message with single signer ed25519 scheme and verifies successfully", () => { const { privateKey: privateKeyBytes, address, signatureHex, messageEncoded } = singleSignerED25519; const privateKey = new Ed25519PrivateKey(privateKeyBytes); diff --git a/tests/unit/helper.ts b/tests/unit/helper.ts index 1eb0b4f10..447c1f1af 100644 --- a/tests/unit/helper.ts +++ b/tests/unit/helper.ts @@ -32,6 +32,15 @@ export const secp256k1WalletTestObject = { "0x04913871f1d6cb7b867e8671cf63cf7b4c43819539fa0074ff933434bf20bab825b335535251f720fff72fd8b567e414af84aacf2f26ec804562081f2e0b0c9478", }; +export const secp256r1WalletTestObject = { + address: "0x071ce203b24472a3f1fffbc864671aa22694e1bb97a515392c3dcbc88b8142ae", + mnemonic: "shoot island position soft burden budget tooth cruel issue economy destroy above", + path: "m/44'/637'/0'/0/0", + privateKey: "0x1eec55afc2f72c4ab7b46c84d761739035ac420a2b6b22cef3411adaf91ce1f7", + publicKey: + "0x04a321d7d3d68e87055b021799dd5916ccf102f81e714ed0bc98d8f001fa40e519f75aebd1d397d6963d8d6f920c79f41506adf1e91b745fd2b845c71fe0d297de", +}; + export const zeroWallet = { address: "0x00fe71257b6b4caca517ef4c9979ada97aa2e2688e950654a40ff82e98f68163", mnemonic: "shoot island position soft burden budget tooth cruel issue economy destroy above", @@ -84,6 +93,18 @@ export const secp256k1TestObject = { "0xd0d634e843b61339473b028105930ace022980708b2855954b977da09df84a770c0b68c29c8ca1b5409a5085b0ec263be80e433c83fcf6debb82f3447e71edca", }; +export const secp256r1TestObject = { + privateKey: "0xd107155adf816a0a94c6db3c9489c13ad8a1eda7ada2e558ba3bfa47c020347e", + publicKey: + "0x04c81c1005cbaff7cdbabee843b1dcd2cabd21e0b728792c73cdaf92bb37bca7d52e9526bb15a32dd8f542bb62b050532884366369f7acfe7d10d8c3840778de8c", + address: "0xbf4cbeb52e99e75bff8908b2c412ae453a2bbaee808f152674193b7866cd1645", + authKey: "0xbf4cbeb52e99e75bff8908b2c412ae453a2bbaee808f152674193b7866cd1645", + messageEncoded: "68656c6c6f20776f726c64", + stringMessage: "hello world", + signatureHex: + "0x67a8c6539315eea3953c04165d2448f2de9bbb800bf5672af8098b73026292966ea226dfe4591b89da58999ef5e7f659a7d5bbee8aedbabe550e3b7034ddc51b", +}; + export const singleSignerED25519 = { publicKey: "0xe425451a5dc888ac871976c3c724dec6118910e7d11d344b4b07a22cd94e8c2e", privateKey: "0xf508cbef4e0fe463204aab724a90791c9a9dbe60a53b4978bbddbc712b55f2fd", diff --git a/tests/unit/secp256r1.test.ts b/tests/unit/secp256r1.test.ts new file mode 100644 index 000000000..d446cbec3 --- /dev/null +++ b/tests/unit/secp256r1.test.ts @@ -0,0 +1,237 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +import { p256 } from "@noble/curves/p256"; +import { sha256 } from "@noble/hashes/sha256"; +import { Deserializer, Hex, Secp256r1PrivateKey, Secp256r1PublicKey, Secp256r1Signature, Serializer } from "../../src"; +import { secp256k1TestObject, secp256r1TestObject, secp256r1WalletTestObject } from "./helper"; + +/* eslint-disable max-len */ +describe("Secp256r1PublicKey", () => { + it("should create the instance correctly without error", () => { + // Create from string + const publicKey = new Secp256r1PublicKey(secp256r1TestObject.publicKey); + expect(publicKey).toBeInstanceOf(Secp256r1PublicKey); + expect(publicKey.toString()).toEqual(secp256r1TestObject.publicKey); + + // // Create from Uint8Array + const hexUint8Array = p256.getPublicKey(p256.utils.randomPrivateKey(), false); + const publicKey2 = new Secp256r1PublicKey(hexUint8Array); + expect(publicKey2).toBeInstanceOf(Secp256r1PublicKey); + expect(publicKey2.toUint8Array()).toEqual(hexUint8Array); + }); + + it("should throw an error with invalid hex input length", () => { + const invalidHexInput = "0123456789abcdef"; // Invalid length + expect(() => new Secp256r1PublicKey(invalidHexInput)).toThrowError( + `PublicKey length should be ${Secp256r1PublicKey.LENGTH}`, + ); + }); + + it("should sign_arbitrary_bytes and verify the signature correctly", () => { + const privateKey = new Secp256r1PrivateKey(secp256r1TestObject.privateKey); + const publicKey = privateKey.publicKey(); + + const message = Hex.fromHexString(secp256r1TestObject.messageEncoded); + const signature = privateKey.signArbitraryMessage(message.toUint8Array()); + expect(signature.toString()).toEqual(secp256r1TestObject.signatureHex); + + const verify = p256.verify(signature.toUint8Array(), sha256(message.toUint8Array()), publicKey.toUint8Array()); + expect(verify).toBeTruthy(); + }); + + it("should verify the signature correctly", () => { + const pubKey = new Secp256r1PublicKey(secp256r1TestObject.publicKey); + const signature = new Secp256r1Signature(secp256r1TestObject.signatureHex); + + // Convert message to hex + const hexMsg = Hex.fromHexString(secp256r1TestObject.messageEncoded); + + // Verify with correct signed message + expect(pubKey.verifySignature({ message: hexMsg.toUint8Array(), signature })).toBe(true); + + // Verify with incorrect signed message + const incorrectSignedMessage = + "0xc5de9e40ac00b371cd83b1c197fa5b665b7449b33cd3cdd305bb78222e06a671a49625ab9aea8a039d4bb70e275768084d62b094bc1b31964f2357b7c1af7e0a"; + const invalidSignature = new Secp256r1Signature(incorrectSignedMessage); + expect( + pubKey.verifySignature({ + message: secp256r1TestObject.messageEncoded, + signature: invalidSignature, + }), + ).toBe(false); + }); + + it("should serialize correctly", () => { + const publicKey = new Secp256r1PublicKey(secp256r1TestObject.publicKey); + const serializer = new Serializer(); + publicKey.serialize(serializer); + + const serialized = Hex.fromHexInput(serializer.toUint8Array()).toString(); + const expected = + "0x4104c81c1005cbaff7cdbabee843b1dcd2cabd21e0b728792c73cdaf92bb37bca7d52e9526bb15a32dd8f542bb62b050532884366369f7acfe7d10d8c3840778de8c"; + expect(serialized).toEqual(expected); + }); + + it("should deserialize correctly", () => { + const serializedPublicKeyStr = + "0x4104c81c1005cbaff7cdbabee843b1dcd2cabd21e0b728792c73cdaf92bb37bca7d52e9526bb15a32dd8f542bb62b050532884366369f7acfe7d10d8c3840778de8c"; + const serializedPublicKey = Hex.fromHexString(serializedPublicKeyStr).toUint8Array(); + const deserializer = new Deserializer(serializedPublicKey); + const publicKey = Secp256r1PublicKey.deserialize(deserializer); + + expect(publicKey.toString()).toEqual(secp256r1TestObject.publicKey); + }); + + it("ecdsa public key recovery", async () => { + // Create from string + const message = Hex.fromHexInput(secp256r1TestObject.messageEncoded); + const signature = new Secp256r1Signature(secp256r1TestObject.signatureHex); + expect(signature).toBeInstanceOf(Secp256r1Signature); + + // Test public key recovery. Should return two valid public keys, one of which contains the expected public key + let publicKeys: Secp256r1PublicKey[] = await Secp256r1PublicKey.recoverPublicKey({ + message: message.toUint8Array(), + signature: signature.toUint8Array(), + }); + let publicKeysHex: string[] = publicKeys.map((key) => key.toString()); + expect(publicKeysHex).toContain(secp256r1TestObject.publicKey); + + // Test public key recovery with two signatures. Should return one valid public key + // UTF-8 -> Hex of "hello blockchain" + const message2 = Hex.fromHexString("68656c6c6f20626c6f636b636861696e"); + const privateKey = new Secp256r1PrivateKey(secp256r1TestObject.privateKey); + const signature2 = privateKey.signArbitraryMessage(message2.toUint8Array()); + publicKeys = await Secp256r1PublicKey.recoverPublicKeyFromTwoSignatures([ + { + message: message.toUint8Array(), + signature: signature.toUint8Array(), + }, + { + message: message2.toUint8Array(), + signature: signature2.toUint8Array(), + } + ]) + publicKeysHex = publicKeys.map((key) => key.toString()); + expect(publicKeys.length).toEqual(1); + + // Asserted there is only one public key in array from the expect array.length === 1 invariant above + const publicKeyHex = publicKeysHex[0]; + expect(publicKeyHex).toEqual(secp256r1TestObject.publicKey); + }); +}); + +describe("Secp256r1PrivateKey", () => { + it("should create the instance correctly without error", () => { + // Create from string + const privateKey = new Secp256r1PrivateKey(secp256r1TestObject.privateKey); + expect(privateKey).toBeInstanceOf(Secp256r1PrivateKey); + expect(privateKey.toString()).toEqual(secp256r1TestObject.privateKey); + + // Create from Uint8Array + const hexUint8Array = Hex.fromHexString(secp256r1TestObject.privateKey).toUint8Array(); + const privateKey2 = new Secp256r1PrivateKey(hexUint8Array); + expect(privateKey2).toBeInstanceOf(Secp256r1PrivateKey); + expect(privateKey2.toString()).toEqual(Hex.fromHexInput(hexUint8Array).toString()); + }); + + it("should throw an error with invalid hex input length", () => { + const invalidHexInput = "0123456789abcdef"; // Invalid length + expect(() => new Secp256r1PrivateKey(invalidHexInput)).toThrowError( + `PrivateKey length should be ${Secp256r1PrivateKey.LENGTH}`, + ); + }); + + it("should sign the message correctly", () => { + const privateKey = new Secp256r1PrivateKey(secp256r1TestObject.privateKey); + const signedMessage = privateKey.sign(secp256r1TestObject.messageEncoded); + expect(signedMessage.toString()).toEqual(secp256r1TestObject.signatureHex); + }); + + it("should serialize correctly", () => { + const privateKey = new Secp256r1PrivateKey(secp256r1TestObject.privateKey); + const serializer = new Serializer(); + privateKey.serialize(serializer); + + const received = Hex.fromHexInput(serializer.toUint8Array()).toString(); + const expected = "0x20d107155adf816a0a94c6db3c9489c13ad8a1eda7ada2e558ba3bfa47c020347e"; + expect(received).toEqual(expected); + }); + + it("should deserialize correctly", () => { + const serializedPrivateKeyStr = "0x20d107155adf816a0a94c6db3c9489c13ad8a1eda7ada2e558ba3bfa47c020347e"; + const serializedPrivateKey = Hex.fromHexString(serializedPrivateKeyStr).toUint8Array(); + const deserializer = new Deserializer(serializedPrivateKey); + const privateKey = Secp256r1PrivateKey.deserialize(deserializer); + + expect(privateKey.toString()).toEqual(secp256r1TestObject.privateKey); + }); + + it("should serialize and deserialize correctly", () => { + const privateKey = new Secp256r1PrivateKey(secp256r1TestObject.privateKey); + const serializer = new Serializer(); + privateKey.serialize(serializer); + + const deserializer = new Deserializer(serializer.toUint8Array()); + const deserializedPrivateKey = Secp256r1PrivateKey.deserialize(deserializer); + + expect(deserializedPrivateKey.toString()).toEqual(privateKey.toString()); + }); + + it("should prevent an invalid bip44 path ", () => { + const { mnemonic } = secp256r1WalletTestObject; + const path = "1234"; + expect(() => Secp256r1PrivateKey.fromDerivationPath(path, mnemonic)).toThrow("Invalid derivation path"); + }); + + it("should derive from path and mnemonic", () => { + const { mnemonic, path, privateKey } = secp256r1WalletTestObject; + const key = Secp256r1PrivateKey.fromDerivationPath(path, mnemonic); + expect(key).toBeInstanceOf(Secp256r1PrivateKey); + expect(key.toString()).toEqual(privateKey); + }); +}); + +describe("Secp256r1Signature", () => { + it("should create an instance correctly without error", () => { + // Create from string + const signatureStr = new Secp256r1Signature(secp256r1TestObject.signatureHex); + expect(signatureStr).toBeInstanceOf(Secp256r1Signature); + expect(signatureStr.toString()).toEqual(secp256r1TestObject.signatureHex); + + // Create from Uint8Array + const array = Array.from({ length: Secp256r1Signature.LENGTH }, () => Math.floor(Math.random() * 16)); + const signatureValue = new Uint8Array(array); + const signature = new Secp256r1Signature(signatureValue); + expect(signature).toBeInstanceOf(Secp256r1Signature); + expect(signature.toUint8Array()).toEqual(signatureValue); + }); + + it("should throw an error with invalid value length", () => { + const invalidSignatureValue = new Uint8Array(Secp256r1Signature.LENGTH - 1); // Invalid length + expect(() => new Secp256r1Signature(invalidSignatureValue)).toThrowError( + `Signature length should be ${Secp256r1Signature.LENGTH}`, + ); + }); + + it("should serialize correctly", () => { + const signature = new Secp256r1Signature(secp256r1TestObject.signatureHex); + const serializer = new Serializer(); + signature.serialize(serializer); + + const received = Hex.fromHexInput(serializer.toUint8Array()).toString(); + const expected = + "0x4067a8c6539315eea3953c04165d2448f2de9bbb800bf5672af8098b73026292966ea226dfe4591b89da58999ef5e7f659a7d5bbee8aedbabe550e3b7034ddc51b"; + expect(received).toEqual(expected); + }); + + it("should deserialize correctly", () => { + const serializedSignature = + "0x4067a8c6539315eea3953c04165d2448f2de9bbb800bf5672af8098b73026292966ea226dfe4591b89da58999ef5e7f659a7d5bbee8aedbabe550e3b7034ddc51b"; + const serializedSignatureUint8Array = Hex.fromHexString(serializedSignature).toUint8Array(); + const deserializer = new Deserializer(serializedSignatureUint8Array); + const signature = Secp256r1Signature.deserialize(deserializer); + + expect(signature.toString()).toEqual(secp256r1TestObject.signatureHex); + }); +});