diff --git a/.gitignore b/.gitignore index c6476abbbe..6d1dad34f2 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,6 @@ node_modules # Hardhat cache/solidity-files-cache.json +*.bak +plugin/go/scripts/__pycache__/ +node.log diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000000..974fa9294c --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,50 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts +node_modules/ +.next/ +out/ +.turbo/ +coverage/ +playwright-report/ +*.log +.env.local +.env*.local diff --git a/frontend/= b/frontend/= new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/AGENTS.md b/frontend/AGENTS.md new file mode 100644 index 0000000000..8bd0e39085 --- /dev/null +++ b/frontend/AGENTS.md @@ -0,0 +1,5 @@ + +# This is NOT the Next.js you know + +This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. + diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md new file mode 100644 index 0000000000..43c994c2d3 --- /dev/null +++ b/frontend/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000000..e215bc4ccf --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/frontend/eslint.config.mjs b/frontend/eslint.config.mjs new file mode 100644 index 0000000000..05e726d1b4 --- /dev/null +++ b/frontend/eslint.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), +]); + +export default eslintConfig; diff --git a/frontend/next.config.ts b/frontend/next.config.ts new file mode 100644 index 0000000000..b4fa67740f --- /dev/null +++ b/frontend/next.config.ts @@ -0,0 +1,22 @@ +import type { NextConfig } from "next"; + +// Backend destinations are configurable so the SAME build works locally +// (defaults to 127.0.0.1) and on Vercel (set these to your node's public +// URL or a tunnel). Server-side only (NOT NEXT_PUBLIC): the browser always +// calls the same-origin /canopy-rpc, /canopy-admin, /arbor-rpc paths and +// Next proxies them server-side, which also sidesteps CORS entirely. +const canopyRpcDest = process.env.CANOPY_RPC_DEST || "http://127.0.0.1:50002"; +const canopyAdminDest = process.env.CANOPY_ADMIN_DEST || "http://127.0.0.1:50003"; +const arborRpcDest = process.env.ARBOR_RPC_DEST || "http://127.0.0.1:50010"; + +const nextConfig: NextConfig = { + async rewrites() { + return [ + { source: "/canopy-rpc/:path*", destination: `${canopyRpcDest}/:path*` }, + { source: "/canopy-admin/:path*", destination: `${canopyAdminDest}/:path*` }, + { source: "/arbor-rpc/:path*", destination: `${arborRpcDest}/:path*` }, + ]; + }, +}; + +export default nextConfig; diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000000..592eac25d0 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,7491 @@ +{ + "name": "arbor-frontend", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "arbor-frontend", + "version": "0.1.0", + "dependencies": { + "@hookform/resolvers": "^5.4.0", + "@noble/curves": "^1.9.7", + "@tanstack/react-query": "^5.101.4", + "framer-motion": "^12.42.2", + "hash-wasm": "^4.12.0", + "long": "^5.3.2", + "lucide-react": "^1.26.0", + "next": "16.2.11", + "protobufjs": "^8.7.1", + "react": "19.2.4", + "react-dom": "19.2.4", + "react-hook-form": "^7.82.0", + "recharts": "^3.10.0", + "zod": "^4.4.3", + "zustand": "^5.0.14" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/long": "^4.0.2", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.2.11", + "tailwindcss": "^4", + "ts-proto": "^2.12.0", + "typescript": "^5" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bufbuild/protobuf": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.13.0.tgz", + "integrity": "sha512-acq7c49vxfm1ggJ95P70TX7ABDM0vxr1SYD3BB0o0jnBLB4OAqeHyKuN+cD3w80gXEDQ2zxHpR6CUeA+O/aU9g==", + "dev": true, + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", + "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.3.0", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", + "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@hookform/resolvers": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.4.0.tgz", + "integrity": "sha512-EIsqr/t/qbinPIhGjMdtvutIN1Kk4uwbROE9/UQ93CAVGR7GkA7Y92+fX80OzXi/OB67jVFYwKGO1WzkxmkFZw==", + "license": "MIT", + "dependencies": { + "@standard-schema/utils": "^0.3.0" + }, + "peerDependencies": { + "react-hook-form": "^7.55.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@next/env": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.11.tgz", + "integrity": "sha512-0do5A3BJ2gxWr0ZCMcD6BhW+e595jyxdTl3rXTS6lOtD8ektMiW6CO+EPwt1Eca1DBnm90r/7GdiKWBKxH++DA==", + "license": "MIT" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.2.11.tgz", + "integrity": "sha512-vMEf/aXOpzFFdtIvFYOnIDPKb0xBbrXONsz83CcKdRrekfxNdL8PNkq5qHqAHSXVlIifnX68LOMaxr3z5PkeLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "3.3.1" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.11.tgz", + "integrity": "sha512-wryL4pjKmDwGv2ox6+GZDFxvmtSRLqApBR8kL1j4+vhB7Z5vJC/zAnXpiR9Xkfzl0AS8WLMnsuGV/UKI67/rrw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.11.tgz", + "integrity": "sha512-aZl2j4f/fLyjQvOhv0Oe9UaMAQHolYpKhctsoYzplSumKJKPUmgjcf6545aBtysLTcu994TREd0+pSgNE4ohmg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.11.tgz", + "integrity": "sha512-5jEriyEnH/LWFy27L2ZG0XaLlyEJIjhsImEsiS9P563PKEVp2BVups/xfOucIrsvVntp11oNcZwjHvaDPYVB5g==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.11.tgz", + "integrity": "sha512-eIjcpx2fnnFSSkZDbTxy74KnokUXDjfoLClpWelfgHLf621aTqswhwXQ7GkD5K5rplrS6LZ/Bj+mVuvzluBOEg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.11.tgz", + "integrity": "sha512-8WgzpaWMs46qJT9kiV47cje86L0x/Mu9t8/Gwj+pnbgW3rETVfCnaScPjlYUwNScpOozdcIMHWmAvuZJUonR2w==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.11.tgz", + "integrity": "sha512-I3UgPds7G4ZYnTb/H+5GBGuUT2DhAk6j0mL6A4s63RjFs74wB2hOWP0vaxsK+3NJraExt3eYEPQ/UtT0x/64Nw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.11.tgz", + "integrity": "sha512-n89CjtcThnjrwgJMAiI5xbqwLY51zvwC9tSlArmVndAJLYVl9T9UAdlkXTmZvE++idoXe8KdglQlhNRdUp1c6g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.11.tgz", + "integrity": "sha512-md8CLNggS1Dx9pUgApzps5uAf+N8GN9xywzmNx9vHAWo94HtBwCCqkSnhIrdfQe83Dhz8Lfo/20Nb1Zxal092w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@reduxjs/toolkit": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.12.0.tgz", + "integrity": "sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^11.0.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", + "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.24.1", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.3" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz", + "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-x64": "4.3.3", + "@tailwindcss/oxide-freebsd-x64": "4.3.3", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-x64-musl": "4.3.3", + "@tailwindcss/oxide-wasm32-wasi": "4.3.3", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz", + "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz", + "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz", + "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz", + "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz", + "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz", + "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz", + "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz", + "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz", + "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz", + "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.11.1", + "@emnapi/runtime": "^1.11.1", + "@emnapi/wasi-threads": "^1.2.2", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", + "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", + "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.3.tgz", + "integrity": "sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.3.3", + "@tailwindcss/oxide": "4.3.3", + "postcss": "^8.5.16", + "tailwindcss": "4.3.3" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.101.4", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.101.4.tgz", + "integrity": "sha512-gNwcvOJcRbLWPOLG/2OBm+zM+Yv+MKsXKEOWC57USuZDEsI71hEErQsiEGx5wX9rzWWkfwM0fVSPoiIFSsxfiw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.101.4", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.101.4.tgz", + "integrity": "sha512-yRg2pfOCxIs4ZJW3XYYHU/WgtD04FHSnfHlpRT7h7pR77hwkdRG4wxbKe4aq6P0RvXUTBSQpQeadS1SUYUe+KA==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.101.4" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.65.0.tgz", + "integrity": "sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.65.0", + "@typescript-eslint/type-utils": "8.65.0", + "@typescript-eslint/utils": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.65.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.65.0.tgz", + "integrity": "sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.65.0", + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/typescript-estree": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.65.0.tgz", + "integrity": "sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.65.0", + "@typescript-eslint/types": "^8.65.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.65.0.tgz", + "integrity": "sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.65.0.tgz", + "integrity": "sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.65.0.tgz", + "integrity": "sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/typescript-estree": "8.65.0", + "@typescript-eslint/utils": "8.65.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.65.0.tgz", + "integrity": "sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.65.0.tgz", + "integrity": "sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.65.0", + "@typescript-eslint/tsconfig-utils": "8.65.0", + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", + "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.65.0.tgz", + "integrity": "sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.65.0", + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/typescript-estree": "8.65.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.65.0.tgz", + "integrity": "sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.65.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", + "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz", + "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", + "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz", + "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz", + "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz", + "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz", + "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz", + "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz", + "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz", + "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz", + "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz", + "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz", + "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz", + "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz", + "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz", + "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz", + "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-openharmony-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz", + "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz", + "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", + "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz", + "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz", + "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.12.1.tgz", + "integrity": "sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.1.tgz", + "integrity": "sha512-HYXq73DDpCtNzOmrFsm9eSwCvWCql0RzqjpDzXN9EadiLJ4DNat0nsZ/Bzmy+Ud12mb4/zKDY0cQ805ZzN+i0A==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", + "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.44", + "caniuse-lite": "^1.0.30001806", + "electron-to-chromium": "^1.5.393", + "node-releases": "^2.0.51", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001806", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", + "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/case-anything": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.13.tgz", + "integrity": "sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dprint-node": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/dprint-node/-/dprint-node-1.0.8.tgz", + "integrity": "sha512-iVKnUtYfGrYcW1ZAlfR/F59cUVL8QIhWoBJoSjkkdua/dkWIgjZfiLMeTjiB06X0ZLkQ0M2C1VbUj/CxkIf1zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^1.0.3" + } + }, + "node_modules/dprint-node/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.395", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.395.tgz", + "integrity": "sha512-7zt9Aw+SrmxLWLN0zhaTWZQiCdryLVrYTq5R7iZakLvi2UQPYMMsROYV/2qVCzMeCiSXHwKOU+sZ4zOVVlrtKA==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.24.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.3.tgz", + "integrity": "sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract-get": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-abstract-get/-/es-abstract-get-1.0.0.tgz", + "integrity": "sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.2", + "is-callable": "^1.2.7", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.4.0.tgz", + "integrity": "sha512-c/A0P0oxkACDc+cKWw8evLXK83oBKgn0qPOqCYT4x9uolpCIJAcYvJC9QYKNDRPsTeGyCrQ326jrvgZWdCdK5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.4.tgz", + "integrity": "sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-abstract-get": "^1.0.0", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "is-callable": "^1.2.7", + "is-date-object": "^1.1.0", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-toolkit": { + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.49.0.tgz", + "integrity": "sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", + "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.6", + "@eslint/js": "9.39.5", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-next": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.2.11.tgz", + "integrity": "sha512-FIpbK/dUyxUExchDB7eBg3k+VU8R2iR/Cx9/kqTBUTFv2bOIR9aRrpno4rvAQ9VhiPQAyFKNA2NlZwouGWtclA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/eslint-plugin-next": "16.2.11", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-react": "^7.37.0", + "eslint-plugin-react-hooks": "^7.0.0", + "globals": "16.4.0", + "typescript-eslint": "^8.46.0" + }, + "peerDependencies": { + "eslint": ">=9.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-config-next/node_modules/globals": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", + "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", + "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.14.0.tgz", + "integrity": "sha512-W2WCRZ9Dqntd+2u8jJcVMV2PKulc6RdLgUUoh/yQr3uB6lo/ZOeGx11sv60/8S4QFFKNslAlWhr9u0Ef7ZW6Ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.3.tgz", + "integrity": "sha512-/zipXxyO6rGvuNGDiULY9MvEGSkb2gaG4GGH4ygMi0ZZzyMHdUZBmntJmx5x1G2VuPytCwGN4xsJP6cw+sK+vQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/framer-motion": { + "version": "12.42.2", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.42.2.tgz", + "integrity": "sha512-5XY9luDiu0oHfHBjpDthFMh0ES+122w6p/papSJBweMkO8Sn+PW2QaEgRblQBpWFnuvZS5qvarpt/hO2pjGmnw==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.42.2", + "motion-utils": "^12.39.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.2.0.tgz", + "integrity": "sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2", + "hasown": "^2.0.4", + "is-callable": "^1.2.7", + "is-document.all": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-wasm": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/hash-wasm/-/hash-wasm-4.12.0.tgz", + "integrity": "sha512-+/2B2rYLb48I/evdOIhP+K/DD2ca2fgBjp6O+GBEnCDk2e4rpeXIK8GvIyRPjTezgmWn9gmKwkQjjx6BtqDHVQ==", + "license": "MIT" + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "11.1.15", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.15.tgz", + "integrity": "sha512-VrNANlmnWQnh5COXIIOQXM9oOJw7naGKlBT74ZOOR6lpVXc3gFEu9FJLDFcpCJ2j+NWr8TIwtWD//T6ZX6TKiQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-bun-module/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-document.all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-document.all/-/is-document.all-1.0.0.tgz", + "integrity": "sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.26.0.tgz", + "integrity": "sha512-raglYVR2+VkMfJL158krjVmE+rV5ST2lzA/KQm1FRSjMHT4MnWaegHxoVEpmc2So3nOEhp9oGejJwAPX8MoAjg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/motion-dom": { + "version": "12.42.2", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.42.2.tgz", + "integrity": "sha512-5gIMWLp/PycBtJRJWRgjxke5n8dlvkSn2DrYW+tr3XcqAZY1xZh6BJyooJXCM8wdfM7wfMjkBJNLge1CKPUIRA==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.39.0" + } + }, + "node_modules/motion-utils": { + "version": "12.39.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz", + "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/next/-/next-16.2.11.tgz", + "integrity": "sha512-B339zaqbyK8cmxhoAvLrcwoabwCP1wz21zSzfqxqXAemTu2BXnH7tQnfcglKv1vnMUIDBc+Hth7XODQriTZiRQ==", + "license": "MIT", + "dependencies": { + "@next/env": "16.2.11", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.9.19", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=20.9.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "16.2.11", + "@next/swc-darwin-x64": "16.2.11", + "@next/swc-linux-arm64-gnu": "16.2.11", + "@next/swc-linux-arm64-musl": "16.2.11", + "@next/swc-linux-x64-gnu": "16.2.11", + "@next/swc-linux-x64-musl": "16.2.11", + "@next/swc-win32-arm64-msvc": "16.2.11", + "@next/swc-win32-x64-msvc": "16.2.11", + "sharp": "^0.34.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/node-exports-info": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.2.tgz", + "integrity": "sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-releases": { + "version": "2.0.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", + "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.2.tgz", + "integrity": "sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.22", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.22.tgz", + "integrity": "sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/protobufjs": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.7.1.tgz", + "integrity": "sha512-agdGHrXNTv0IrYscJPDou/PlEJk1c/hBZ9o/B5NH2i/nSPtPqacNxzgwf1CebXxFMjMrZH5sqv9uQuw96aGt/A==", + "license": "BSD-3-Clause", + "dependencies": { + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/react-hook-form": { + "version": "7.82.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.82.0.tgz", + "integrity": "sha512-Zw/uFZ2dO+02GHlBn7JFGn8kZJ7LdM33B/0BXOovzFay+CMhf94JMw5BVu+F1tVkUKjNvBuaE3fz5BJhga10Tg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-redux": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.3.0.tgz", + "integrity": "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/recharts": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.10.0.tgz", + "integrity": "sha512-wulMvfncpIlmu2uFtRU/mE5/+NiVtASXkw2KdwJTdHs3WsASX0WxZlX+rpKgyn5BDbIhkPtCpUKkB9XNK5KE0w==", + "license": "MIT", + "workspaces": [ + "www" + ], + "dependencies": { + "@reduxjs/toolkit": "^1.9.0 || 2.x.x", + "clsx": "^2.1.1", + "decimal.js-light": "^2.5.1", + "es-toolkit": "^1.39.3", + "eventemitter3": "^5.0.1", + "immer": "^11.1.8", + "react-redux": "8.x.x || 9.x.x", + "reselect": "5.2.0", + "tiny-invariant": "^1.3.3", + "use-sync-external-store": "^1.2.2", + "victory-vendor": "^37.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reselect": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.2.0.tgz", + "integrity": "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "2.0.0-next.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", + "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.2", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/sharp/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stable-hash": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz", + "integrity": "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-object-atoms": "^1.1.2", + "has-property-descriptors": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz", + "integrity": "sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", + "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-poet": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ts-poet/-/ts-poet-6.12.0.tgz", + "integrity": "sha512-xo+iRNMWqyvXpFTaOAvLPA5QAWO6TZrSUs5s4Odaya3epqofBu/fMLHEWl8jPmjhA0s9sgj9sNvF1BmaQlmQkA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dprint-node": "^1.0.8" + } + }, + "node_modules/ts-proto": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-2.12.0.tgz", + "integrity": "sha512-ezMxg57ZiK/ZTW14U7y38+qyWHJr8cn8ELKuppANER666YnUteuNFO/mM1qI+9/wAHoTAfRadnIwtVdp1xw0jQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@bufbuild/protobuf": "^2.10.2", + "case-anything": "^2.1.13", + "ts-poet": "^6.12.0", + "ts-proto-descriptors": "2.1.0" + }, + "bin": { + "protoc-gen-ts_proto": "protoc-gen-ts_proto" + } + }, + "node_modules/ts-proto-descriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-2.1.0.tgz", + "integrity": "sha512-S5EZYEQ6L9KLFfjSRpZWDIXDV/W7tAj8uW7pLsihIxyr62EAVSiKuVPwE8iWnr849Bqa53enex1jhDUcpgquzA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@bufbuild/protobuf": "^2.0.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "possible-typed-array-names": "^1.1.0", + "reflect.getprototypeof": "^1.0.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.65.0.tgz", + "integrity": "sha512-/ggrHAwyjENDusvyxbuqxAC2dTnZg/Z8F+fgQtYIz+L6n/9HfSlEZcFGV/NsMNa6CkGk0xUjUAFwC0vHOflvIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.65.0", + "@typescript-eslint/parser": "8.65.0", + "@typescript-eslint/typescript-estree": "8.65.0", + "@typescript-eslint/utils": "8.65.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unrs-resolver": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", + "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.4" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.12.2", + "@unrs/resolver-binding-android-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-x64": "1.12.2", + "@unrs/resolver-binding-freebsd-x64": "1.12.2", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", + "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", + "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-musl": "1.12.2", + "@unrs/resolver-binding-openharmony-arm64": "1.12.2", + "@unrs/resolver-binding-wasm32-wasi": "1.12.2", + "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", + "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", + "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/victory-vendor": { + "version": "37.3.6", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", + "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz", + "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + }, + "node_modules/zustand": { + "version": "5.0.14", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.14.tgz", + "integrity": "sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000000..13f3d86b7c --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,40 @@ +{ + "name": "arbor-frontend", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --webpack", + "build": "next build --webpack", + "start": "next start", + "lint": "eslint" + }, + "dependencies": { + "@hookform/resolvers": "^5.4.0", + "@noble/curves": "^1.9.7", + "@tanstack/react-query": "^5.101.4", + "framer-motion": "^12.42.2", + "hash-wasm": "^4.12.0", + "long": "^5.3.2", + "lucide-react": "^1.26.0", + "next": "16.2.11", + "protobufjs": "^8.7.1", + "react": "19.2.4", + "react-dom": "19.2.4", + "react-hook-form": "^7.82.0", + "recharts": "^3.10.0", + "zod": "^4.4.3", + "zustand": "^5.0.14" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/long": "^4.0.2", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.2.11", + "tailwindcss": "^4", + "ts-proto": "^2.12.0", + "typescript": "^5" + } +} diff --git a/frontend/postcss.config.mjs.disabled b/frontend/postcss.config.mjs.disabled new file mode 100644 index 0000000000..61e36849cf --- /dev/null +++ b/frontend/postcss.config.mjs.disabled @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/frontend/proto/account.proto b/frontend/proto/account.proto new file mode 100644 index 0000000000..fcec4d6669 --- /dev/null +++ b/frontend/proto/account.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; +package types; +option go_package = "github.com/ARBOR-L/ARBOR/plugin/go/contract"; + +// An account is a structure that holds funds and can send or receive transactions using a crypto key pair +// Each account has a unique address and a balance, think a bank account - but managed by the blockchain +// instead of a bank +message Account { + // address: the short version of a public key + bytes address = 1; + // amount: the balance of funds the account has + uint64 amount = 2; + // NOTE: CAN EXTEND FUNCTIONALITY BY ADDING ADDITIONAL FIELDS +} + +// A pool is like an account without an owner, holding funds that are managed directly by the blockchain protocol +// It's very similar to an account but instead of an address it has a unique ID and operates based on predefined +// blockchain rules rather than individual control +message Pool { + // id: the unique identifier of the pool + uint64 id = 1; + // amount: the balance of funds the pool has + uint64 amount = 2; +} \ No newline at end of file diff --git a/frontend/proto/arbor.proto b/frontend/proto/arbor.proto new file mode 100644 index 0000000000..6d4a9df9f7 --- /dev/null +++ b/frontend/proto/arbor.proto @@ -0,0 +1,155 @@ +syntax = "proto3"; +package types; + +option go_package = "github.com/ARBOR-L/ARBOR/plugin/go/contract"; + +// ───────────────────────────────────────────── +// Market lifecycle +// ───────────────────────────────────────────── + +// MessageCreateMarket creates a new isolated lending market (ARCM §3, §19.2) +message MessageCreateMarket { + string market_id = 1; + string collateral_asset_id = 2; + string debt_asset_id = 3; + uint32 asset_tier = 4; // 0-4, ARCM §4 LTV table + uint64 reserve_factor_bps = 5; // 200-3000 bps, AYIS §13 + bytes creator = 6; + repeated bytes authorized_submitters = 7; // ARCM §10 permissioned price feed; + // trusted addresses for update_price on + // this market's two assets (shared list, + // not per-asset). Immutable as of this + // version -- no governance-gated + // add/remove path exists yet. Must satisfy + // MinReporters (hardcoded 3, mirrors + // interest_rate.go's precedent of + // hardcoding pending {22}'s governance + // param store, which does not exist yet). +} + +// MessageUpdateMarketParams updates governance-bounded per-market params (ARCM §13, §15) +message MessageUpdateMarketParams { + string market_id = 1; + bytes authority = 2; + uint64 reserve_factor_bps = 3; +} + +// MessagePauseMarket halts a market via governance/risk-committee action (ARCM §13, §16) +message MessagePauseMarket { + string market_id = 1; + bytes authority = 2; +} + +// MessageResumeMarket resumes a paused market +message MessageResumeMarket { + string market_id = 1; + bytes authority = 2; +} + +// MessageDeprecateMarket permanently retires a market +message MessageDeprecateMarket { + string market_id = 1; + bytes authority = 2; +} + +// ───────────────────────────────────────────── +// Oracle (ARCM §10) +// ───────────────────────────────────────────── + +// MessageUpdatePrice submits a permissioned price feed reading +message MessageUpdatePrice { + string asset_id = 1; // must match this market's collateral_asset_id + // or debt_asset_id (checked at DeliverTx) + uint64 price = 2; // USD per unit, x1e8 + uint32 confidence_bps = 3; + bytes submitter = 4; + string market_id = 5; // scopes this submission to one market's + // authorized_submitters list (ARCM Section + // 10 is a PER-MARKET permissioned feed, not + // a global asset-price authority -- added + // to avoid an unbounded PrefixMarkets scan + // to reverse-lookup market from asset_id) +} + +// ───────────────────────────────────────────── +// Collateral (borrower side, ARCM §6) +// ───────────────────────────────────────────── + +// MessageDepositCollateral posts collateral against a borrower position +message MessageDepositCollateral { + string market_id = 1; + bytes address = 2; + uint64 quantity = 3; // native units, 9-decimal convention (ARCM §2.1a) +} + +// MessageWithdrawCollateral removes collateral, subject to post-withdrawal HF check +message MessageWithdrawCollateral { + string market_id = 1; + bytes address = 2; + uint64 quantity = 3; +} + +// ───────────────────────────────────────────── +// Supply / lending side (AYIS §4) +// ───────────────────────────────────────────── + +// MessageDeposit supplies the market's asset in exchange for aToken shares (AYIS MintShares) +message MessageDeposit { + string market_id = 1; + bytes address = 2; + uint64 amount = 3; // native asset units +} + +// MessageWithdraw redeems aToken shares for the underlying asset (AYIS RedeemShares) +message MessageWithdraw { + string market_id = 1; + bytes address = 2; + uint64 shares = 3; // aToken shares, not underlying amount +} + +// ───────────────────────────────────────────── +// Borrow / repay (ARCM §6, §19.2.1) +// ───────────────────────────────────────────── + +// MessageBorrow opens or increases a borrow position against posted collateral +message MessageBorrow { + string market_id = 1; + bytes address = 2; + uint64 borrow_amount = 3; +} + +// MessageRepay reduces or closes a borrow position +message MessageRepay { + string market_id = 1; + bytes address = 2; + uint64 repay_amount = 3; +} + +// ───────────────────────────────────────────── +// Liquidation (ARCM §6, §19.2.2) +// ───────────────────────────────────────────── + +// MessageLiquidatePosition liquidates an undercollateralized borrower position +message MessageLiquidatePosition { + string market_id = 1; + bytes liquidator = 2; + bytes borrower_address = 3; + uint64 repay_amount = 4; // capped at debt x close_factor, ARCM §7 +} + +// ───────────────────────────────────────────── +// Asset tier registry (ARCM §3.1/§3.2) +// ───────────────────────────────────────────── + +// MessageSetAssetTier registers or updates an asset's canonical risk tier +// (0=Tier0/CNPY .. 3=Tier3/Restricted; Tier 4/Blacklisted is never stored, +// see state_keys.go PrefixAssetTier). Authority-gated -- single hardcoded +// address for now, standing in for the risk-committee multisig ARCM §13 +// names as the intended actor for tier promotion/demotion; same disclosed- +// placeholder pattern as authorized_submitters above. Real governance-gated +// multisig/timelock is a future milestone, not implemented here. +message MessageSetAssetTier { + string asset_id = 1; + uint32 tier = 2; // 0-3 only; checked at DeliverTx + bytes authority = 3; +} diff --git a/frontend/proto/arbor_events.proto b/frontend/proto/arbor_events.proto new file mode 100644 index 0000000000..55e168824b --- /dev/null +++ b/frontend/proto/arbor_events.proto @@ -0,0 +1,127 @@ +syntax = "proto3"; +package types; + +option go_package = "github.com/ARBOR-L/ARBOR/plugin/go/contract"; + +// ───────────────────────────────────────────── +// Encoding-boundary / freeze events (ARCM §9.3a, AYIS §3.2/4.6, Principle 14) +// ───────────────────────────────────────────── + +// EventIndexEncodingOverflowHalted fires when a BeginBlock-context TryEncodeUint128 +// call fails for B_index, S_rate, or R_fund's interest-routing leg. Sets +// index_overflow_halted for this market only. +message EventIndexEncodingOverflowHalted { + string market_id = 1; + string field = 2; // "B_index" | "S_rate" | "R_fund" + string attempted_value = 3; // decimal string, the value that failed to encode +} + +// ───────────────────────────────────────────── +// Insolvent-market value routing (ARCM §9.3, J1/K1) +// ───────────────────────────────────────────── + +// EventInsolventMarketValueRecovered fires each time recovered value routes to +// R_fund for an Insolvent market (interest, repay principal, or liquidation proceeds). +message EventInsolventMarketValueRecovered { + string market_id = 1; + uint64 recovered_amount = 2; + string source = 3; // "interest" | "repay_principal" | "liquidation_proceeds" +} + +// ───────────────────────────────────────────── +// Dust-clamp events (ARCM §19.2.1b, AYIS §4.4 — H4 fix: pre-clamp value, not post-clamp zero) +// ───────────────────────────────────────────── + +// EventTotalSuppliedDustClamp fires when a withdrawal clamps market.total_supplied to zero +message EventTotalSuppliedDustClamp { + string market_id = 1; + uint64 actual_withdrawn = 2; + uint64 pre_clamp_value = 3; // [H4] the amount actually clamped away +} + +// EventTotalSharesOutstandingDustClamp fires when a redemption clamps +// total_shares_outstanding to zero +message EventTotalSharesOutstandingDustClamp { + string market_id = 1; + uint64 shares_redeemed = 2; + uint64 pre_clamp_value = 3; // [H4] the amount actually clamped away +} + +// EventTotalBorrowedDustClamp fires when applyDebtDelta's decrement branch +// clamps market.TotalBorrowed to zero because the decrease amount (from +// repay or liquidation) was >= the current aggregate. Mirrors +// EventTotalSuppliedDustClamp's fix (ARCM v3.11.1 Section III.6 / AYIS +// Section 4.4) for the identical failure class on the borrower-side +// aggregate: without this event, the clamp is silent and the resulting +// total_borrowed == 0 (while a position may still show nonzero +// debtPrincipal, per ARCM Invariant I3's drift tolerance) is +// indistinguishable from a market with genuinely no outstanding debt. +message EventTotalBorrowedDustClamp { + string market_id = 1; + string source = 2; // "repay" | "liquidation" + uint64 decrease_amount = 3; // the delta that triggered the clamp + uint64 pre_clamp_value = 4; // the amount actually clamped away +} + +// ───────────────────────────────────────────── +// Layer 4 (bad-debt socialization) events (ARCM §9.2b, §9.2, AYIS §5.4.3) +// ───────────────────────────────────────────── + +// EventLayer4PendingCountWarning fires when the soft backlog threshold is crossed +message EventLayer4PendingCountWarning { + string market_id = 1; + uint32 pending_count = 2; + string pending_bad_debt_total = 3; // decimal string, uint128-scale (L2-widen) +} + +// EventLayer4PendingBadDebtTotalSaturated fires when the widened uint128 counter +// would overflow (astronomically unlikely post-widen; retained as a tripwire) +message EventLayer4PendingBadDebtTotalSaturated { + string market_id = 1; + uint64 bad_debt = 2; +} + +// EventLayer4PendingCountUnderflow fires on a decrement-below-zero attempt +// (should never occur; defensive signal only) +message EventLayer4PendingCountUnderflow { + string market_id = 1; +} + +// EventDepositWithdrawBlockedDuringPendingLoss fires when deposit/withdraw/borrow +// is rejected due to layer4_pending_count > 0 +message EventDepositWithdrawBlockedDuringPendingLoss { + string market_id = 1; + string tx_type = 2; +} + +// EventLossFactorExhausted fires when bad_debt >= total_supplied_equiv, driving +// loss_factor to zero and transitioning the market to Insolvent +message EventLossFactorExhausted { + string market_id = 1; + uint64 bad_debt = 2; + uint64 total_supplied_equiv = 3; +} + +// EventBadDebtSocialization fires on every non-exhausting Layer 4 haircut application +message EventBadDebtSocialization { + string market_id = 1; + uint64 bad_debt = 2; + string new_loss_factor = 3; // decimal string, uint128-scale, RAY-precision +} + +// EventLossFactorAppliedToAlreadyInsolventMarket fires on the K3 idempotency +// guard's early-return path (queued application against an already-Insolvent market) +message EventLossFactorAppliedToAlreadyInsolventMarket { + string market_id = 1; + uint64 bad_debt = 2; +} + +// ───────────────────────────────────────────── +// Migration (ARCM §12.4, M4) +// ───────────────────────────────────────────── + +// EventReserveFundEncodingMigrationCompleted fires once, at the announced upgrade +// height, after the one-time {18} uint64->uint128 zero-extension pass completes +message EventReserveFundEncodingMigrationCompleted { + uint64 completed_at_height = 1; +} diff --git a/frontend/proto/arbor_state.proto b/frontend/proto/arbor_state.proto new file mode 100644 index 0000000000..69a7b4dd71 --- /dev/null +++ b/frontend/proto/arbor_state.proto @@ -0,0 +1,97 @@ +syntax = "proto3"; +package types; + +option go_package = "github.com/ARBOR-L/ARBOR/plugin/go/contract"; + +// MarketStatus mirrors ARCM's market.status enum (Section 9, Section 13, Section 16). +enum MarketStatus { + ACTIVE = 0; + PAUSED = 1; // governance action (ARCM Section 13) + INSOLVENT = 2; // loss_factor reached zero (AYIS Section 5.4.3, I11) + DEPRECATED = 3; // permanently retired (ARCM Section 19.2) +} + +// Market is the {16} record: core market metadata plus the flags and counters +// ARCM's bad-debt waterfall and freeze mechanism operate on. See ARCM v3.11.1 +// Section 19.1 for the canonical field set this implements. +message Market { + string market_id = 1; + string collateral_asset_id = 2; + string debt_asset_id = 3; + uint32 asset_tier = 4; // 0-4, ARCM Section 4 LTV table + uint64 reserve_factor_bps = 5; // AYIS Section 13 + bytes creator = 6; + + MarketStatus status = 7; + bool index_overflow_halted = 8; // ARCM Section 9.3a + + uint32 layer4_pending_count = 9; // ARCM Section 9.2b + bytes layer4_pending_bad_debt_total = 10; // uint128, EncodeUint128 raw bytes (widened v3.11, L2-widen) + + uint64 total_borrowed = 11; // guarded via applyDebtDelta, C1 + uint64 total_supplied = 12; // ARCM Section 19.2.1b + + uint64 last_accrual_block = 13; // AYIS Section 7 Step 11 + + repeated bytes authorized_submitters = 14; // ARCM Section 10 permissioned + // price feed; trusted addresses + // for update_price on this + // market's two assets (shared + // list). Set once at + // create_market, immutable -- + // no governance add/remove path + // exists yet. +} + +// BorrowerPosition is the {17} record (ARCM Section 6, AYIS Section 6). +message BorrowerPosition { + string market_id = 1; + bytes address = 2; + uint64 collateral_quantity = 3; + uint64 debt_principal = 4; + bytes borrow_index_at_open = 5; // uint128, EncodeUint128 raw bytes -- B_index snapshot at open +} + +// PriceRecord is one {19} entry, keyed by (asset_id, submitter) -- +// ARCM Section 10's permissioned price feed. Multiple independent +// submitters each write their own record per asset; quorum (MIN_REPORTERS) +// and deviation (30% circuit breaker) are resolved by aggregating across +// all of an asset's records at READ time, not by any single record being +// authoritative on its own. block_height is chain-assigned at write time +// (not submitter-supplied) for Section 11's staleness checks. +message PriceRecord { + string asset_id = 1; + bytes submitter = 2; + uint64 price = 3; // USD per unit, x1e8 + uint32 confidence_bps = 4; + uint64 block_height = 5; +} + +// LenderPosition is the {24} record (AYIS Section 5.1). +message LenderPosition { + string market_id = 1; + bytes address = 2; + uint64 shares = 3; + uint64 deposit_block = 4; +} + +// LossFactorQueueEntry is a {28} record (AYIS Section 12.4, ARCM v3.11.1 +// Section 9.3b Rule 3). One entry per market_id: a backstop-triggered +// Layer 4 exhaustion enqueues a bad_debt amount here (via +// EnqueueLossFactorApplication) rather than calling ApplyLossFactor() +// synchronously, so BeginBlock's ProcessLossFactorQueue() can drain it +// later in the same call under Section 12.3's Accrual Ordering Contract +// (AccrueInterest MUST run before this queue drains). A market has at +// most one outstanding entry at a time -- K3's idempotency guard in +// ApplyLossFactor() means a second enqueue against an already-Insolvent +// market is a no-op at drain time, not a second queued entry, so this +// message does not need its own sequence/ordering field. +message LossFactorQueueEntry { + string market_id = 1; + uint64 bad_debt = 2; + uint64 enqueued_block = 3; // observability only; not read by any + // drain-order logic (drain order is + // unspecified/immaterial per AYIS 5.4.3, + // MAX_LOSS_FACTOR_APPLICATIONS_PER_BLOCK + // bounds work per block, not by age) +} diff --git a/frontend/proto/event.proto b/frontend/proto/event.proto new file mode 100644 index 0000000000..fafdccb8ba --- /dev/null +++ b/frontend/proto/event.proto @@ -0,0 +1,35 @@ +syntax = "proto3"; +package types; + +option go_package = "github.com/ARBOR-L/ARBOR/plugin/go/contract"; + +import "google/protobuf/any.proto"; + +message Event { + // event_type: The type of the transaction like 'slash' or 'unstake' + string event_type = 1; // @gotags: json:"eventType" + // msg: The actual event message payload, which is encapsulated in a oneof format + oneof msg { + EventCustom custom = 11; + } + // height: the block height of the event + uint64 height = 91; + // reference: the 'begin_block' / transaction hash / 'end_block' + string reference = 92; + // chainId: the chain id associated with the event + uint64 chainId = 93; + // block_height: the number of blocks in the blockchain before a specific block, indicating its position in the chain + // and representing the blockchain's length + uint64 block_height = 94; // @gotags: json:"blockHeight" + // block_hash: a unique identifier for a block, generated by applying a cryptographic hash function to the block's contents, + // ensuring its integrity and connecting it to the previous block in the chain. + bytes block_hash = 95; // @gotags: json:"blockHash" + // address: The address of the user affected by the event + bytes address = 96; +} + +// EventCustom carries a plugin-defined event payload. +message EventCustom { + // msg: custom payload. + google.protobuf.Any msg = 1; +} diff --git a/frontend/proto/plugin.proto b/frontend/proto/plugin.proto new file mode 100644 index 0000000000..9f5f8e64a0 --- /dev/null +++ b/frontend/proto/plugin.proto @@ -0,0 +1,246 @@ +syntax = "proto3"; +package types; +option go_package = "github.com/ARBOR-L/ARBOR/plugin/go/contract"; +import "event.proto"; +import "tx.proto"; + +// FSMToPlugin is the outbound message to the plugin from the main FSM (fsm -> plugin) +message FSMToPlugin { + // id: the unique ID of the request + uint64 id = 1; + // payload: the payload of the message + oneof payload { + // config: the response to the plugin config message + PluginFSMConfig config = 2; + // genesis: request to execute genesis logic on the plugin + PluginGenesisRequest genesis = 3; + // begin: request to execute 'begin block' logic on the plugin + PluginBeginRequest begin = 4; + // check: request to execute minimum logic to validate the transaction + PluginCheckRequest check = 5; + // deliver: request to execute 'deliver tx' logic on the plugin + PluginDeliverRequest deliver = 6; + // end: request to execute 'end block' logic on the plugin + PluginEndRequest end = 7; + // state_read: response with read state data + PluginStateReadResponse state_read = 8; + // state_write: acknowledgment of write operation + PluginStateWriteResponse state_write = 9; + // query: response to a detached, read-only state query + PluginQueryResponse query = 10; + // error: any error returned by the FSM + PluginError error = 99; + } +} + +// PluginToFSM is the outbound message from the plugin to the FSM (plugin -> fsm) +message PluginToFSM { + // id: the unique ID of the request + uint64 id = 1; + // payload: the payload of the message + oneof payload { + // config: the request to initialize the plugin + PluginConfig config = 2; + // genesis: response to the genesis request + PluginGenesisResponse genesis = 3; + // begin: response to the begin block request + PluginBeginResponse begin = 4; + // check: response to the check tx request + PluginCheckResponse check = 5; + // deliver: response to the deliver tx request + PluginDeliverResponse deliver = 6; + // end: response to the end block request + PluginEndResponse end = 7; + // state_read: request to read plugin state from the FSM + PluginStateReadRequest state_read = 8; + // state_write: request to write plugin state to the FSM + PluginStateWriteRequest state_write = 9; + // query: detached, read-only state query (not tied to a tx/block lifecycle) + PluginQueryRequest query = 10; + } +} + +// PluginConfig is the identity information of the plugin that is communicated to the fsm +message PluginConfig { + // name: the name of the plugin + string name = 1; + // id: the unique identifier of the plugin + uint64 id = 2; + // version: the version of the plugin + uint64 version = 3; + // supported_transactions: a list of custom transaction names that are supported (order must match transaction_type_urls) + repeated string supported_transactions = 4; + // file_descriptor_protos: serialized FileDescriptorProto bytes + repeated bytes file_descriptor_protos = 5; // @gotags: json:"fileDescriptorProtos" + // transaction_type_urls: protobuf type URLs for transaction messages (aligned by index with supported_transactions) + repeated string transaction_type_urls = 6; // @gotags: json:"transactionTypeUrls" + // event_type_urls: protobuf type URLs for event messages + repeated string event_type_urls = 7; // @gotags: json:"eventTypeUrls" + // custom_state_prefixes: the store key prefixes the plugin owns for its custom records (each entry + // is the raw prefix bytes, e.g. [100] for faucet). Canopy panics at handshake if any collides with + // a core-reserved prefix (1-15), preventing silent state corruption from colliding keyspaces. + repeated bytes custom_state_prefixes = 8; // @gotags: json:"customStatePrefixes" +} + +// PluginFSMConfig is the identity information of the plugin that is communicated from the fsm to the plugin +message PluginFSMConfig {PluginConfig config = 1;} + +// Core block lifecycle messages + +// PluginGenesisRequest carries genesis JSON data for initialization +message PluginGenesisRequest {bytes genesis_json = 1;} + +// PluginGenesisResponse acknowledges genesis execution completion +message PluginGenesisResponse {PluginError error = 99;} + +// PluginBeginRequest signals start of a new block +message PluginBeginRequest {uint64 height = 1; } + +// PluginBeginResponse acknowledges begin block execution +message PluginBeginResponse { + repeated Event events = 1; + PluginError error = 99; +} + +// PluginCheckRequest carries a transaction to be checked +message PluginCheckRequest {Transaction tx = 1;} + +// PluginCheckResponse acknowledges transaction check +message PluginCheckResponse { + // authorized_signers: addresses who are authorized to sign the transaction + repeated bytes authorized_signers = 1; // @gotags: json:"authorizedSigners" + // recipient: address of the recipient of the transaction (nil if not applicable) + bytes recipient = 2; + // error: an error occurred when checking the transaction + PluginError error = 99; +} + +// PluginDeliverRequest carries a transaction to be processed +message PluginDeliverRequest {Transaction tx = 1;} + +// PluginDeliverResponse acknowledges transaction delivery +message PluginDeliverResponse { + repeated Event events = 1; + PluginError error = 99; +} + +// PluginEndRequest signals end of the current block +message PluginEndRequest { + uint64 height = 1; + bytes proposer_address = 2; +} + +// PluginEndResponse acknowledges end block execution +message PluginEndResponse { + repeated Event events = 1; + PluginError error = 99; +} + +// PluginError carries error details from plugin or FSM +message PluginError { + uint64 code = 1; // error code + string module = 2; // error module + string msg = 3; // error message +} + +// Plugin Detached Query Interface + +// PluginQueryRequest is a detached, read-only state query (not tied to a tx/block) +message PluginQueryRequest { + // height: the height to query; 0 = latest committed + uint64 height = 1; + // read: the read request to execute against the read-only state snapshot + PluginStateReadRequest read = 2; +} + +// PluginQueryResponse returns the results of a detached, read-only state query +message PluginQueryResponse { + // read: the results of the read request + PluginStateReadResponse read = 1; + // error: if an error occurred during the request execution + PluginError error = 99; +} + +// Plugin State Read Interface + +// PluginStateReadRequest allows batching multiple key or range reads in one call +message PluginStateReadRequest { + // keys: explicit keys to read + repeated PluginKeyRead keys = 1; + // ranges: key ranges to iterate over and read + repeated PluginRangeRead ranges = 2; +} + +// PluginKeyRead requests a single key read, identified by query_id +message PluginKeyRead { + // query_id to correlate requests and responses + uint64 query_id = 1; // @gotags: json:"queryId" + // key to read from state + bytes key = 2; +} + +// PluginRangeRead requests an iteration over a key range with optional limits and direction +message PluginRangeRead { + // query_id to correlate requests and responses + uint64 query_id = 1; // @gotags: json:"queryId" + // prefix: the prefix to iterate over + bytes prefix = 2; + // limit: maximum number of entries to return + uint64 limit = 3; + // reverse: whether to iterate in reverse order + bool reverse = 4; +} + +// PluginStateReadResponse returns the results for the read requests +message PluginStateReadResponse { + // results hold multiple query results matching requests by query_id + repeated PluginReadResult results = 1; + // error: if an error occurred during the request execution + PluginError error = 99; +} + +// PluginReadResult holds the result entries for a specific read query +message PluginReadResult { + // query_id: matching the original read request + uint64 query_id = 1; // @gotags: json:"queryId" + // entries: returned for this query + repeated PluginStateEntry entries = 2; +} + +// Plugin State Write Interface + +// PluginStateWriteRequest batches multiple set and delete operations in one call +message PluginStateWriteRequest { + // sets: keys and values to write to state + repeated PluginSetOp sets = 1; + // deletes: keys to remove from state + repeated PluginDeleteOp deletes = 2; +} + +// PluginStateWriteResponse acknowledges successful write operations +message PluginStateWriteResponse { + // error: if an error occurred during the request execution + PluginError error = 99; +} + +// PluginSetOp represents a key/value pair to set in state +message PluginSetOp { + // key: is the 'key' associated with the value in the KV pair for the set op + bytes key = 1; + // key: is the 'value' associated with the value in the KV pair for the set op + bytes value = 2; +} + +// PluginDeleteOp represents a key to delete from state +message PluginDeleteOp { + // key: is the 'key' associated with the value in the KV pair for the delete op + bytes key = 1; +} + +// PluginStateEntry represents a key/value pair returned in read results +message PluginStateEntry { + // key: is the 'key' associated with the value in the KV pair for the 'get' op + bytes key = 1; + // value: is the 'value' associated with the value in the KV pair for the 'get' op + bytes value = 2; +} diff --git a/frontend/proto/tx.proto b/frontend/proto/tx.proto new file mode 100644 index 0000000000..3e37ae88ac --- /dev/null +++ b/frontend/proto/tx.proto @@ -0,0 +1,56 @@ +syntax = "proto3"; +package types; +option go_package = "github.com/ARBOR-L/ARBOR/plugin/go/contract"; + +import "google/protobuf/any.proto"; +// Transaction represents a request or action submitted to the network like transfer assets or perform other operations +// within the blockchain system - THIS MUST MATCH lib.Transaction EXACTLY for signing +message Transaction { + // message_type: The type of the transaction like 'send' or 'stake' + string message_type = 1; // @gotags: json:"messageType" + // msg: The actual transaction message payload, which is encapsulated in a generic message format + google.protobuf.Any msg = 2; + // signature: The cryptographic signature used to verify the authenticity of the transaction + Signature signature = 3; + // created_height: The height when the transaction was created - allows 'safe pruning' + uint64 created_height = 4; // @gotags: json:"createdHeight" + // time: The timestamp when the transaction was created - used as temporal entropy to prevent hash collisions in txs + uint64 time = 5; + // fee: The fee associated with processing the transaction + uint64 fee = 6; + // memo: An optional message or note attached to the transaction + string memo = 7; + // network_id: The identity of the network the transaction is intended for + uint64 network_id = 8; // @gotags: json:"networkID" + // chain_id: The identity of the committee the transaction is intended for + uint64 chain_id = 9; // @gotags: json:"chainID" + // NOTE: CAN EXTEND FUNCTIONALITY BY ADDING ADDITIONAL FIELDS + // NO CONFLICT STARTING AT FIELD = 10 +} + +// MessageSend is a standard transfer transaction, taking tokens from the sender and transferring +// them to the recipient +message MessageSend { + // from_address: is the sender of the funds + bytes from_address = 1; // @gotags: json:"fromAddress" + // to_address: is the recipient of the funds + bytes to_address = 2; // @gotags: json:"toAddress" + // amount: is the amount of tokens in micro-denomination (uCNPY) + uint64 amount = 3; +} + +// FeeParams is the parameter space that defines various amounts for transaction fees +message FeeParams { + // send_fee: is the fee amount (in uCNPY) for Message Send + uint64 send_fee = 1; // @gotags: json:"sendFee" + // NO CONFLICT STARTING AT FIELD = 14 +} + +// A Signature is a digital signature is a cryptographic "fingerprint" created with a private key, +// allowing others to verify the authenticity and integrity of a message using the corresponding public key +message Signature { + // public_key: is a cryptographic code shared openly, used to verify digital signatures + bytes public_key = 1; // @gotags: json:"publicKey" + // signature: the bytes of the signature output from a private key which may be verified with the message and public + bytes signature = 2; +} diff --git a/frontend/public/file.svg b/frontend/public/file.svg new file mode 100644 index 0000000000..004145cddf --- /dev/null +++ b/frontend/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/public/globe.svg b/frontend/public/globe.svg new file mode 100644 index 0000000000..567f17b0d7 --- /dev/null +++ b/frontend/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/public/logo-mark.svg b/frontend/public/logo-mark.svg new file mode 100644 index 0000000000..1cb4539fe6 --- /dev/null +++ b/frontend/public/logo-mark.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/public/logo-seal.svg b/frontend/public/logo-seal.svg new file mode 100644 index 0000000000..7949925891 --- /dev/null +++ b/frontend/public/logo-seal.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/public/logo-tree.svg b/frontend/public/logo-tree.svg new file mode 100644 index 0000000000..63b1bd5149 --- /dev/null +++ b/frontend/public/logo-tree.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/public/next.svg b/frontend/public/next.svg new file mode 100644 index 0000000000..5174b28c56 --- /dev/null +++ b/frontend/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/public/vercel.svg b/frontend/public/vercel.svg new file mode 100644 index 0000000000..7705396033 --- /dev/null +++ b/frontend/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/public/window.svg b/frontend/public/window.svg new file mode 100644 index 0000000000..b2b2a44f6e --- /dev/null +++ b/frontend/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/scripts/gen-proto.sh b/frontend/scripts/gen-proto.sh new file mode 100755 index 0000000000..3420cf7b1f --- /dev/null +++ b/frontend/scripts/gen-proto.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +set -euo pipefail + +PROTO_DIR="proto" +OUT_DIR="src/lib/canopy/proto/generated" + +mkdir -p "$OUT_DIR" + +# Termux well-known types location +WELL_KNOWN_INCLUDE="/data/data/com.termux/files/usr/include" + +if [ ! -f "$WELL_KNOWN_INCLUDE/google/protobuf/any.proto" ]; then + WELL_KNOWN_INCLUDE="/usr/include" +fi + +if [ ! -f "$WELL_KNOWN_INCLUDE/google/protobuf/any.proto" ]; then + WELL_KNOWN_INCLUDE="/usr/local/include" +fi + +echo "Proto dir: $PROTO_DIR" +echo "Output dir: $OUT_DIR" +echo "Well-known include: $WELL_KNOWN_INCLUDE" + +protoc \ + --plugin=protoc-gen-ts_proto=./node_modules/.bin/protoc-gen-ts_proto \ + --ts_proto_out="$OUT_DIR" \ + --ts_proto_opt=esModuleInterop=true \ + --ts_proto_opt=forceLong=bigint \ + --ts_proto_opt=env=browser \ + --ts_proto_opt=outputEncodeMethods=true \ + --ts_proto_opt=outputJsonMethods=true \ + --ts_proto_opt=outputClientImpl=false \ + --ts_proto_opt=useDate=false \ + --ts_proto_opt=onlyTypes=false \ + --ts_proto_opt=unrecognizedEnum=false \ + -I"$PROTO_DIR" \ + -I"$WELL_KNOWN_INCLUDE" \ + "$PROTO_DIR"/*.proto \ + "$WELL_KNOWN_INCLUDE/google/protobuf/any.proto" + +echo "Proto generation complete." diff --git a/frontend/src/app/admin/page.tsx b/frontend/src/app/admin/page.tsx new file mode 100644 index 0000000000..9410c0f90a --- /dev/null +++ b/frontend/src/app/admin/page.tsx @@ -0,0 +1,173 @@ +"use client"; + +import { useRoles, PROTOCOL_AUTHORITY } from "@/lib/hooks/useRoles"; +import { useMarkets } from "@/lib/hooks/useMarkets"; +import { bytesToHex } from "@/lib/canopy/decode"; +import { CreateMarketForm } from "@/components/forms/CreateMarketForm"; +import { MarketLifecycleForm } from "@/components/forms/MarketLifecycleForm"; +import { SetAssetTierForm } from "@/components/forms/SetAssetTierForm"; +import { SetTreasuryCutForm } from "@/components/forms/SetTreasuryCutForm"; + +function shortHex(hex: string): string { + if (!hex) return "—"; + const h = hex.replace(/^0x/, "").toLowerCase(); + return h.length > 12 ? `0x${h.slice(0, 6)}…${h.slice(-4)}` : `0x${h}`; +} + +function norm(hex: string): string { + return hex.replace(/^0x/, "").toLowerCase(); +} + +export default function AuthorityPage() { + const roles = useRoles(); + const { data: markets } = useMarkets(); + const list = markets ?? []; + + return ( +
+
+

+ Governance · protocol authority +

+

Authority console

+

+ Governance controls gated by your on-chain role. The plugin enforces + these same roles at submit time; this console mirrors them so a + control you cannot use is shown locked before you ever sign. +

+
+ +
+ {!roles.connected ? ( +
+ Connect a wallet to see your on-chain role on this network. +
+ ) : roles.isProtocolAuthority ? ( +
+
+ + Authority + + You are the protocol authority on this network. +
+

+ You can exercise governance: pause / resume / deprecate markets, update + market parameters, and set asset tiers. On this devnet that role is the + single hardcoded placeholder for the future on-chain governance store + ({`{22}`}), which is not yet live. +

+

+ authority: {PROTOCOL_AUTHORITY} +

+
+ ) : ( +
+
+ Public + {roles.oracleFor.length > 0 && ( + Oracle · {roles.oracleFor.length} + )} + You hold no protocol authority on this network. +
+

+ Governance actions below are locked. Submitting them would be rejected by + the plugin with ErrUnauthorized at + DeliverTx. Oracle submission + works only for markets that list you as an authorized submitter. +

+

+ protocol authority: {PROTOCOL_AUTHORITY} +

+
+ )} +
+ +
+

Open actions

+

+ Creating a market is signed by its creator — no authority required. The + plugin records the signer as the market's Creator for provenance. +

+
+ +
+
+ +
+

Protocol authority actions

+ {roles.isProtocolAuthority ? ( +
+
+ +
+
+ +
+
+ +
+
+ ) : ( +
+ Locked. Pause / resume / deprecate / update market params / set asset tier / + set treasury cut require the protocol authority, which this connected address is not. +
+ )} +
+ +
+

Per-market authority & oracle map

+

+ Creator is provenance (who signed create_market), not a gate. + Oracle eligibility is per-market (authorized_submitters on each + Market record). Authority is global — the single hardcoded address above. +

+
+ + + + + + + + + + + + {list.map((e) => { + const m = e.market; + const creatorHex = m.creator ? bytesToHex(m.creator) : ""; + const isOracle = + roles.connected && + (m.authorizedSubmitters ?? []).some((s) => norm(bytesToHex(s)) === roles.address); + return ( + + + + + + + + ); + })} + +
MarketStatusCreatorYou = oracle?You = authority?
{m.marketId}{m.status} + {shortHex(creatorHex)} + + {isOracle ? ( + + ) : ( + + )} + + {roles.isProtocolAuthority ? ( + + ) : ( + + )} +
+
+
+
+ ); +} diff --git a/frontend/src/app/api/auth/discord/callback/route.ts b/frontend/src/app/api/auth/discord/callback/route.ts new file mode 100644 index 0000000000..acd2e98556 --- /dev/null +++ b/frontend/src/app/api/auth/discord/callback/route.ts @@ -0,0 +1,54 @@ +import { NextRequest, NextResponse } from "next/server"; + +/** + * Discord's redirect target. Exchanges the auth code for an access token, + * fetches the user's Discord ID, and stores it in a short-lived cookie for + * the /link page to read. Nothing is written to the indexer here — this + * route only proves "this browser owns this Discord account"; the actual + * wallet-signature binding happens later, on /link. + */ +export async function GET(req: NextRequest) { + const appUrl = process.env.APP_URL ?? "http://localhost:3000"; + const url = new URL(req.url); + const code = url.searchParams.get("code"); + const state = url.searchParams.get("state"); + const expectedState = req.cookies.get("discord_oauth_state")?.value; + + if (!code || !state || !expectedState || state !== expectedState) { + return NextResponse.redirect(`${appUrl}/link?error=discord_state_mismatch`); + } + + const tokenRes = await fetch("https://discord.com/api/oauth2/token", { + method: "POST", + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + body: new URLSearchParams({ + client_id: process.env.DISCORD_CLIENT_ID ?? "", + client_secret: process.env.DISCORD_CLIENT_SECRET ?? "", + grant_type: "authorization_code", + code, + redirect_uri: `${appUrl}/api/auth/discord/callback`, + }), + }); + + if (!tokenRes.ok) { + return NextResponse.redirect(`${appUrl}/link?error=discord_token_exchange_failed`); + } + + const { access_token } = await tokenRes.json(); + + const userRes = await fetch("https://discord.com/api/users/@me", { + headers: { Authorization: `Bearer ${access_token}` }, + }); + + if (!userRes.ok) { + return NextResponse.redirect(`${appUrl}/link?error=discord_user_fetch_failed`); + } + + const discordUser = await userRes.json(); + + const res = NextResponse.redirect(`${appUrl}/link?linked=discord`); + res.cookies.set("discord_id", discordUser.id, { httpOnly: true, maxAge: 3600, path: "/" }); + res.cookies.set("discord_username", discordUser.username ?? "", { httpOnly: true, maxAge: 3600, path: "/" }); + res.cookies.delete("discord_oauth_state"); + return res; +} diff --git a/frontend/src/app/api/auth/discord/start/route.ts b/frontend/src/app/api/auth/discord/start/route.ts new file mode 100644 index 0000000000..60c9926495 --- /dev/null +++ b/frontend/src/app/api/auth/discord/start/route.ts @@ -0,0 +1,26 @@ +import { NextRequest, NextResponse } from "next/server"; +import { randomBytes } from "node:crypto"; + +/** + * Kicks off Discord OAuth. Requires DISCORD_CLIENT_ID and APP_URL env vars + * (see .env.example). A random `state` value is stored in a short-lived + * cookie and echoed back by Discord on callback — standard CSRF protection + * for OAuth redirects, so a third party can't trick a user's browser into + * completing a login flow the user didn't start. + */ +export async function GET() { + const state = randomBytes(16).toString("hex"); + const appUrl = process.env.APP_URL ?? "http://localhost:3000"; + + const params = new URLSearchParams({ + client_id: process.env.DISCORD_CLIENT_ID ?? "", + redirect_uri: `${appUrl}/api/auth/discord/callback`, + response_type: "code", + scope: "identify", + state, + }); + + const res = NextResponse.redirect(`https://discord.com/api/oauth2/authorize?${params}`); + res.cookies.set("discord_oauth_state", state, { httpOnly: true, maxAge: 600, path: "/" }); + return res; +} diff --git a/frontend/src/app/api/auth/session/route.ts b/frontend/src/app/api/auth/session/route.ts new file mode 100644 index 0000000000..2cb7b74cb4 --- /dev/null +++ b/frontend/src/app/api/auth/session/route.ts @@ -0,0 +1,15 @@ +import { NextRequest, NextResponse } from "next/server"; + +/** + * Cookies set by the OAuth callbacks are httpOnly (can't be read from + * client-side JS directly, which is deliberate — keeps the raw Discord ID + * out of reach of any injected script). This route is the one sanctioned + * way for the /link page to check "what's already connected in this + * browser session" without exposing the cookies themselves. + */ +export async function GET(req: NextRequest) { + const discordId = req.cookies.get("discord_id")?.value ?? null; + const discordUsername = req.cookies.get("discord_username")?.value ?? null; + const twitterHandle = req.cookies.get("twitter_handle")?.value ?? null; + return NextResponse.json({ discordId, discordUsername, twitterHandle }); +} diff --git a/frontend/src/app/api/auth/twitter/callback/route.ts b/frontend/src/app/api/auth/twitter/callback/route.ts new file mode 100644 index 0000000000..61a4a680a1 --- /dev/null +++ b/frontend/src/app/api/auth/twitter/callback/route.ts @@ -0,0 +1,54 @@ +import { NextRequest, NextResponse } from "next/server"; + +export async function GET(req: NextRequest) { + const appUrl = process.env.APP_URL ?? "http://localhost:3000"; + const url = new URL(req.url); + const code = url.searchParams.get("code"); + const state = url.searchParams.get("state"); + const expectedState = req.cookies.get("twitter_oauth_state")?.value; + const codeVerifier = req.cookies.get("twitter_code_verifier")?.value; + + if (!code || !state || !expectedState || state !== expectedState || !codeVerifier) { + return NextResponse.redirect(`${appUrl}/link?error=twitter_state_mismatch`); + } + + const basicAuth = Buffer.from( + `${process.env.TWITTER_CLIENT_ID ?? ""}:${process.env.TWITTER_CLIENT_SECRET ?? ""}` + ).toString("base64"); + + const tokenRes = await fetch("https://api.twitter.com/2/oauth2/token", { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: "authorization_code", + code, + redirect_uri: `${appUrl}/api/auth/twitter/callback`, + code_verifier: codeVerifier, + }), + }); + + if (!tokenRes.ok) { + return NextResponse.redirect(`${appUrl}/link?error=twitter_token_exchange_failed`); + } + + const { access_token } = await tokenRes.json(); + + const userRes = await fetch("https://api.twitter.com/2/users/me", { + headers: { Authorization: `Bearer ${access_token}` }, + }); + + if (!userRes.ok) { + return NextResponse.redirect(`${appUrl}/link?error=twitter_user_fetch_failed`); + } + + const { data: twitterUser } = await userRes.json(); + + const res = NextResponse.redirect(`${appUrl}/link?linked=twitter`); + res.cookies.set("twitter_handle", `@${twitterUser.username}`, { httpOnly: true, maxAge: 3600, path: "/" }); + res.cookies.delete("twitter_oauth_state"); + res.cookies.delete("twitter_code_verifier"); + return res; +} diff --git a/frontend/src/app/api/auth/twitter/start/route.ts b/frontend/src/app/api/auth/twitter/start/route.ts new file mode 100644 index 0000000000..ff420e7184 --- /dev/null +++ b/frontend/src/app/api/auth/twitter/start/route.ts @@ -0,0 +1,35 @@ +import { NextResponse } from "next/server"; +import { randomBytes, createHash } from "node:crypto"; + +/** + * X's OAuth 2.0 requires PKCE (a code_verifier/code_challenge pair) even + * for confidential clients. The verifier is stored in a cookie and sent + * again on callback to prove this is the same browser session that + * started the flow — a second CSRF-style protection alongside `state`. + * Requires TWITTER_CLIENT_ID and APP_URL env vars. + */ +function base64url(input: Buffer): string { + return input.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); +} + +export async function GET() { + const appUrl = process.env.APP_URL ?? "http://localhost:3000"; + const state = randomBytes(16).toString("hex"); + const codeVerifier = base64url(randomBytes(32)); + const codeChallenge = base64url(createHash("sha256").update(codeVerifier).digest()); + + const params = new URLSearchParams({ + response_type: "code", + client_id: process.env.TWITTER_CLIENT_ID ?? "", + redirect_uri: `${appUrl}/api/auth/twitter/callback`, + scope: "users.read tweet.read", + state, + code_challenge: codeChallenge, + code_challenge_method: "S256", + }); + + const res = NextResponse.redirect(`https://twitter.com/i/oauth2/authorize?${params}`); + res.cookies.set("twitter_oauth_state", state, { httpOnly: true, maxAge: 600, path: "/" }); + res.cookies.set("twitter_code_verifier", codeVerifier, { httpOnly: true, maxAge: 600, path: "/" }); + return res; +} diff --git a/frontend/src/app/events/page.tsx b/frontend/src/app/events/page.tsx new file mode 100644 index 0000000000..6947bf86cb --- /dev/null +++ b/frontend/src/app/events/page.tsx @@ -0,0 +1,304 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { useQuery } from "@tanstack/react-query"; +import { + queryTxsBySenderPaged, + queryFailedTxsPaged, + queryEventsByAddress, + type TxRecord, +} from "@/lib/canopy/rpc"; +import { WaterfallPanel } from "@/components/sections/WaterfallPanel"; +import { useWalletStore } from "@/lib/wallet"; +import { formatAmount } from "@/lib/arbor/format"; + +type Tab = "activity" | "failed" | "consensus"; + +const ACTION_META: Record = { + create_market: { label: "Create market", dot: "bg-indigo-400", text: "text-indigo-300" }, + deposit: { label: "Supply", dot: "bg-emerald-400", text: "text-emerald-300" }, + withdraw: { label: "Withdraw", dot: "bg-amber-400", text: "text-amber-300" }, + deposit_collateral: { label: "Collateral deposit", dot: "bg-sky-400", text: "text-sky-300" }, + withdraw_collateral: { label: "Collateral withdraw", dot: "bg-violet-400", text: "text-violet-300" }, + borrow: { label: "Borrow", dot: "bg-rose-400", text: "text-rose-300" }, + repay: { label: "Repay", dot: "bg-emerald-400", text: "text-emerald-300" }, + liquidate_position: { label: "Liquidation", dot: "bg-rose-400", text: "text-rose-300" }, + update_price: { label: "Price update", dot: "bg-cyan-400", text: "text-cyan-300" }, + pause_market: { label: "Market paused", dot: "bg-amber-400", text: "text-amber-300" }, + resume_market: { label: "Market resumed", dot: "bg-emerald-400", text: "text-emerald-300" }, + deprecate_market: { label: "Market deprecated", dot: "bg-zinc-400", text: "text-zinc-300" }, + update_market_params: { label: "Params update", dot: "bg-indigo-400", text: "text-indigo-300" }, + set_asset_tier: { label: "Tier update", dot: "bg-violet-400", text: "text-violet-300" }, + send: { label: "Send", dot: "bg-zinc-400", text: "text-zinc-300" }, +}; + +function toBig(v: unknown): bigint { + try { + return BigInt(String(v ?? 0)); + } catch { + return 0n; + } +} + +function actionMeta(t: string) { + const key = t + .replace(/^type\.googleapis\.com\/types\.Message/, "") + .replace(/([a-z0-9])([A-Z])/g, "$1_$2") + .toLowerCase(); + return ( + ACTION_META[key] ?? + ACTION_META[t] ?? { label: t || "tx", dot: "bg-zinc-500", text: "text-zinc-300" } + ); +} + +function pickAmount(m: Record, dec = 9): string { + if (m.price != null) return `$${formatAmount(toBig(m.price), 8)}`; + for (const k of ["amount", "quantity", "shares", "borrowAmount", "repayAmount"]) { + if (m[k] != null) return formatAmount(toBig(m[k]), dec); + } + return ""; +} + +function detail(tx: TxRecord): string { + const m = tx.msg ?? {}; + const market = m.marketId ? String(m.marketId) : m.assetId ? String(m.assetId) : ""; + const dec = tx.messageType === "send" ? 6 : 9; + const amt = pickAmount(m, dec); + return [market, amt].filter(Boolean).join(" · "); +} + +function short(v: string, head = 8, tail = 6): string { + if (!v) return ""; + if (v.length <= head + tail + 1) return v; + return `${v.slice(0, head)}…${v.slice(-tail)}`; +} + +export default function EventsPage() { + const wallet = useWalletStore(); + const [addr, setAddr] = useState(""); + const [tab, setTab] = useState("activity"); + const [page, setPage] = useState(1); + + useEffect(() => { + if (wallet.isConnected && wallet.address) setAddr(wallet.address); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [wallet.isConnected, wallet.address]); + + useEffect(() => { + setPage(1); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [tab, addr]); + + const clean = addr.trim(); + const enabled = clean.length > 0; + + const txQuery = useQuery({ + queryKey: ["tx-activity", tab, clean, page], + queryFn: () => + tab === "failed" + ? queryFailedTxsPaged(clean, page, 25) + : queryTxsBySenderPaged(clean, page, 25), + enabled: enabled && tab !== "consensus", + staleTime: 8_000, + }); + + const evQuery = useQuery({ + queryKey: ["consensus-events", clean, page], + queryFn: () => queryEventsByAddress(clean, page, 25), + enabled: enabled && tab === "consensus", + staleTime: 8_000, + }); + + const txRows = tab !== "consensus" ? txQuery.data?.results ?? [] : []; + const txTotalPages = tab !== "consensus" ? txQuery.data?.totalPages ?? 0 : 0; + const txTotalCount = tab !== "consensus" ? txQuery.data?.totalCount ?? 0 : 0; + const evRows = tab === "consensus" ? evQuery.data?.events ?? [] : []; + const evTotalPages = tab === "consensus" ? evQuery.data?.totalPages ?? 0 : 0; + const evTotalCount = tab === "consensus" ? evQuery.data?.totalCount ?? 0 : 0; + + const loading = tab === "consensus" ? evQuery.isLoading : txQuery.isLoading; + const totalPages = tab === "consensus" ? evTotalPages : txTotalPages; + const totalCount = tab === "consensus" ? evTotalCount : txTotalCount; + + const TABS: { key: Tab; label: string }[] = [ + { key: "activity", label: "Activity" }, + { key: "failed", label: "Failed" }, + { key: "consensus", label: "Consensus events" }, + ]; + + return ( +
+
+

+ Events & activity log +

+

+ ARBOR protocol activity, read live from the node's transaction + history. Consensus‑layer events (reward/slash/dex) are indexed + separately by core. +

+
+ +
+ setAddr(e.target.value)} + placeholder="20‑byte hex address (e.g. your signer) — or connect a wallet" + className="w-full max-w-md rounded-xl border border-white/10 bg-white/[0.02] px-3.5 py-2.5 font-mono text-xs text-zinc-100 outline-none transition placeholder:text-zinc-600 focus:border-indigo-400/60 focus:ring-2 focus:ring-indigo-500/20" + /> + {wallet.isConnected && ( + + using connected wallet + + )} +
+ +
+ {TABS.map((t) => { + const active = tab === t.key; + return ( + + ); + })} + + {totalCount.toLocaleString()} total + +
+ +
+ {!enabled ? ( +

+ Enter an address (or connect a wallet) to view its activity. +

+ ) : loading ? ( +

Loading…

+ ) : tab !== "consensus" && txRows.length === 0 ? ( +

+ No {tab === "failed" ? "failed" : ""} transactions for this address. +

+ ) : tab === "consensus" && evRows.length === 0 ? ( +

+ No core consensus events indexed for this address on this node. +

+ ) : tab !== "consensus" ? ( + + + + + + + + + + + + + {txRows.map((tx, i) => { + const m = actionMeta(tx.messageType); + return ( + + + + + + + + + ); + })} + +
HeightActionDetailFeeTx hashStatus
+ {tx.height > 0 ? tx.height.toLocaleString() : "—"} + + + + {m.label} + + {detail(tx) || "—"} + {formatAmount(tx.fee, 6)} + + {short(tx.txHash)} + + {tab === "failed" && tx.error ? ( + + {tx.error.msg || `code ${tx.error.code}`} + + ) : ( + Confirmed + )} +
+ ) : ( + + + + + + + + + + + {evRows.map((e, i) => ( + + + + + + + ))} + +
HeightEventReferenceAddress
+ {e.height.toLocaleString()} + {e.eventType} + {e.reference === "begin_block" || e.reference === "end_block" + ? e.reference + : short(e.reference)} + {short(e.address)}
+ )} +
+ + {enabled && ( +
+ + + page {page} / {Math.max(1, totalPages)} + + +
+ )} + +

+ Activity/Failed read /v1/query/txs-by-sender and /v1/query/failed-txs + (real transactions). ARBOR amounts in 9‑decimal native units; prices in + 8‑decimal USD. Consensus events read /v1/query/events-by-address (core + index — empty on this node). +

+ +
+ ); +} diff --git a/frontend/src/app/favicon.ico b/frontend/src/app/favicon.ico new file mode 100644 index 0000000000..718d6fea48 Binary files /dev/null and b/frontend/src/app/favicon.ico differ diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css new file mode 100644 index 0000000000..ebb358d4ba --- /dev/null +++ b/frontend/src/app/globals.css @@ -0,0 +1,192 @@ +:root { + color-scheme: dark; +} + +* { + box-sizing: border-box; +} + +html, +body { + margin: 0; + padding: 0; +} + +body { + min-height: 100vh; + color: #f4f5f7; + background: + radial-gradient(1100px 560px at 50% -8%, rgba(99, 102, 241, 0.12), transparent 60%), + radial-gradient(820px 460px at 92% -4%, rgba(16, 185, 129, 0.08), transparent 55%), + radial-gradient(700px 500px at 4% 6%, rgba(56, 189, 248, 0.05), transparent 50%), + #05070d; + background-attachment: fixed; + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + font-feature-settings: "cv02", "cv03", "cv04", "cv11", "ss01"; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; +} + +::selection { + background: rgba(99, 102, 241, 0.35); + color: #fff; +} + +* { + scrollbar-width: thin; + scrollbar-color: rgba(148, 163, 184, 0.25) transparent; +} + +*::-webkit-scrollbar { + width: 9px; + height: 9px; +} + +*::-webkit-scrollbar-thumb { + background: rgba(148, 163, 184, 0.22); + border-radius: 9999px; +} + +*::-webkit-scrollbar-thumb:hover { + background: rgba(148, 163, 184, 0.38); +} + +.no-scrollbar { + -ms-overflow-style: none; + scrollbar-width: none; +} + +.no-scrollbar::-webkit-scrollbar { + display: none; +} + +@keyframes arbor-shimmer { + 100% { + transform: translateX(100%); + } +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.001ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.001ms !important; + } +} + +/* arbor-brand-system v1 */ +:root{ + --ink:#070A0F; --ink-2:#0A0F17; + --teal:#2FD6C0; --violet:#7C6CF2; --gold:#F2B84B; + --txt:#EDEFF3; --txt-2:#9AA4B2; --txt-3:#5C6675; + --line:rgba(255,255,255,.08); --line-2:rgba(255,255,255,.16); + --grad:linear-gradient(135deg,#2FD6C0 0%,#7C6CF2 100%); +} +html{ color-scheme: dark; } +body{ background: var(--ink); color: var(--txt); } +body::before{ + content:""; position:fixed; inset:0; z-index:-2; pointer-events:none; + background: + radial-gradient(58% 46% at 14% -6%, rgba(47,214,192,.18), transparent 60%), + radial-gradient(46% 40% at 92% 4%, rgba(124,108,242,.20), transparent 62%), + radial-gradient(60% 55% at 84% 104%, rgba(124,108,242,.12), transparent 60%), + radial-gradient(50% 50% at 6% 96%, rgba(47,214,192,.10), transparent 60%), + radial-gradient(40% 30% at 50% -8%, rgba(242,184,75,.06), transparent 70%); +} +body::after{ + content:""; position:fixed; inset:0; z-index:-1; pointer-events:none; + opacity:.035; mix-blend-mode:overlay; + background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 220 220' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); +} +body > div:first-of-type{ background:transparent; } +::selection{ background:rgba(47,214,192,.30); color:#fff; } +*{ scrollbar-width:thin; scrollbar-color:rgba(124,108,242,.45) transparent; } +*::-webkit-scrollbar{ width:10px; height:10px; } +*::-webkit-scrollbar-thumb{ background:linear-gradient(180deg,rgba(47,214,192,.4),rgba(124,108,242,.4)); border-radius:999px; border:2px solid transparent; background-clip:padding-box; } +*::-webkit-scrollbar-track{ background:transparent; } +.eyebrow{ display:inline-flex; align-items:center; gap:.5rem; font-size:11px; font-weight:600; letter-spacing:.2em; text-transform:uppercase; color:var(--teal); margin:0 0 .55rem; } +.eyebrow::before{ content:""; width:6px; height:6px; border-radius:999px; background:var(--gold); box-shadow:0 0 10px var(--gold); } +.display-title{ font-size:clamp(1.7rem,1.15rem + 1.9vw,2.6rem); font-weight:700; letter-spacing:-.025em; line-height:1.04; background:linear-gradient(96deg,#ffffff 24%,#bff4ec 56%,#cdc6ff 92%); -webkit-background-clip:text; background-clip:text; color:transparent; } +.section-h{ font-size:1.05rem; font-weight:600; letter-spacing:-.01em; color:var(--txt); } +.glass{ position:relative; background:linear-gradient(180deg, rgba(255,255,255,.055), rgba(255,255,255,.018)); border:1px solid var(--line); border-top-color:var(--line-2); box-shadow: inset 0 1px 0 rgba(255,255,255,.05), 0 22px 48px -30px rgba(0,0,0,.85); backdrop-filter:blur(12px); -webkit-backdrop-filter:blur(12px); } +.glass-hover{ transition:transform .28s cubic-bezier(.2,.7,.2,1), border-color .28s, box-shadow .28s; } +.glass-hover:hover{ transform:translateY(-3px); border-color:rgba(47,214,192,.40); box-shadow: inset 0 1px 0 rgba(255,255,255,.07), 0 0 0 1px rgba(47,214,192,.14), 0 26px 60px -28px rgba(47,214,192,.30), 0 22px 48px -30px rgba(0,0,0,.85); } +.brand-glyph{ background:var(--grad); box-shadow: inset 0 1px 0 rgba(255,255,255,.4), 0 8px 18px -8px rgba(124,108,242,.65); color:#06121a; } +.btn-brand{ background-image:var(--grad) !important; box-shadow:0 10px 30px -12px rgba(124,108,242,.7), 0 6px 18px -10px rgba(47,214,192,.5) !important; border-color:transparent !important; } +.btn-brand:hover{ filter:brightness(1.06); } +.util-track{ height:6px; border-radius:999px; overflow:hidden; background:rgba(255,255,255,.06); box-shadow:inset 0 1px 2px rgba(0,0,0,.55); } +.util-track > .bg-emerald-400{ background:linear-gradient(90deg,#13a07d,#2FD6C0) !important; box-shadow:0 0 12px rgba(47,214,192,.6); } +.util-track > .bg-amber-400{ background:linear-gradient(90deg,#b9791d,#F2B84B) !important; box-shadow:0 0 12px rgba(242,184,75,.55); } +.util-track > .bg-rose-400{ background:linear-gradient(90deg,#9f1239,#fb7185) !important; box-shadow:0 0 12px rgba(251,113,133,.55); } +.util-track > .bg-zinc-600{ background:rgba(255,255,255,.20) !important; } + +/* arbor-life-v1 — ambient motion layered on already-visible elements only */ +.display-title{ background-size:220% 100%; animation: arborTitleShift 9s ease-in-out infinite alternate; } +@keyframes arborTitleShift{ from{ background-position:0% 50% } to{ background-position:100% 50% } } +body::before{ animation: arborAuroraDrift 30s ease-in-out infinite alternate; } +@keyframes arborAuroraDrift{ from{ transform:translate3d(0,0,0) scale(1) } to{ transform:translate3d(-1.5%,1.2%,0) scale(1.07) } } +@media (prefers-reduced-motion: reduce){ .display-title, body::before{ animation:none !important; } } +/* arbor-refine-v1 — solid display cut + accent rule, structural field, micro-feedback */ +.display-title{ + background-image:none !important; + -webkit-background-clip:border-box !important; + background-clip:border-box !important; + color:#F4F6FA !important; + -webkit-text-fill-color:#F4F6FA !important; + font-weight:700; + letter-spacing:-0.035em; + line-height:1.0; + position:relative; + padding-left:0.85rem; +} +.display-title::before{ + content:""; + position:absolute; left:0; top:0.10em; bottom:0.10em; width:4px; + border-radius:2px; + background:var(--grad); + box-shadow:0 0 14px rgba(47,214,192,.45); +} +body{ + background-image: + linear-gradient(to right, rgba(255,255,255,.022) 1px, transparent 1px), + linear-gradient(to bottom, rgba(255,255,255,.022) 1px, transparent 1px); + background-size:46px 46px, 46px 46px; + background-attachment:fixed, fixed; +} +.glass{ transition:border-color .3s ease, box-shadow .3s ease; } +.glass:not(.glass-hover):hover{ border-color:rgba(255,255,255,.14); box-shadow:inset 0 1px 0 rgba(255,255,255,.06), 0 24px 52px -30px rgba(0,0,0,.9); } +.btn-brand{ transition:transform .12s ease, filter .2s ease, box-shadow .2s ease; } +.btn-brand:active{ transform:scale(.97); } +a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible{ + outline:none; + box-shadow:0 0 0 2px rgba(7,10,15,.95), 0 0 0 4px rgba(47,214,192,.55); +} +.util-track > div{ transition:width .7s cubic-bezier(.2,.7,.2,1); } + + +/* arbor-type-v1 — distinctive display + readable body via next/font vars */ +body{ font-family: var(--font-body, "Manrope", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif); } +.display-title, h1, h2, .section-h{ font-family: var(--font-display, "Space Grotesk", "Sora", ui-sans-serif, system-ui, sans-serif); } + +/* arbor-reveal-v1 — scroll entrances; visible unless armed by RevealObserver */ +.reveal-armed .reveal{ opacity:0; transform:translateY(16px); transition:opacity .7s cubic-bezier(.2,.7,.2,1), transform .7s cubic-bezier(.2,.7,.2,1); } +.reveal-armed .reveal.is-in{ opacity:1; transform:none; } +.reveal-armed .reveal[data-rd="1"]{ transition-delay:.08s; } +.reveal-armed .reveal[data-rd="2"]{ transition-delay:.16s; } +@media (prefers-reduced-motion: reduce){ .reveal-armed .reveal{ opacity:1 !important; transform:none !important; transition:none !important; } } +/* arbor-surfaces-v1 — CDN-proof dark surfaces (Play CDN drops opacity on arbitrary hex) */ +.arbor-surface{background:rgba(7,10,18,.82);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);} +.arbor-surface-solid{background:#070a12;} +.arbor-popover{background:rgba(11,15,26,.96);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);} +/* arbor-scrim-v1 — dims the page behind the open mobile drawer (hand CSS, CDN-proof) */ +.arbor-scrim{background:rgba(2,4,8,.62);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);} +/* arbor-mark-v1 — ambient brand glow behind the transparent header tree */ +.arbor-mark{filter:drop-shadow(0 1px 0 rgba(255,255,255,.22)) drop-shadow(0 0 9px rgba(47,214,192,.40)) drop-shadow(0 0 16px rgba(124,108,242,.30));} +/* arbor-roles-v1 — on-chain role badges; brand color = role meaning */ +.role-badge{display:inline-flex;align-items:center;gap:.3rem;border-radius:999px;padding:.15rem .55rem;font-size:10px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;border:1px solid;white-space:nowrap;} +.role-authority{color:#F2B84B;border-color:rgba(242,184,75,.35);background:rgba(242,184,75,.10);} +.role-oracle{color:#2FD6C0;border-color:rgba(47,214,192,.35);background:rgba(47,214,192,.10);} +.role-public{color:#9AA4B2;border-color:rgba(255,255,255,.12);background:rgba(255,255,255,.05);} diff --git a/frontend/src/app/governance/page.tsx b/frontend/src/app/governance/page.tsx new file mode 100644 index 0000000000..812715f083 --- /dev/null +++ b/frontend/src/app/governance/page.tsx @@ -0,0 +1,325 @@ +"use client"; + +import Link from "next/link"; +import { useMarkets } from "@/lib/hooks/useMarkets"; +import { TIER_PARAMS } from "@/lib/arbor/constants"; +import { getGovernanceParams } from "@/lib/canopy/pluginRpc"; +import { useEffect, useState } from "react"; + +type Tone = "emerald" | "amber" | "zinc"; +const toneCls: Record = { + emerald: "bg-emerald-500/15 text-emerald-300", + amber: "bg-amber-500/15 text-amber-300", + zinc: "bg-zinc-500/15 text-zinc-400", +}; + +function Pill({ tone, label }: { tone: Tone; label: string }) { + return ( + + {label} + + ); +} + +interface ParamRow { + name: string; + value: string; + bounds: string; + tone: Tone; + status: string; + action: string; + editable?: boolean; +} + +export default function GovernancePage() { + const { data: markets } = useMarkets(); + const list = markets ?? []; + + const [gov, setGov] = useState<{ treasuryCutBps: bigint } | null>(null); + useEffect(() => { + let alive = true; + getGovernanceParams().then((g) => { if (alive) setGov(g); }); + return () => { alive = false; }; + }, []); + + const reserveFactors = list.map((e) => ({ + id: e.market.marketId, + bps: Number(e.market.reserveFactorBps), + })); + const reserveSummary = reserveFactors.length + ? reserveFactors.map((r) => `${r.id}: ${(r.bps / 100).toFixed(2)}%`).join(" · ") + : "per-market"; + + const tierAssets = (t: number): string => + Array.from( + new Set( + list + .filter((e) => e.market.assetTier === t) + .map((e) => e.market.collateralAssetId) + ) + ).join(", ") || "—"; + + const params: ParamRow[] = [ + { + name: "RESERVE_FACTOR", + value: `Per-market · ${reserveSummary}`, + bounds: "2% – 30% (200–3000 bps)", + tone: "emerald", + status: "Enforced per-market", + action: "update_market_params", + editable: true, + }, + { + name: "LIQUIDATION_CLOSE_FACTOR", + value: "Dynamic: 30% / 60% / 100% by HF", + bounds: "HF-tiered (ARCM §7)", + tone: "emerald", + status: "Enforced (dynamic)", + action: "hardcoded · close_factor.go", + }, + { + name: "LIQUIDATION_INCENTIVE_FACTOR", + value: "Per-tier: 1.030 / 1.036 / 1.050 / 1.090", + bounds: "per asset tier", + tone: "emerald", + status: "Enforced per-tier", + action: "hardcoded · tier_params.go", + }, + { + name: "LIQUIDATION_THRESHOLD (HF)", + value: "HF ≤ 1.0", + bounds: "ARCM §5 boundary", + tone: "emerald", + status: "Enforced", + action: "hardcoded · health_factor.go", + }, + { + name: "MAX_LTV (tier 0–3)", + value: "80% / 75% / 65% / 40%", + bounds: "per asset tier", + tone: "emerald", + status: "Enforced per-tier", + action: "hardcoded · tier_params.go", + }, + { + name: "ORACLE_STALENESS_THRESHOLD", + value: "30 blocks", + bounds: "placeholder for per-tier 50/30/20/10", + tone: "amber", + status: "Enforced (default)", + action: "hardcoded · price_resolve.go", + }, + { + name: "MIN_REPORTERS (oracle quorum)", + value: "1 (devnet override)", + bounds: "ARCM spec = 3", + tone: "amber", + status: "Enforced (devnet override)", + action: "hardcoded · price_resolve.go", + }, + { + name: "MIN_DEPOSIT", + value: "Not enforced", + bounds: "AYIS §13: 1 CNPY (1–100), pending NUSD", + tone: "amber", + status: "Not enforced", + action: "deferred · deposit.go", + }, + { + name: "BORROW_CAP", + value: "None", + bounds: "—", + tone: "zinc", + status: "Not implemented", + action: "—", + }, + { + name: "SUPPLY_CAP", + value: "None", + bounds: "—", + tone: "zinc", + status: "Not implemented", + action: "—", + }, + { + name: "TREASURY_CUT", + value: gov ? Number(gov.treasuryCutBps) + " bps" : "…", + bounds: "25–150 bps (checked at DeliverTx)", + tone: "emerald", + status: "Enforced (live {22})", + action: "set_treasury_cut", + }, + { + name: "CIRCUIT_BREAKER_DEVIATION", + value: "Not implemented", + bounds: "ARCM Rule 4 deferred", + tone: "zinc", + status: "Not implemented", + action: "— · {20} has no writer", + }, + { + name: "DUST_CLAMP_THRESHOLD", + value: "Values rounding to zero", + bounds: "no explicit constant", + tone: "emerald", + status: "Enforced (events on clamp)", + action: "implicit", + }, + ]; + + const tiers = [0, 1, 2, 3].map((t) => { + const p = TIER_PARAMS[t] ?? { ltvMaxBps: 0n, ltvLiqBps: 0n, lifBps: 0n }; + return { + tier: t, + maxLtv: Number(p.ltvMaxBps) / 100, + liqLtv: Number(p.ltvLiqBps) / 100, + lif: Number(p.lifBps) / 10000, + assets: tierAssets(t), + }; + }); + + const closeFactorTiers = [ + { range: "HF > 0.95", factor: "30%", bps: "3000 bps", tone: "emerald" as Tone }, + { range: "0.85 < HF ≤ 0.95", factor: "60%", bps: "6000 bps", tone: "amber" as Tone }, + { range: "HF ≤ 0.85", factor: "100%", bps: "10000 bps", tone: "zinc" as Tone }, + ]; + + return ( +
+
+

+ Governance parameters +

+

+ Protocol parameters and their on-chain status. The governance parameter + store ({"{22}"}) now holds treasury_cut_bps on-chain (live row below); the remaining values are still the hardcoded; the values below are the hardcoded + launch defaults enforced directly in the contract code, with bounds where + the code enforces them. RESERVE_FACTOR (per-market) and TREASURY_CUT (global) have live on-chain governance + action today. +

+
+ +
+

+ Parameters +

+
+ + + + + + + + + + + + {params.map((p) => ( + + + + + + + + ))} + +
ParameterCurrent valueBoundsStatusAction
+ {p.name} + {p.value}{p.bounds} + + + {p.editable ? ( + + Edit (Admin) + + ) : ( + {p.action} + )} +
+
+
+ +
+
+

+ Asset tiers +

+
+ + + + + + + + + + + + {tiers.map((t) => ( + + + + + + + + ))} + +
TierMax LTVLiq LTVLIFAssets (live)
Tier {t.tier} + {t.maxLtv.toFixed(0)}% + + {t.liqLtv.toFixed(0)}% + + {t.lif.toFixed(3)} + + {t.assets} +
+

+ From tier_params.go. Tier 4 (Blacklisted) is never stored — an asset + with no {"{29}"} registry entry is ineligible, not Tier 4. Asset + column reflects collateral assets of live markets. +

+
+
+ +
+

+ Liquidation close-factor curve +

+
+
+ {closeFactorTiers.map((c) => ( +
+ {c.range} + + + {c.factor} + + + +
+ ))} +
+

+ ARCM §7 dynamic close factor (close_factor.go): the fraction of a + liquidatable position's debt a liquidator may repay, tiered by how + far underwater the position is. Max repay = current debt × close + factor. +

+
+
+
+
+ ); +} diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx new file mode 100644 index 0000000000..2d48f80c71 --- /dev/null +++ b/frontend/src/app/layout.tsx @@ -0,0 +1,49 @@ +import type { Metadata } from "next"; +import "./globals.css"; +import { Providers } from "@/components/layout/Providers"; +import { Header } from "@/components/layout/Header"; +import { TxSubmissionTracker } from "@/components/widgets/TxSubmissionTracker"; +import { FirstTimeExplainer } from "@/components/widgets/FirstTimeExplainer"; +import { Space_Grotesk, Manrope } from "next/font/google"; +/* arbor-fonts */ +const arborDisplay = Space_Grotesk({ subsets: ["latin"], variable: "--font-display", display: "swap" }); +const arborBody = Manrope({ subsets: ["latin"], variable: "--font-body", display: "swap" }); + +export const metadata: Metadata = { + metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL || "http://localhost:3000"), + title: "ARBOR — Smart Lending Protocol", + description: "Isolated ARBOR lending markets on Canopy — supply, borrow, and liquidate against live on-chain oracle prices, with real health factors and the protocol bad-debt waterfall.", + openGraph: { title: "ARBOR — Smart Lending Protocol", description: "Isolated ARBOR lending markets on Canopy — live oracle prices, real health factors, on-chain risk monitor.", images: ["/logo-seal.svg"] }, + icons: { icon: "/logo-seal.svg", apple: "/logo-seal.svg" }, +}; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + {/* eslint-disable-next-line @next/next/no-sync-scripts */} + {/* eslint-disable-next-line @next/next/no-sync-scripts */} + + + + +
+ + +
{children}
+ +
+ +
+ + + + ); +} diff --git a/frontend/src/app/link/page.tsx b/frontend/src/app/link/page.tsx new file mode 100644 index 0000000000..4491090f07 --- /dev/null +++ b/frontend/src/app/link/page.tsx @@ -0,0 +1,137 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { useWalletStore } from "@/lib/stores/walletStore"; +import { signBls12381, bytesToHex } from "@/lib/wallet/signer"; +import { queryHeight } from "@/lib/canopy/rpc"; +import { linkIdentity } from "@/lib/quest/api"; + +interface SessionStatus { + discordId: string | null; + discordUsername: string | null; + twitterHandle: string | null; +} + +export default function LinkPage() { + const { address, publicKeyHex, privateKeyHex, isConnected } = useWalletStore(); + const [session, setSession] = useState(null); + const [linking, setLinking] = useState(false); + const [result, setResult] = useState<{ ok: boolean; message: string } | null>(null); + + useEffect(() => { + fetch("/api/auth/session") + .then((r) => r.json()) + .then(setSession) + .catch(() => setSession({ discordId: null, discordUsername: null, twitterHandle: null })); + }, []); + + const discordDone = !!session?.discordId; + const twitterDone = !!session?.twitterHandle; + const readyToLink = isConnected && discordDone && twitterDone; + + async function handleLink() { + if (!address || !publicKeyHex || !privateKeyHex || !session?.discordId || !session?.twitterHandle) return; + setLinking(true); + setResult(null); + try { + const height = await queryHeight(); + if (!height) throw new Error("Could not reach Arbor node to fetch current height"); + + const message = `Link Arbor identity\ndiscord:${session.discordId}\ntwitter:${session.twitterHandle}\nissuedAt:${height}`; + const signature = signBls12381(new TextEncoder().encode(message), privateKeyHex); + const signatureHex = bytesToHex(signature); + + const res = await linkIdentity({ + address, + publicKeyHex, + discordId: session.discordId, + twitterHandle: session.twitterHandle, + issuedAtHeight: height, + signatureHex, + }); + + if (res.ok) { + setResult({ ok: true, message: "Linked! Your quest completions will now be tracked." }); + } else { + setResult({ ok: false, message: res.error ?? "Linking failed." }); + } + } catch (err) { + setResult({ ok: false, message: err instanceof Error ? err.message : "Something went wrong." }); + } finally { + setLinking(false); + } + } + + return ( +
+
Link Your Identity
+

Connect for Quests

+

+ Link your Discord and X accounts to your wallet to start earning quest XP. + This is a one-time signature — your wallet never leaves your browser. +

+ +
+
+
+
Wallet
+
+ {isConnected ? `${address?.slice(0, 8)}...${address?.slice(-6)}` : "Not connected"} +
+
+ {!isConnected && ( + Connect wallet first + )} +
+ +
+
+
Discord
+
+ {discordDone ? `Connected as ${session?.discordUsername}` : "Not connected"} +
+
+ {!discordDone && ( + + Connect + + )} +
+ +
+
+
X (Twitter)
+
+ {twitterDone ? `Connected as ${session?.twitterHandle}` : "Not connected"} +
+
+ {!twitterDone && ( + + Connect + + )} +
+
+ + + + {result && ( +
+ {result.message} +
+ )} +
+ ); +} diff --git a/frontend/src/app/liquidate/page.tsx b/frontend/src/app/liquidate/page.tsx new file mode 100644 index 0000000000..fa8329b03c --- /dev/null +++ b/frontend/src/app/liquidate/page.tsx @@ -0,0 +1,323 @@ +"use client"; + +import { useEffect, useState } from "react"; +import Link from "next/link"; +import { useQuery } from "@tanstack/react-query"; +import { useMarkets } from "@/lib/hooks/useMarkets"; +import { useAssetPrice } from "@/lib/hooks/useAssetPrice"; +import { + getAllBorrowerPositions, + type BorrowerPositionSummary, +} from "@/lib/canopy/pluginRpc"; +import { computeHealthFactorScaled } from "@/lib/arbor/math"; +import { formatAmount, formatHealthFactor } from "@/lib/arbor/format"; +import { + TIER_PARAMS, + HF_LIQUIDATABLE_SCALED, + STATE_REFRESH_INTERVAL_MS, +} from "@/lib/arbor/constants"; +import { bytesToHex } from "@/lib/canopy/decode"; +import type { Market } from "@/lib/arbor/types"; + +type PosMetric = { + debtUsd: number; + collUsd: number; + liquidatable: boolean; + priced: boolean; +}; + +function fmtUsd(n: number | null): string { + if (n === null || !Number.isFinite(n)) return "—"; + if (n >= 1_000_000) return `$${(n / 1_000_000).toFixed(2)}M`; + if (n >= 1_000) return `$${(n / 1_000).toFixed(2)}K`; + if (n >= 1) return `$${n.toFixed(2)}`; + if (n > 0) return `$${n.toFixed(6)}`; + return "$0.00"; +} + +function shortAddr(hex: string): string { + if (hex.length <= 12) return hex; + return `0x${hex.slice(0, 6)}…${hex.slice(-4)}`; +} + +function PositionRow({ + p, + market, + report, +}: { + p: BorrowerPositionSummary; + market: Market | undefined; + report: (key: string, m: PosMetric) => void; +}) { + const collAsset = market?.collateralAssetId ?? null; + const debtAsset = market?.debtAssetId ?? null; + const { data: collPrice } = useAssetPrice(collAsset); + const { data: debtPrice } = useAssetPrice(debtAsset); + const tier = market ? TIER_PARAMS[market.assetTier] : undefined; + + const pricesOk = + !!market && + !!tier && + !!collPrice?.available && + !!debtPrice?.available && + collPrice.price != null && + debtPrice.price != null; + + const hf = pricesOk + ? computeHealthFactorScaled( + p.collateralQuantity, + collPrice!.price as bigint, + tier!.ltvLiqBps, + p.currentDebt, + debtPrice!.price as bigint + ) + : null; + + const noDebt = hf === 0n; + const liquidatable = hf != null && !noDebt && hf <= HF_LIQUIDATABLE_SCALED; + const debtUsd = pricesOk + ? Number(p.currentDebt) * (Number(debtPrice!.price) / 1e8) + : null; + const collUsd = pricesOk + ? Number(p.collateralQuantity) * (Number(collPrice!.price) / 1e8) + : null; + const hfActual = hf != null ? Number(hf) / 1e6 : null; + const closeFactorBps = + hfActual == null || noDebt ? null : hfActual > 0.95 ? 3000 : hfActual > 0.85 ? 6000 : 10000; + const lif = tier ? Number(tier.lifBps) / 10000 : null; + const distance = + hfActual == null + ? "No oracle" + : noDebt + ? "Safe" + : hfActual <= 1.0 + ? "Liquidatable" + : hfActual <= 1.2 + ? "At risk" + : "Safe"; + const distCls = + distance === "Liquidatable" + ? "bg-rose-500/15 text-rose-300" + : distance === "At risk" + ? "bg-amber-500/15 text-amber-300" + : distance === "Safe" + ? "bg-emerald-500/15 text-emerald-300" + : "bg-zinc-500/15 text-zinc-400"; + + const addrHex = bytesToHex(p.address); + const key = `${p.marketId}:${addrHex}`; + + useEffect(() => { + report(key, { + debtUsd: debtUsd ?? 0, + collUsd: collUsd ?? 0, + liquidatable, + priced: pricesOk, + }); + }, [report, key, debtUsd, collUsd, liquidatable, pricesOk]); + + return ( + + + {shortAddr(addrHex)} + + +

{p.marketId}

+

+ {market ? `${market.collateralAssetId}/${market.debtAssetId}` : "—"} +

+ + +

{fmtUsd(debtUsd)}

+

+ {formatAmount(p.currentDebt, 0)} {debtAsset ?? ""} +

+ + +

{fmtUsd(collUsd)}

+

+ {formatAmount(p.collateralQuantity, 0)} {collAsset ?? ""} +

+ + + {hf == null ? "—" : formatHealthFactor(hf)} + + + {liquidatable && closeFactorBps != null ? `${closeFactorBps / 100}%` : "—"} + + + {lif != null ? lif.toFixed(3) : "—"} + + + + {distance} + + + + {liquidatable && market ? ( + + Liquidate + + ) : ( + + )} + + + ); +} + +export default function LiquidationPage() { + const { data: positions, isLoading } = useQuery({ + queryKey: ["all-borrower-positions"], + queryFn: getAllBorrowerPositions, + refetchInterval: STATE_REFRESH_INTERVAL_MS, + staleTime: 20_000, + }); + const { data: marketsData } = useMarkets(); + + const marketMap: Record = {}; + (marketsData ?? []).forEach((e) => { + marketMap[e.market.marketId] = e.market; + }); + + const [metrics, setMetrics] = useState>({}); + const report = (key: string, m: PosMetric) => { + setMetrics((prev) => { + const old = prev[key]; + if ( + old && + old.debtUsd === m.debtUsd && + old.collUsd === m.collUsd && + old.liquidatable === m.liquidatable && + old.priced === m.priced + ) + return prev; + return { ...prev, [key]: m }; + }); + }; + + const list = positions ?? []; + const vals = Object.values(metrics); + const liquidatableCount = vals.filter((v) => v.liquidatable).length; + const pricedCount = vals.filter((v) => v.priced).length; + const unpricedCount = vals.filter((v) => !v.priced).length; + const totalDebtUsd = vals.reduce((a, v) => a + (v.priced ? v.debtUsd : 0), 0); + const totalCollUsd = vals.reduce((a, v) => a + (v.priced ? v.collUsd : 0), 0); + + return ( +
+
+

+ Liquidation dashboard +

+

+ Every borrower position on chain, joined to live oracle prices and the + market's tier parameters. Health factor uses the on-chain formula + (health_factor.go); close factor is dynamic by HF (close_factor.go); LIF + is per-tier. Executing a liquidation uses the Liquidate form on the + market page. +

+
+ +
+
+

Liquidatable positions

+

+ {liquidatableCount} +

+

+ {unpricedCount > 0 ? `${unpricedCount} unpriced (HF n/a)` : "all assessable"} +

+
+
+

Monitored positions

+

+ {list.length} +

+

{pricedCount} with oracle price

+
+
+

Total debt value

+

+ {fmtUsd(totalDebtUsd)} +

+

priced positions only

+
+
+

Total collateral value

+

+ {fmtUsd(totalCollUsd)} +

+

priced positions only

+
+
+ + {liquidatableCount === 0 && pricedCount > 0 && ( +

+ All {pricedCount} priced positions are healthy - none are currently below the liquidation threshold (HF <= 1.0). +

+ )} + +
+

+ Borrower positions +

+ {isLoading ? ( +

Loading positions…

+ ) : list.length === 0 ? ( +

+ No borrower positions on chain. +

+ ) : ( +
+ + + + + + + + + + + + + + + + {list.map((p) => ( + + ))} + +
PositionMarketDebt valueCollateral valueHFClose factorLIFDistanceAction
+
+ )} + {unpricedCount > 0 && ( +

+ {unpricedCount} position(s) use assets without an oracle price, so their + health factor cannot be computed and they are excluded from the dollar + totals. Post a price for those assets (Oracle page) to assess them. +

+ )} +

+ Bad-debt coverage (the 4-layer waterfall: borrower collateral → R_fund → + backstop → loss factor) is on the{" "} + + Monitor + {" "} + page. +

+
+
+ ); +} diff --git a/frontend/src/app/markets/[marketId]/page.tsx b/frontend/src/app/markets/[marketId]/page.tsx new file mode 100644 index 0000000000..ec86f1e092 --- /dev/null +++ b/frontend/src/app/markets/[marketId]/page.tsx @@ -0,0 +1,367 @@ +"use client"; +import { useState, type ReactNode } from "react"; +import { AssetIcon } from "@/components/AssetIcon"; + +import { useParams } from "next/navigation"; +import { useMarket } from "@/lib/hooks/useMarket"; +import { useWalletStore } from "@/lib/wallet"; +import { useLenderPosition } from "@/lib/hooks/useLenderPosition"; +import { useBorrowerPosition } from "@/lib/hooks/useBorrowerPosition"; +import { useAssetPrice } from "@/lib/hooks/useAssetPrice"; +import { Tooltip } from "@/components/ui/Tooltip"; +import { LiveDot } from "@/components/ui/LiveDot"; +import { EmptyState } from "@/components/widgets/EmptyState"; +import { LoadingSkeleton } from "@/components/widgets/LoadingSkeleton"; +import { StatusPill } from "@/components/widgets/StatusPill"; +import { DepositForm } from "@/components/forms/DepositForm"; +import { WithdrawForm } from "@/components/forms/WithdrawForm"; +import { DepositCollateralForm } from "@/components/forms/DepositCollateralForm"; +import { WithdrawCollateralForm } from "@/components/forms/WithdrawCollateralForm"; +import { BorrowForm } from "@/components/forms/BorrowForm"; +import { RepayForm } from "@/components/forms/RepayForm"; +import { LiquidateForm } from "@/components/forms/LiquidateForm"; +import { UpdatePriceForm } from "@/components/forms/UpdatePriceForm"; +import { MarketDetailTabs } from "@/components/sections/MarketDetailTabs"; +import { formatAmount, formatHealthFactor, formatRay } from "@/lib/arbor/format"; + +const BINDEX_BASE = 1000000000000000000000n; +function fmtIndex(v: bigint, base: bigint): string { + return (Number((v * 1000000n) / base) / 1000000).toFixed(6); +} +import { scaledDebt, computeHealthFactorScaled } from "@/lib/arbor/math"; +import { TIER_PARAMS } from "@/lib/arbor/constants"; + + + +// Local number-based rate helpers (mirror MarketDetailTabs kinked two-slope model). +const BPS_SCALE = 10000; +const U_OPTIMAL_BPS = 8000; +const BASE_RATE_BPS = 200; +const SLOPE1_BPS = 800; +const SLOPE2_BPS = 10000; + +function borrowRateBpsLocal(utilBps: number): number { + if (utilBps <= U_OPTIMAL_BPS) { + return BASE_RATE_BPS + (utilBps * SLOPE1_BPS) / U_OPTIMAL_BPS; + } + const excess = utilBps - U_OPTIMAL_BPS; + const remaining = BPS_SCALE - U_OPTIMAL_BPS; + return BASE_RATE_BPS + SLOPE1_BPS + (excess * SLOPE2_BPS) / remaining; +} + +function supplyRateBpsLocal(utilBps: number, reserveFactorBps: number): number { + const br = borrowRateBpsLocal(utilBps); + return (br * utilBps * (BPS_SCALE - reserveFactorBps)) / (BPS_SCALE * BPS_SCALE); +} + +function FormSection({ + symbol, + title, + blurb, + defaultOpen = false, + children, +}: { + symbol: string; + title: string; + blurb: string; + defaultOpen?: boolean; + children: ReactNode; +}) { + const [open, setOpen] = useState(defaultOpen); + return ( +
+ + {open && ( +
+ {children} +
+ )} +
+ ); +} + +export default function MarketPage() { + const params = useParams(); + + const marketId = + typeof params.marketId === "string" + ? params.marketId + : Array.isArray(params.marketId) + ? params.marketId[0] + : ""; + + const { data: marketData, isLoading } = useMarket(marketId || null); + const wallet = useWalletStore(); + + const { data: lenderPosition } = useLenderPosition( + marketId || null, + wallet.address + ); + + const { data: borrowerPosition } = useBorrowerPosition( + marketId || null, + wallet.address + ); + + const collateralAssetId = marketData?.market.collateralAssetId ?? null; + const debtAssetId = marketData?.market.debtAssetId ?? null; + + const { data: collateralPrice } = useAssetPrice(collateralAssetId); + const { data: debtPrice } = useAssetPrice(debtAssetId); + + if (!marketId) { + return ; + } + + if (isLoading) { + return ; + } + + if (!marketData) { + return ; + } + + const { market, bIndex, supplyIndex, lossFactor, reserveFund } = + marketData; + + const tier = TIER_PARAMS[market.assetTier]; + + const currentDebt = borrowerPosition + ? scaledDebt( + borrowerPosition.debtPrincipal, + bIndex, + borrowerPosition.borrowIndexAtOpen + ) + : 0n; + + const pricesAvailable = + !!collateralPrice?.available && + !!debtPrice?.available && + collateralPrice.price !== null && + debtPrice.price !== null; + + const hf = + tier && pricesAvailable && borrowerPosition + ? computeHealthFactorScaled( + borrowerPosition.collateralQuantity, + collateralPrice.price as bigint, + tier.ltvLiqBps, + currentDebt, + debtPrice.price as bigint + ) + : 0n; + + return ( +
+
+
+
+

+ {market.marketId} +

+

+ {market.collateralAssetId} collateral / {market.debtAssetId} debt +

+
+ + +
+ + {(() => { + const utilBps = market.totalSupplied > 0n + ? Number((market.totalBorrowed * 10000n) / market.totalSupplied) + : 0; + const reserveFactor = Number(market.reserveFactorBps); + const borrowApr = (borrowRateBpsLocal(utilBps) / 100).toFixed(2); + const supplyApr = (supplyRateBpsLocal(utilBps, reserveFactor) / 100).toFixed(2); + return ( +
+
+
+

What would I earn if I lend?

+

{supplyApr}% APR

+

Current supply yield at {Math.round(utilBps / 100)}% utilization

+
+
+

What would it cost me to borrow?

+

{borrowApr}% APR

+

Current borrow cost at {Math.round(utilBps / 100)}% utilization

+
+
+ +
+
+ Total supplied +

{formatAmount(market.totalSupplied, 0)}

+
+
+ Total borrowed +

{formatAmount(market.totalBorrowed, 0)}

+
+
+ Reserve fund +

{formatAmount(reserveFund, 0)}

+
+
+ +
+ Protocol internals +
+
+ S rate +

{formatRay(supplyIndex.sRate)}

+
+
+ B index +

{fmtIndex(bIndex, BINDEX_BASE)}×

+
+
+ Loss factor +

{formatRay(lossFactor)}

+
+
+ Layer4 pending +

{market.layer4PendingCount}

+
+
+
+
+ ); + })()} +
+ +
+

+ Your position +

+ + {!wallet.isConnected && ( +

+ Connect a wallet to view positions. +

+ )} + + {wallet.isConnected && ( +
+
+ Lender shares +

+ {formatAmount(lenderPosition?.shares ?? 0n, 0)} +

+
+ +
+ Collateral +

+ {formatAmount( + borrowerPosition?.collateralQuantity ?? 0n, + 0 + )} +

+
+ +
+ + Debt + + +

+ {formatAmount(currentDebt, 0)} +

+
+ +
+ Health factor + {pricesAvailable && borrowerPosition ? ( +
+ {hf === 0n ? ( + + No debt + + ) : ( + <> + = 1_100_000n ? 'bg-emerald-500/20 text-emerald-400' : + hf >= 1_000_000n ? 'bg-amber-500/20 text-amber-400' : + 'bg-red-500/20 text-red-400' + }`}> + {hf >= 1_100_000n ? 'Safe' : hf >= 1_000_000n ? 'Caution' : 'At risk'} + +
+
= 1_100_000n ? 'bg-emerald-500' : + hf >= 1_000_000n ? 'bg-amber-500' : + 'bg-red-500' + }`} + style={{ width: `${Math.min(100, Number(hf * 100n / 2_000_000n))}%` }} + /> +
+

{formatHealthFactor(hf)}

+ + )} +
+ ) : ( +

--

+ )} +
+
+ )} +
+ + + +
+ + + + + + + + + + + + + + + + +
+
+ ); +} diff --git a/frontend/src/app/monitor/page.tsx b/frontend/src/app/monitor/page.tsx new file mode 100644 index 0000000000..22afa45cd6 --- /dev/null +++ b/frontend/src/app/monitor/page.tsx @@ -0,0 +1,328 @@ +"use client"; + +import { useCallback, useEffect, useState } from "react"; +import { useMarkets, type MarketWithIndices } from "@/lib/hooks/useMarkets"; +import { useMarketPools } from "@/lib/hooks/useMarketPools"; +import { formatAmount } from "@/lib/arbor/format"; +import { getTreasury } from "@/lib/canopy/pluginRpc"; +import { RAY } from "@/lib/arbor/constants"; +import { useAssetPrice } from "@/lib/hooks/useAssetPrice"; + +function Flag({ bad }: { bad: boolean }) { + return bad ? ( + + + Yes + + ) : ( + + + No + + ); +} + +function LayerCard({ + layer, + title, + desc, + value, + sub, + tone, +}: { + layer: string; + title: string; + desc: string; + value: string; + sub?: string; + tone: "emerald" | "indigo" | "zinc" | "rose"; +}) { + const ring = + tone === "emerald" + ? "border-emerald-500/30 bg-emerald-500/[0.06]" + : tone === "indigo" + ? "border-indigo-500/30 bg-indigo-500/[0.06]" + : tone === "rose" + ? "border-rose-500/30 bg-rose-500/[0.06]" + : "border-white/10 bg-white/[0.03]"; + return ( +
+

+ {layer} +

+

{title}

+

+ {value} +

+ {sub &&

{sub}

} +

{desc}

+
+ ); +} + +function MarketRow({ + entry, + onCollateral, + onUsd, +}: { + entry: MarketWithIndices; + onCollateral: (id: string, v: bigint) => void; + onUsd: (id: string, suppliedUsd: number, rfUsd: number, collateralUsd: number) => void; +}) { + const m = entry.market; + const { data: pools } = useMarketPools(m.marketId); + const collateral = pools?.collateral ?? 0n; + const supply = pools?.supply ?? 0n; + + useEffect(() => { + onCollateral(m.marketId, collateral); + return () => onCollateral(m.marketId, 0n); + }, [onCollateral, m.marketId, collateral]); + + const { data: priceData } = useAssetPrice(m.debtAssetId); + const unitPrice = + priceData?.available && priceData.price != null + ? Number(priceData.price) / 1e8 + : null; + + const { data: collPriceData } = useAssetPrice(m.collateralAssetId); + const collUnitPrice = + collPriceData?.available && collPriceData.price != null + ? Number(collPriceData.price) / 1e8 + : null; + + useEffect(() => { + onUsd( + m.marketId, + unitPrice !== null ? Number(m.totalSupplied) * unitPrice : 0, + unitPrice !== null ? Number(entry.reserveFund) * unitPrice : 0, + collUnitPrice !== null ? Number(collateral) * collUnitPrice : 0 + ); + return () => onUsd(m.marketId, 0, 0, 0); + }, [onUsd, m.marketId, m.totalSupplied, entry.reserveFund, unitPrice, collateral, collUnitPrice]); + + +function renderLossFactor(entry: { lossFactor: bigint; lossFactorAbsent: boolean }, status: string) { + const RAY = 1000000000000000000n; + if (entry.lossFactorAbsent) { + return ; + } + if (entry.lossFactor === 0n) { + if (status === "INSOLVENT") { + return exhausted; + } + return exhausted ; + } + if (entry.lossFactor === RAY) { + return 1.000000; + } + const v = Number(entry.lossFactor) / 1e18; + return {v.toFixed(6)}; +} + + const tvl = m.totalSupplied; + const rfRatio = tvl > 0n ? Number((entry.reserveFund * 10000n) / tvl) / 100 : 0; + + return ( + + {m.marketId} + + + 0} /> + + + + {formatAmount(supply, 0)} + + + {formatAmount(collateral, 0)} + + + {formatAmount(entry.reserveFund, 0)} + + {renderLossFactor(entry, m.status)} + + {rfRatio.toFixed(1)}% + + + ); +} + +export default function MonitorPage() { + const { data: markets, isLoading } = useMarkets(); + const list = markets ?? []; + + const [collateralByMarket, setCollateralByMarket] = useState< + Record + >({}); + const onCollateral = useCallback( + (id: string, v: bigint) => setCollateralByMarket((p) => ({ ...p, [id]: v })), + [] + ); + + const [usdByMarket, setUsdByMarket] = useState< + Record + >({}); + const onUsd = useCallback( + (id: string, s: number, rf: number, coll: number) => + setUsdByMarket((p) => ({ ...p, [id]: { s, rf, c: coll } })), + [] + ); + const totalTvlUsd = Object.values(usdByMarket).reduce((a, v) => a + v.s, 0); + const totalRfUsd = Object.values(usdByMarket).reduce((a, v) => a + v.rf, 0); + const totalCollateralUsd = Object.values(usdByMarket).reduce((a, v) => a + v.c, 0); + const collateralBreakdown = list + .map((e) => ({ + v: collateralByMarket[e.market.marketId] ?? 0n, + a: e.market.collateralAssetId, + })) + .filter((x) => x.v > 0n) + .map((x) => `${formatAmount(x.v, 0)} ${x.a}`) + .join(" \u00b7 "); + + const totalRf = list.reduce((a, e) => a + e.reserveFund, 0n); + const [treasuryArbor, setTreasuryArbor] = useState(0n); + useEffect(() => { + let alive = true; + getTreasury("arbor").then((t) => { if (alive) setTreasuryArbor(t.amount); }); + return () => { alive = false; }; + }, []); + const totalTvl = list.reduce((a, e) => a + e.market.totalSupplied, 0n); + const totalCollateral = Object.values(collateralByMarket).reduce( + (a, b) => a + b, + 0n + ); + const l4PendingBacklog = list.reduce( + (a, e) => a + e.market.layer4PendingCount, + 0 + ); + const l4Haircuted = list.filter((e) => e.lossFactor < RAY).length; + const coverageRatio = + totalTvl > 0n ? Number((totalRf * 10000n) / totalTvl) / 100 : 0; + + return ( +
+
+

+ Reserve & risk monitor +

+

+ Bad‑debt waterfall, reserve adequacy, and per‑market risk flags — read + live from the ARBOR plugin's custom queries. +

+
+ +
+

+ 4‑layer bad‑debt waterfall +

+
+ + + 0n ? "indigo" : "zinc"} + /> + 0 ? `${l4PendingBacklog} pending` : l4Haircuted > 0 ? `${l4Haircuted} applied` : "0"}`} + tone={l4PendingBacklog > 0 || l4Haircuted > 0 ? "rose" : "zinc"} + /> +
+
+ +
+
+

Total R_fund

+

+ ${totalRfUsd.toLocaleString(undefined, { maximumFractionDigits: 2 })} +

+

+ {formatAmount(totalRf, 0)} native +

+
+
+

Total TVL (supplied)

+

+ ${totalTvlUsd.toLocaleString(undefined, { maximumFractionDigits: 2 })} +

+

+ {formatAmount(totalTvl, 0)} native +

+
+
+

R_fund / TVL coverage

+

+ {coverageRatio.toFixed(1)}% +

+
+
+ +
+

+ Per‑market risk flags & reserves +

+ {isLoading ? ( +

Loading markets…

+ ) : list.length === 0 ? ( +

+ No markets on chain yet. +

+ ) : ( +
+ + + + + + + + + + + + + + + + + + {list.map((entry) => ( + + ))} + +
MarketInsolventIdx overflowL4PausedDeprecatedSupply poolCollat. poolR_fundLoss factorR_fund/TVL
+
+ )} +

+ Amounts in whole units. Supply/collateral pools from + /v1/query/pool; R_fund from /v1/query/reservefund; loss factor from + /v1/query/lossfactor (RAY = 1.0, no haircut). +

+
+
+ ); +} diff --git a/frontend/src/app/nusd/page.tsx b/frontend/src/app/nusd/page.tsx new file mode 100644 index 0000000000..a9a43c26e7 --- /dev/null +++ b/frontend/src/app/nusd/page.tsx @@ -0,0 +1,338 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { useMarkets } from "@/lib/hooks/useMarkets"; +import { useWalletStore } from "@/lib/wallet"; +import { + getNusdSupply, + getStabilityFeeIndex, + getNasmTier, + getNusdBalance, + getTreasury, + getNasmVaultPool, + getAllNasmVaults, +} from "@/lib/canopy/pluginRpc"; +import { formatAmount } from "@/lib/arbor/format"; +import { MintNusdForm } from "@/components/forms/MintNusdForm"; +import { BurnNusdForm } from "@/components/forms/BurnNusdForm"; +import { LiquidateNasmVaultForm } from "@/components/forms/LiquidateNasmVaultForm"; +import { AssetIcon } from "@/components/AssetIcon"; +import { useNasmTierBacking } from "@/lib/hooks/useNasmVault"; + +const RAY = 1000000000000000000n; + +function fmtBps(bps: bigint): string { + return (Number(bps) / 100).toFixed(2) + "%"; +} + + +function NasmVaults() { + const wallet = useWalletStore(); + const [rows, setRows] = useState; pool: bigint }>>([]); + const [loading, setLoading] = useState(false); + const [refreshKey, setRefreshKey] = useState(0); + const refetch = () => setRefreshKey((k) => k + 1); + + useEffect(() => { + if (!wallet.address) return; + let alive = true; + getAllNasmVaults(wallet.address).then(async (list) => { + const withPool = await Promise.all( + list.map(async (v) => { + const p = await getNasmVaultPool(String(v.vaultId ?? "")); + return { v, pool: p?.amount ?? 0n }; + }) + ); + if (alive) { setRows(withPool); setLoading(false); } + }); + return () => { alive = false; }; + }, [wallet.address, refreshKey]); + + return ( +
+

Mint & manage NUSD

+
+ + + +
+ +

Your Vaults

+

+ Vaults owned by the connected wallet, enumerated live via + /v1/query/all-nasm-vaults?owner=… Collateral and minted NUSD principal come + from each NasmVault record; escrowed collateral from nasmvaultpool. +

+ {!wallet.address ? ( +
+ Connect a wallet to view your vaults. +
+ ) : loading ? ( +

Loading vaults…

+ ) : rows.length === 0 ? ( +
+ No NUSD vaults found for this address. +
+ ) : ( +
+ + + + + + + + + + + {rows.map(({ v, pool }) => ( + + + + + + + ))} + +
VaultCollateralEscrowedNUSD principal
{String(v.vaultId)} + + + {formatAmount(BigInt(String(v.collateralQuantity ?? "0")), 0)} {String(v.collateralAssetId ?? "")} + + {formatAmount(pool, 0)}{formatAmount(BigInt(String(v.nusdPrincipal ?? "0")), 6)}
+
+ )} +
+ ); +} + +export default function NusdPage() { + const wallet = useWalletStore(); + const { data: markets } = useMarkets(); + const [supply, setSupply] = useState(null); + const [sfi, setSfi] = useState<{ sfIndexDecimal: bigint; lastAccrualBlock: number } | null>(null); + const [treasury, setTreasury] = useState(null); + const [balance, setBalance] = useState(null); + const [tiers, setTiers] = useState< + Record + >({}); + + useEffect(() => { + let alive = true; + getNusdSupply().then((s) => { if (alive) setSupply(s.totalSupply); }); + getStabilityFeeIndex().then((v) => { if (alive) setSfi(v); }); + getTreasury("nasm").then((t) => { if (alive) setTreasury(t.amount); }); + return () => { alive = false; }; + }, []); + + useEffect(() => { + if (!wallet.address) return; + let alive = true; + getNusdBalance(wallet.address).then((b) => { if (alive) setBalance(b.amount); }); + return () => { alive = false; }; + }, [wallet.address]); + + const assetIds = Array.from( + new Set([ + ...(markets ?? []).flatMap((e) => [e.market.collateralAssetId, e.market.debtAssetId]), + "eth", "CNPY", "usdc", + ]) + ); + + useEffect(() => { + let alive = true; + Promise.all(assetIds.map((a) => getNasmTier(a))).then((rs) => { + if (!alive) return; + const map: Record = {}; + for (const r of rs) map[r.assetId] = r; + setTiers(map); + }); + return () => { alive = false; }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [JSON.stringify(assetIds)]); + + const sfMult = sfi ? Number((sfi.sfIndexDecimal * 1000000n) / RAY) / 1000000 : null; + const feePct = sfMult != null ? (sfMult - 1) * 100 : null; + + return ( +
+
+

+ Arbor stablecoin · NASM +

+
+
+

NUSD

+

+ The ARBOR-native stablecoin, minted against NASM-tier collateral via vaults. A + stability fee accrues to every minted position each block; the NASM treasury is + fully isolated from Arbor lending's. +

+
+
+

Total supply

+

+ {supply != null ? formatAmount(supply, 6) : "—"} + NUSD +

+
+
+
+ +
+
+

NUSD supply

+

+ {supply != null ? formatAmount(supply, 6) : "—"} +

+

1e6 precision

+
+
+

+ Stability fee index + + + + +

+

+ {sfMult != null ? sfMult.toFixed(6) + "×" : "—"} +

+

+ {feePct != null ? "+" + feePct.toFixed(6) + "% accrued · " : ""} + {sfi ? "block " + sfi.lastAccrualBlock : "accruing per block"} +

+
+
+

NASM treasury {"{41}"}

+

+ {treasury != null ? formatAmount(treasury, 6) : "—"} +

+

isolated from Arbor {"{40}"}

+
+
+

Your NUSD balance

+

+ {wallet.address ? (balance != null ? formatAmount(balance, 6) : "—") : "connect wallet"} +

+

+ {wallet.address ? "held by this address" : "to view your balance"} +

+
+
+ +
+

NASM tier eligibility

+

+ Which assets may back NUSD minting, at NASM's tighter LTV table (bridged from + ARCM's {"{29}"} registry). Tier 2/3 assets are not eligible. +

+
+ + + + + + + + + + + + {assetIds.map((a) => { + const t = tiers[a]; + return ( + + + + + + + + ); + })} + +
AssetNASM tierMax LTVLiq LTVEligible
+ + + {a} + + {t ? (t.eligible ? t.nasmTier : "—") : "…"}{t && t.eligible ? fmtBps(t.ltvMaxBps) : "—"}{t && t.eligible ? fmtBps(t.ltvLiqBps) : "—"} + {t ? ( + t.eligible ? ( + eligible + ) : ( + not eligible + ) + ) : ( + + )} +
+
+

+ Vault-level detail (per-vault collateral and minted NUSD) needs a vault id; the plugin + exposes /v1/query/nasmvault and /v1/query/nasmvaultpool per vault, but there is no route + to enumerate all vaults yet. Total supply and per-address balances above are live. +

+
+ + + +
+ ); +} + +// NASM Spec Section 3.3: no single NASM tier (N-0 or N-1) may back more +// than maxTierShareBps of total NUSD supply. Shown proactively here so a +// mint that would breach the cap can be avoided before submitting, rather +// than only discovered via the on-chain rejection (error 258). +function NasmTierConcentrationCap() { + const { data, isLoading } = useNasmTierBacking(); + + const maxBps = data?.maxTierShareBps ?? 7000n; + + const rows = [ + { label: "Tier N-0", backing: data?.tierN0Backing ?? 0n, shareBps: data?.tierN0ShareBps ?? 0n }, + { label: "Tier N-1", backing: data?.tierN1Backing ?? 0n, shareBps: data?.tierN1ShareBps ?? 0n }, + ]; + + return ( +
+

NASM tier concentration cap

+

+ No single NASM tier may back more than {fmtBps(maxBps)} of total NUSD supply (Spec + Section 3.3). A mint that would push a tier over this line is rejected on-chain. +

+
+ {rows.map((r) => { + const pct = Number(r.shareBps) / 100; + const capPct = Number(maxBps) / 100; + const overCap = Number(r.shareBps) >= Number(maxBps); + const nearCap = !overCap && Number(r.shareBps) >= Number(maxBps) * 0.9; + return ( +
+
+ {r.label} + + {isLoading ? "…" : `${formatAmount(r.backing, 6)} NUSD · ${pct.toFixed(2)}% of ${capPct.toFixed(0)}% cap`} + +
+
+
+
+ {overCap && ( +

At or above cap — mints into this tier will be rejected.

+ )} + {nearCap && ( +

Approaching cap — headroom is limited.

+ )} +
+ ); + })} +
+
+ ); +} diff --git a/frontend/src/app/oracle/page.tsx b/frontend/src/app/oracle/page.tsx new file mode 100644 index 0000000000..2a6fcac6fb --- /dev/null +++ b/frontend/src/app/oracle/page.tsx @@ -0,0 +1,235 @@ +"use client"; +import { AssetIcon } from "@/components/AssetIcon"; + +import { useState } from "react"; +import { useQuery } from "@tanstack/react-query"; +import { useMarkets } from "@/lib/hooks/useMarkets"; +import { useAssetPrice } from "@/lib/hooks/useAssetPrice"; +import { getAllPrices } from "@/lib/canopy/pluginRpc"; +import { useBlockHeight } from "@/lib/hooks/useChainStatus"; +import { UpdatePriceForm } from "@/components/forms/UpdatePriceForm"; +import { EmptyState } from "@/components/widgets/EmptyState"; +import { LoadingSkeleton } from "@/components/widgets/LoadingSkeleton"; +import { SelectInput } from "@/components/forms/FormPrimitives"; +import { formatAmount } from "@/lib/arbor/format"; +import { + PRICE_DECIMALS, + DEFAULT_STALENESS_BLOCKS, + MIN_REPORTERS, + STATE_REFRESH_INTERVAL_MS, +} from "@/lib/arbor/constants"; + +function statusFor(age: bigint): { label: string; cls: string } { + if (age <= BigInt(DEFAULT_STALENESS_BLOCKS)) { + return { label: "Fresh", cls: "bg-emerald-500/15 text-emerald-300" }; + } + if (age <= 300n) { + return { label: "Stale", cls: "bg-amber-500/15 text-amber-300" }; + } + return { label: "Expired", cls: "bg-rose-500/15 text-rose-300" }; +} + +function shortAddr(b: Uint8Array): string { + const hex = Array.from(b) + .map((x) => x.toString(16).padStart(2, "0")) + .join(""); + return hex.length > 12 ? `${hex.slice(0, 6)}…${hex.slice(-4)}` : hex || "—"; +} + +function PriceFreshnessTable({ assetId }: { assetId: string }) { + const { data: height } = useBlockHeight(); + const { data: records, isLoading } = useQuery({ + queryKey: ["price-records", assetId], + queryFn: () => getAllPrices(assetId), + refetchInterval: STATE_REFRESH_INTERVAL_MS, + staleTime: 20_000, + }); + + if (isLoading) return

Loading…

; + if (!records || records.length === 0) { + return

No submissions for {assetId}.

; + } + + return ( +
+ + + + + + + + + + + {records.map((r, i) => { + const age = + height != null ? BigInt(height) - r.blockHeight : 0n; + const st = statusFor(age < 0n ? 0n : age); + return ( + + + + + + + ); + })} + +
SubmitterPriceAgeStatus
+ {shortAddr(r.submitter)} + + ${formatAmount(r.price, PRICE_DECIMALS)} + + {age.toString()} blk + + + {st.label} + +
+
+ ); +} + +export default function OraclePage() { + const { data: markets, isLoading } = useMarkets(); + const [marketId, setMarketId] = useState(""); + + const selectedMarketId = marketId || markets?.[0]?.market.marketId || ""; + const selectedMarket = markets?.find( + (m) => m.market.marketId === selectedMarketId + )?.market; + + const { data: collateralPrice } = useAssetPrice( + selectedMarket?.collateralAssetId ?? null + ); + const { data: debtPrice } = useAssetPrice(selectedMarket?.debtAssetId ?? null); + + if (isLoading) { + return ; + } + + if (!markets || markets.length === 0) { + return ( + + ); + } + + return ( +
+
+

Oracle

+

+ Permissioned ARBOR price submissions scoped to a market. Resolution + quorum = {MIN_REPORTERS} fresh reporter(s) within{" "} + {DEFAULT_STALENESS_BLOCKS} blocks (devnet override; ARCM spec = 3). +

+
+ +
+ setMarketId(e.target.value)} + > + {markets.map(({ market }) => ( + + ))} + +
+ + {selectedMarket && ( + <> +
+
+

+ {selectedMarket.collateralAssetId} price +

+

+ Median:{" "} + + {collateralPrice?.available && collateralPrice.price + ? `$${formatAmount(collateralPrice.price, PRICE_DECIMALS)}` + : "--"} + +

+

+ Reporters:{" "} + + {collateralPrice?.reporters ?? 0} + +

+ {!collateralPrice?.available && collateralPrice?.reason && ( +

+ {collateralPrice.reason} +

+ )} +
+ +
+

+ {selectedMarket.debtAssetId} price +

+

+ Median:{" "} + + {debtPrice?.available && debtPrice.price + ? `$${formatAmount(debtPrice.price, PRICE_DECIMALS)}` + : "--"} + +

+

+ Reporters:{" "} + + {debtPrice?.reporters ?? 0} + +

+ {!debtPrice?.available && debtPrice?.reason && ( +

{debtPrice.reason}

+ )} +
+
+ +
+
+

+ {selectedMarket.collateralAssetId} freshness monitor +

+
+ +
+
+
+

+ {selectedMarket.debtAssetId} freshness monitor +

+
+ +
+
+
+ +
+

+ Circuit breaker +

+

+ Deviation check (ARCM Rule 4) is{" "} + not yet active on-chain — + the {"{20}"} circuit-breaker state has no writer (price_resolve.go + discloses Rules 3 & 4 as deferred). No violations are tracked. +

+
+ + )} + + {selectedMarketId && } +
+ ); +} diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx new file mode 100644 index 0000000000..e602c3a2c4 --- /dev/null +++ b/frontend/src/app/page.tsx @@ -0,0 +1,510 @@ +"use client"; + +import { useCallback, useEffect, useState } from "react"; +import Link from "next/link"; +import { useMarkets, type MarketWithIndices } from "@/lib/hooks/useMarkets"; +import { useAssetPrice } from "@/lib/hooks/useAssetPrice"; +import { StatusPill } from "@/components/widgets/StatusPill"; +import { LoadingSkeleton } from "@/components/widgets/LoadingSkeleton"; +import { formatAmount } from "@/lib/arbor/format"; +import type { MarketStatus } from "@/lib/arbor/types"; +import { AssetIcon } from "@/components/AssetIcon"; + +type Filter = "all" | MarketStatus; + +const TABS: { key: Filter; label: string }[] = [ + { key: "all", label: "All statuses" }, + { key: "ACTIVE", label: "Active" }, + { key: "PAUSED", label: "Paused" }, + { key: "INSOLVENT", label: "Insolvent" }, + { key: "DEPRECATED", label: "Deprecated" }, +]; + +const TIER_LABEL: Record = { + 0: "Tier 0 · CNPY", + 1: "Tier 1 · BTC / ETH", + 2: "Tier 2 · Majors", + 3: "Tier 3 · Restricted", +}; + +// Rate model — exact mirror of contract/interest_rate.go (ARCM §14). +const U_OPT = 8000; +const BASE = 200; +const S1 = 800; +const S2 = 10000; +const BPS = 10000; +function borrowAprBps(u: number): number { + if (u <= U_OPT) return BASE + (u * S1) / U_OPT; + return BASE + S1 + ((u - U_OPT) * S2) / (BPS - U_OPT); +} +function supplyAprBps(u: number, rf: number): number { + const br = borrowAprBps(u); + return (br * u * (BPS - rf)) / (BPS * BPS); +} + +function fmtUsd(n: number | null): string { + if (n === null || !Number.isFinite(n)) return "—"; + if (n >= 1_000_000) return `$${(n / 1_000_000).toFixed(2)}M`; + if (n >= 1_000) return `$${(n / 1_000).toFixed(2)}K`; + if (n >= 1) return `$${n.toFixed(2)}`; + if (n > 0) return `$${n.toFixed(6)}`; + return "$0.00"; +} + +function fmtUnitPrice(price: bigint): string { + const u = Number(price) / 1e8; + return `$${u.toLocaleString(undefined, { maximumFractionDigits: 2 })}`; +} + +function fmtPct(n: number | null): string { + if (n === null || !Number.isFinite(n)) return "—"; + return `${n.toFixed(1)}%`; +} + +function utilBand(u: number | null): { bar: string; text: string } { + if (u === null) return { bar: "bg-zinc-600", text: "text-zinc-500" }; + if (u < 70) return { bar: "bg-emerald-400", text: "text-emerald-300" }; + if (u < 85) return { bar: "bg-amber-400", text: "text-amber-300" }; + return { bar: "bg-rose-400", text: "text-rose-300" }; +} + +function Monogram({ symbol }: { symbol: string }) { + return ; +} + +function StatCard({ + label, + value, + sub, + subTone = "muted", + coins, + accent = false, +}: { + label: string; + value: string; + sub?: string; + subTone?: "muted" | "up" | "down"; + coins?: string[]; + accent?: boolean; +}) { + const tone = + subTone === "up" + ? "text-emerald-400" + : subTone === "down" + ? "text-rose-400" + : "text-zinc-500"; + return ( +
+
+

+ {label} +

+ {coins && coins.length > 0 && ( + + {coins.slice(0, 4).map((s) => ( + + ))} + {coins.length > 4 && ( + + +{coins.length - 4} + + )} + + )} +
+

+ {value} +

+ {sub &&

{sub}

} +
+ ); +} + +function MarketCard({ + entry, + report, +}: { + entry: MarketWithIndices; + report: (id: string, s: number, b: number, priced: boolean) => void; +}) { + const m = entry.market; + const { data: priceData } = useAssetPrice(m.debtAssetId); + const price = + priceData?.available && priceData.price != null ? priceData.price : null; + + const suppliedUsd = + price !== null ? Number(m.totalSupplied) * (Number(price) / 1e8) : null; + const borrowedUsd = + price !== null ? Number(m.totalBorrowed) * (Number(price) / 1e8) : null; + + useEffect(() => { + report(m.marketId, suppliedUsd ?? 0, borrowedUsd ?? 0, suppliedUsd !== null); + }, [report, m.marketId, suppliedUsd, borrowedUsd]); + + const util = + m.totalSupplied > 0n + ? (Number(m.totalBorrowed) / Number(m.totalSupplied)) * 100 + : null; + const utilBps = + m.totalSupplied > 0n + ? Number((m.totalBorrowed * 10000n) / m.totalSupplied) + : 0; + const band = utilBand(util); + const lossFactorRatio = Number(entry.lossFactor) / 1e18; + const borrowApr = borrowAprBps(utilBps) / 100; + const supplyApr = supplyAprBps(utilBps, Number(m.reserveFactorBps)) / 100; + + return ( + +
+
+ +
+

{m.marketId}

+

+ {m.collateralAssetId} / {m.debtAssetId} +

+
+
+ +
+ +
+
+

Supplied

+ {suppliedUsd !== null ? ( + <> +

+ {fmtUsd(suppliedUsd)} +

+

+ {formatAmount(m.totalSupplied, 0)} {m.debtAssetId} +

+ + ) : ( + <> +

+ {formatAmount(m.totalSupplied, 0)} +

+

+ {m.debtAssetId} +

+ + )} +
+
+

Borrowed

+ {borrowedUsd !== null ? ( + <> +

+ {fmtUsd(borrowedUsd)} +

+

+ {formatAmount(m.totalBorrowed, 0)} {m.debtAssetId} +

+ + ) : ( + <> +

+ {formatAmount(m.totalBorrowed, 0)} +

+

+ {m.debtAssetId} +

+ + )} +
+
+ +
+
+ Utilization + {fmtPct(util)} +
+
+
+
+
+ +
+
+ Borrow APR +

{borrowApr.toFixed(2)}%

+
+
+ Supply APR +

{supplyApr.toFixed(2)}%

+
+
+ +
+ + Protocol internals + +
+
+ R_fund +

{formatAmount(entry.reserveFund, 0)}

+
+
+ Loss factor +

{lossFactorRatio.toFixed(6)}

+
+
+ L4 pending +

{m.layer4PendingCount}

+
+
+
+ + {price !== null ? ( +

+ {m.debtAssetId} @ {fmtUnitPrice(price)} · live oracle +

+ ) : ( +

+ USD valuation pending oracle quorum ({m.collateralAssetId}/ + {m.debtAssetId}) +

+ )} + + ); +} + +export default function HomePage() { + const { data: markets, isLoading, error } = useMarkets(); + const [usd, setUsd] = useState< + Record + >({}); + const [filter, setFilter] = useState("all"); + + const report = useCallback( + (id: string, s: number, b: number, priced: boolean) => { + setUsd((prev) => { + if (prev[id]?.s === s && prev[id]?.b === b && prev[id]?.priced === priced) + return prev; + return { ...prev, [id]: { s, b, priced } }; + }); + }, + [] + ); + + const list = markets ?? []; + const count = list.length; + + const totalSupplied = list.reduce((a, e) => a + e.market.totalSupplied, 0n); + const totalBorrowed = list.reduce((a, e) => a + e.market.totalBorrowed, 0n); + const util = + totalSupplied > 0n + ? (Number(totalBorrowed) / Number(totalSupplied)) * 100 + : null; + + const counts = list.reduce( + (acc, e) => { + acc[e.market.status] = (acc[e.market.status] ?? 0) + 1; + return acc; + }, + {} as Record + ); + + const shown = + filter === "all" ? list : list.filter((e) => e.market.status === filter); + + const empty = !isLoading && count === 0; + const activeLabel = TABS.find((t) => t.key === filter)?.label ?? ""; + + const activeCount = counts["ACTIVE"] ?? 0; + + const pricedSupplied = Object.values(usd).reduce( + (a, v) => (v.priced ? a + v.s : a), + 0 + ); + const pricedBorrowed = Object.values(usd).reduce( + (a, v) => (v.priced ? a + v.b : a), + 0 + ); + const unpricedActive = list.filter( + (e) => + !usd[e.market.marketId]?.priced && + (e.market.totalSupplied > 0n || e.market.totalBorrowed > 0n) + ).length; + const unitLabel = + Array.from(new Set(list.map((e) => e.market.debtAssetId))).length === 1 + ? ` ${list[0]?.market.debtAssetId ?? ""}` + : ""; + + return ( +
+
+
+
+ +
+

Arbor · Smart Lending Protocol

+

Protocol overview

+

+ Isolated lending markets with a four-layer bad-debt waterfall — + R_fund, T_fund, socialized lenders, and the NASM reserve. +

+
+
+
+ +
+ + e.market.collateralAssetId)))} + value={ + pricedSupplied > 0 + ? fmtUsd(pricedSupplied) + : formatAmount(totalSupplied, 0) + } + sub={ + pricedSupplied > 0 + ? `${formatAmount(totalSupplied, 0)} native${ + unpricedActive > 0 ? ` · ${unpricedActive} unpriced` : "" + }` + : `native units${unitLabel}` + } + /> + e.market.debtAssetId)))} + value={ + pricedBorrowed > 0 + ? fmtUsd(pricedBorrowed) + : formatAmount(totalBorrowed, 0) + } + sub={ + pricedBorrowed > 0 + ? `${formatAmount(totalBorrowed, 0)} native${ + unpricedActive > 0 ? ` · ${unpricedActive} unpriced` : "" + }` + : `native units${unitLabel}` + } + subTone="down" + /> + +
+ +

+ Dollar values use live oracle medians from /v1/query/prices and only + sum markets whose debt asset is priced (the standard TVL convention); + native whole-unit totals are shown alongside. Health factor and per‑card + APR derive from the on‑chain rate model. +

+
+ + +
+
+

+ All markets +

+ + {count} total + +
+ +
+ {TABS.map((t) => { + const n = t.key === "all" ? count : counts[t.key] ?? 0; + const active = filter === t.key; + return ( + + ); + })} +
+ + {error && ( +
+ Failed to load markets. Check the ARBOR plugin RPC connection. +
+ )} + + {isLoading && } + + {!isLoading && empty && ( +
+
+

+ No markets yet +

+

+ ARBOR markets are created on chain by an authority. Launch your + first isolated market to populate the overview and portfolio. +

+ + Go to Admin + +
+ )} + + {!isLoading && !empty && shown.length === 0 && ( +

+ No {activeLabel.toLowerCase()} markets. +

+ )} + +
+ {shown.map((entry) => ( + + ))} +
+
+
+ ); +} diff --git a/frontend/src/app/quests/page.tsx b/frontend/src/app/quests/page.tsx new file mode 100644 index 0000000000..0d0f37fef4 --- /dev/null +++ b/frontend/src/app/quests/page.tsx @@ -0,0 +1,133 @@ +"use client"; + +import { useWalletStore } from "@/lib/stores/walletStore"; +import { useQuestXp, useLeaderboard, useTodayQuests } from "@/lib/quest/hooks"; + +function shortAddr(addr: string): string { + return addr.length > 10 ? `${addr.slice(0, 6)}...${addr.slice(-4)}` : addr; +} + +export default function QuestsPage() { + const address = useWalletStore((s) => s.address); + const { data: today, isLoading: todayLoading } = useTodayQuests(address ?? undefined); + const { data: myXp, isLoading: myXpLoading } = useQuestXp(address ?? undefined); + const { data: leaderboard, isLoading: leaderboardLoading, isError } = useLeaderboard("current"); + + return ( +
+
+ Arbor Community Quests +
+

Quests & XP

+

+ Complete real actions on Arbor — supply, borrow, repay, and more — + to earn XP automatically. XP is read live from the quest indexer, + a service separate from Arbor's core protocol. +

+ +
+
+
Today's quests
+
Resets daily
+
+ {todayLoading ? ( +
Loading…
+ ) : today ? ( +
+ {today.quests.map((q) => ( +
+
+ {q.completed ? "✓" : ""} +
+
+
+ + {q.label} + + +{q.xp} XP +
+

{q.description}

+
+
+ ))} +
+ ) : ( +
Couldn't reach the quest service.
+ )} + {!address && ( +
+ Connect your wallet to track which quests you've completed today. +
+ )} +
+ +
+
Your XP
+ {!address ? ( +
Connect your wallet to see your XP.
+ ) : myXpLoading ? ( +
Loading…
+ ) : myXp ? ( + <> +
{myXp.totalXp} XP
+
+ {myXp.entries.slice(0, 5).map((e) => ( +
+ {e.questId} + +{e.xp} XP +
+ ))} + {myXp.entries.length > 5 && ( +
+ +{myXp.entries.length - 5} more +
+ )} +
+ + ) : ( +
+ No XP yet — link your Discord/X account, then complete a quest action. +
+ )} +
+ +
+
+ Weekly leaderboard {leaderboard ? `(week ${leaderboard.weekId})` : ""} +
+ {isError ? ( +
Couldn't reach the quest service.
+ ) : leaderboardLoading ? ( +
Loading…
+ ) : leaderboard && leaderboard.leaderboard.length > 0 ? ( + + + + + + + + + + {leaderboard.leaderboard.map((entry, i) => ( + + + + + + ))} + +
#WalletXP
{i + 1}{shortAddr(entry.address)}{entry.xp}
+ ) : ( +
No activity yet this week.
+ )} +
+
+ ); +} diff --git a/frontend/src/app/send/page.tsx b/frontend/src/app/send/page.tsx new file mode 100644 index 0000000000..8648113ff3 --- /dev/null +++ b/frontend/src/app/send/page.tsx @@ -0,0 +1,200 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { useWalletStore } from "@/lib/wallet"; +import { SendForm } from "@/components/forms/SendForm"; +import { useAccount } from "@/lib/hooks/useAccount"; +import { Portfolio } from "@/components/sections/Portfolio"; +import { FaucetCard } from "@/components/sections/FaucetCard"; +import { AssetRows } from "@/components/sections/AssetRows"; +import { AssetIcon } from "@/components/AssetIcon"; +import { formatAddress, formatAmount } from "@/lib/arbor/format"; +import { + getNusdBalance, + getAllNasmVaults, + getNasmVaultPool, +} from "@/lib/canopy/pluginRpc"; + +type VaultRow = { + id: string; + asset: string; + collateral: bigint; + escrowed: bigint; + principal: bigint; +}; + +function BalanceRow({ + symbol, + name, + note, + amount, + decimals, + staked, +}: { + symbol: string; + name: string; + note: string; + amount: bigint | null; + decimals: number; + staked?: bigint | null; +}) { + return ( +
+ +
+

{name}

+

{note}

+
+
+

+ {amount != null ? formatAmount(amount, decimals) : "—"} +

+ {staked != null && staked > 0n && ( +

+ +{formatAmount(staked, decimals)} staked +

+ )} +
+
+ ); +} + +export default function SendPage() { + const wallet = useWalletStore(); + const addr = wallet.address; + + const [nusd, setNusd] = useState(null); + const [vaults, setVaults] = useState([]); + + const { data: accountData } = useAccount(addr); + const cnpy = accountData?.amount ?? null; + const staked = accountData?.stakedAmount ?? null; + + useEffect(() => { + if (!addr) return; + let alive = true; + getNusdBalance(addr).then((b) => { + if (alive) setNusd(b.amount); + }); + getAllNasmVaults(addr).then(async (list) => { + const rows = await Promise.all( + list.map(async (v) => { + const p = await getNasmVaultPool(String(v.vaultId ?? "")); + return { + id: String(v.vaultId), + asset: String(v.collateralAssetId ?? ""), + collateral: BigInt(String(v.collateralQuantity ?? "0")), + escrowed: p?.amount ?? 0n, + principal: BigInt(String(v.nusdPrincipal ?? "0")), + }; + }) + ); + if (alive) setVaults(rows); + }); + return () => { + alive = false; + }; + }, [addr]); + + return ( +
+
+

+ Wallet +

+
+ +
+

Portfolio overview

+

+ Transferable balances and every module your wallet is active in — + lending, borrowing and NASM vaults. +

+
+
+ {addr && ( +

+ address: {formatAddress(addr)} +

+ )} +
+ +
+
+

Your balances

+ {!addr ? ( +

+ Connect a wallet to view transferable balances. +

+ ) : ( +
+ + + +
+ )} +
+ +
+ +
+

Your modules

+ {addr && vaults.length > 0 && ( +
+

NASM vaults

+
+ + + + + + + + + + + {vaults.map((v) => ( + + + + + + + ))} + +
VaultCollateralEscrowedNUSD principal
{v.id} + + + {formatAmount(v.collateral, 0)} {v.asset} + + + {formatAmount(v.escrowed, 0)} + + {formatAmount(v.principal, 6)} +
+
+
+ )} + + +
+
+ ); +} diff --git a/frontend/src/app/tx/page.tsx b/frontend/src/app/tx/page.tsx new file mode 100644 index 0000000000..42b4038891 --- /dev/null +++ b/frontend/src/app/tx/page.tsx @@ -0,0 +1,7 @@ +"use client"; + +import { TxExplorer } from "@/components/widgets/TxExplorer"; + +export default function TxPage() { + return ; +} diff --git a/frontend/src/app/watch/[address]/page.tsx b/frontend/src/app/watch/[address]/page.tsx new file mode 100644 index 0000000000..d9d219f097 --- /dev/null +++ b/frontend/src/app/watch/[address]/page.tsx @@ -0,0 +1,297 @@ +"use client"; + +import { useState, useEffect, useCallback } from "react"; +import { useParams, useRouter } from "next/navigation"; +import { useMarkets, type MarketWithIndices } from "@/lib/hooks/useMarkets"; +import { useLenderPosition } from "@/lib/hooks/useLenderPosition"; +import { useBorrowerPosition } from "@/lib/hooks/useBorrowerPosition"; +import { useNasmVaultsByOwner } from "@/lib/hooks/useNasmVault"; +import { useAssetPrice } from "@/lib/hooks/useAssetPrice"; +import { useAccount } from "@/lib/hooks/useAccount"; +import { computeHealthFactorScaled } from "@/lib/arbor/math"; +import { formatAmount, formatHealthFactor, formatAddress } from "@/lib/arbor/format"; +import { TIER_PARAMS } from "@/lib/arbor/constants"; +import { AssetIcon } from "@/components/AssetIcon"; +import { AssetRows } from "@/components/sections/AssetRows"; + +function Monogram({ symbol }: { symbol: string }) { + return ; +} + +function HfPill({ hf }: { hf: bigint | null }) { + if (hf == null) return ; + const v = Number(hf) / 1e6; + const cls = + v < 1.0 + ? "bg-rose-500/15 text-rose-300" + : v < 1.5 + ? "bg-amber-500/15 text-amber-300" + : "bg-emerald-500/15 text-emerald-300"; + return ( + + {formatHealthFactor(hf)} + + ); +} + +function MarketCell({ entry }: { entry: MarketWithIndices }) { + const m = entry.market; + return ( + +
+ +
+

{m.marketId}

+

+ {m.collateralAssetId}/{m.debtAssetId} +

+
+
+ + ); +} + +function LendingRow({ entry, address }: { entry: MarketWithIndices; address: string }) { + const m = entry.market; + const { data: lp } = useLenderPosition(m.marketId, address); + const { data: price } = useAssetPrice(m.debtAssetId); + const shares = lp?.shares ?? 0n; + const value = + price?.available && price.price != null + ? Number(shares) * (Number(price.price) / 1e8) + : null; + + if (shares === 0n) return null; + + return ( + + + +

+ {formatAmount(shares, 0)} +

+

+ {value != null ? `$${value.toFixed(2)}` : "—"} +

+ + — + + ); +} + +function BorrowingRow({ entry, address }: { entry: MarketWithIndices; address: string }) { + const m = entry.market; + const { data: bp } = useBorrowerPosition(m.marketId, address); + const { data: collPrice } = useAssetPrice(m.collateralAssetId); + const { data: debtPrice } = useAssetPrice(m.debtAssetId); + const tier = TIER_PARAMS[m.assetTier]; + + const debt = bp?.currentDebt ?? 0n; + const coll = bp?.collateralQuantity ?? 0n; + + if (debt === 0n && coll === 0n) return null; + + const hf = tier && collPrice?.available && collPrice.price != null && debtPrice?.available && debtPrice.price != null + ? computeHealthFactorScaled( + coll, + collPrice.price, + tier.ltvLiqBps, + debt, + debtPrice.price, + ) + : null; + + return ( + + + +

+ {formatAmount(coll, 0)} +

+

{m.collateralAssetId}

+ + +

+ {formatAmount(debt, 0)} +

+

{m.debtAssetId}

+ + + + + + ); +} + + +export default function WatchPage() { + const params = useParams(); + const router = useRouter(); + const watchedAddress = (params.address as string).toLowerCase(); + const [inputAddr, setInputAddr] = useState(watchedAddress); + + const { data: markets } = useMarkets(); + const { data: accountData } = useAccount(watchedAddress); + const { data: nasmVaults } = useNasmVaultsByOwner(watchedAddress); + + const [lendingPresent, setLendingPresent] = useState>({}); + const [borrowingPresent, setBorrowingPresent] = useState>({}); + + const trackLending = useCallback((id: string, v: boolean) => { + setLendingPresent((prev) => ({ ...prev, [id]: v })); + }, []); + + const trackBorrowing = useCallback((id: string, v: boolean) => { + setBorrowingPresent((prev) => ({ ...prev, [id]: v })); + }, []); + + useEffect(() => { + setInputAddr(watchedAddress); + }, [watchedAddress]); + + const handleSwitch = (e: React.FormEvent) => { + e.preventDefault(); + const trimmed = inputAddr.trim().toLowerCase(); + if (trimmed && trimmed !== watchedAddress) { + router.push(`/watch/${trimmed}`); + } + }; + + const cnpy = accountData?.amount ?? null; + const staked = accountData?.stakedAmount ?? null; + + return ( +
+
+

+ Watch mode +

+

+ Read-only view of any wallet's positions on the Arbor protocol. +

+
+ setInputAddr(e.target.value)} + placeholder="Enter address (40 hex chars)" + className="flex-1 rounded-lg border border-white/10 bg-white/5 px-4 py-2 text-sm text-zinc-100 placeholder-zinc-500 focus:border-indigo-400 focus:outline-none" + /> + +
+

+ Watching: {watchedAddress} +

+
+ +
+

Balances

+
+
+
+ +
+

Arbor

+

Native token

+
+
+
+

+ {cnpy != null ? formatAmount(cnpy, 6) : "—"} +

+ {staked != null && staked > 0n && ( +

+ Staked: {formatAmount(staked, 6)} +

+ )} +
+
+ +
+
+ + {markets && markets.length > 0 && ( +
+

Lending positions

+ + + + + + + + + + {markets.map((entry) => ( + + ))} + +
MarketSharesValue
+ {Object.values(lendingPresent).every((v) => !v) && ( +

+ No lending positions for this address. +

+ )} +
+ )} + + {markets && markets.length > 0 && ( +
+

Borrowing positions

+ + + + + + + + + + + {markets.map((entry) => ( + + ))} + +
MarketCollateralDebtHealth
+ {Object.values(borrowingPresent).every((v) => !v) && ( +

+ No borrowing positions for this address. +

+ )} +
+ )} + + {nasmVaults && nasmVaults.length > 0 && ( +
+

NASM vaults

+
+ {nasmVaults.map((vault: any) => ( +
+

+ Vault {String(vault.vaultId)} — {String(vault.collateralAssetId)} +

+
+
+

Escrowed

+

{formatAmount(vault.escrowed as bigint, 0)}

+
+
+

Principal

+

{formatAmount(vault.principal as bigint, 0)}

+
+
+
+ ))} +
+
+ )} +
+ ); +} diff --git a/frontend/src/components/AssetIcon.tsx b/frontend/src/components/AssetIcon.tsx new file mode 100644 index 0000000000..e3124cbe28 --- /dev/null +++ b/frontend/src/components/AssetIcon.tsx @@ -0,0 +1,162 @@ +"use client"; + +import { useId } from "react"; + +export type AssetIconProps = { + symbol?: string | null; + size?: number; + className?: string; +}; + +const NAVY = "#16324F"; +const GOLD = "#C9A24B"; +const SERIF = "Georgia, 'Times New Roman', serif"; + +function normalize(symbol: string): string { + const s = symbol.trim().toLowerCase(); + if (["eth", "weth", "steth", "reth"].includes(s)) return "eth"; + if (s === "usdc") return "usdc"; + if (s === "usdt") return "usdt"; + if (["cnpy", "canopy"].includes(s)) return "canopy"; + if (["btc", "bitcoin", "wbtc", "tbtc"].includes(s)) return "bitcoin"; + if (s === "nusd") return "nusd"; + if (s === "arbor") return "arbor"; + return s; +} + +function Glyph({ k }: { k: string }) { + switch (k) { + case "arbor": + return ( + <> + + + + + + + + + + + + + + + + + + + + + + + + + + ); + case "nusd": + return ( + <> + + + + + + + + + + + ); + case "canopy": + return ( + <> + + + + + + + + + + + ); + case "eth": + return ( + <> + + + + + + ); + case "bitcoin": + return ( + <> + B + + + + + + + + + ); + case "usdc": + return ( + <> + + $ + + + ); + case "usdt": + return ( + <> + + + + + + + + + ); + default: + return ( + + {k.charAt(0).toUpperCase()} + + ); + } +} + +export function AssetIcon({ symbol, size = 32, className }: AssetIconProps) { + const uid = useId(); + const gradId = `parchment-${uid}`; + const k = normalize(symbol ?? ""); + return ( + + + + + + + + + + + + + ); +} diff --git a/frontend/src/components/forms/BorrowForm.tsx b/frontend/src/components/forms/BorrowForm.tsx new file mode 100644 index 0000000000..e7741a956b --- /dev/null +++ b/frontend/src/components/forms/BorrowForm.tsx @@ -0,0 +1,255 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { useMarket } from "@/lib/hooks/useMarket"; +import { useBorrowerPosition } from "@/lib/hooks/useBorrowerPosition"; +import { useAssetPrice } from "@/lib/hooks/useAssetPrice"; +import { useWalletStore } from "@/lib/wallet"; +import { useArborTx } from "@/lib/hooks/useArborTx"; +import { marketAdmissionFromMarket } from "@/lib/hooks/useMarketAdmission"; +import { getBlockedReason } from "@/lib/arbor/admission"; +import { parseAmount, formatAmount, formatHealthFactor } from "@/lib/arbor/format"; +import { + scaledDebt, + maxBorrowQty, + computeHealthFactorScaled, +} from "@/lib/arbor/math"; +import { + TIER_PARAMS, + HF_LIQUIDATABLE_SCALED, +} from "@/lib/arbor/constants"; +import { addressBytesFromHex } from "@/lib/wallet"; +import { EmptyState } from "@/components/widgets/EmptyState"; +import { LoadingSkeleton } from "@/components/widgets/LoadingSkeleton"; +import { AdmissionGateBanner } from "@/components/widgets/AdmissionGateBanner"; +import { + Field, + TextInput, + SubmitButton, + ErrorText, +} from "@/components/forms/FormPrimitives"; + +const MAX_UINT64 = 18446744073709551615n; + +export function BorrowForm({ marketId }: { marketId: string }) { + const { data: marketData, isLoading } = useMarket(marketId); + const wallet = useWalletStore(); + const { data: borrowerPosition, refetch: refetchPosition } = useBorrowerPosition(marketId, wallet.address); + const { submit, phase } = useArborTx(); + + useEffect(() => { + if (phase === "confirmed") { + refetchPosition(); + const t = setTimeout(() => refetchPosition(), 2500); + return () => clearTimeout(t); + } + }, [phase, refetchPosition]); + + const { data: position } = useBorrowerPosition(marketId, wallet.address); + + const [amount, setAmount] = useState(""); + const [localError, setLocalError] = useState(null); + + const collateralAssetId = marketData?.market.collateralAssetId ?? null; + const debtAssetId = marketData?.market.debtAssetId ?? null; + + const { data: collateralPrice } = useAssetPrice(collateralAssetId); + const { data: debtPrice } = useAssetPrice(debtAssetId); + + if (isLoading) { + return ; + } + + if (!marketData) { + return ; + } + + const { market, bIndex } = marketData; + const admission = marketAdmissionFromMarket(market); + const blocked = getBlockedReason("borrow", admission) !== null; + + const busy = + phase === "signing" || + phase === "submitting" || + phase === "waiting"; + + const tier = TIER_PARAMS[market.assetTier]; + + const collateralQty = position?.collateralQuantity ?? 0n; + + const currentDebt = position?.currentDebt ?? 0n; + + const pricesAvailable = + !!collateralPrice?.available && + !!debtPrice?.available && + collateralPrice.price !== null && + debtPrice.price !== null; + + const maxBorrow = + tier && pricesAvailable + ? maxBorrowQty( + collateralQty, + collateralPrice.price as bigint, + tier.ltvMaxBps, + debtPrice.price as bigint + ) + : 0n; + + const availableLiquidity = + market.totalSupplied > market.totalBorrowed + ? market.totalSupplied - market.totalBorrowed + : 0n; + + const collateralCap = maxBorrow > currentDebt ? maxBorrow - currentDebt : 0n; + const remainingBorrow = + availableLiquidity < collateralCap ? availableLiquidity : collateralCap; + + let previewHf = 0n; + let parseError: string | null = null; + + if (!tier) { + parseError = "Asset tier parameters unavailable."; + } else if (!pricesAvailable) { + parseError = + collateralPrice?.reason || + debtPrice?.reason || + "Oracle prices unavailable."; + } else if (amount.trim()) { + try { + const parsed = parseAmount(amount, 0); + + if (parsed > MAX_UINT64) { + parseError = "Borrow amount exceeds uint64 max."; + } else if (parsed > remainingBorrow) { + parseError = `Borrow exceeds max borrowable amount: ${formatAmount(remainingBorrow, 0)}.`; + } else { + const newDebt = currentDebt + parsed; + + previewHf = computeHealthFactorScaled( + collateralQty, + collateralPrice.price as bigint, + tier.ltvLiqBps, + newDebt, + debtPrice.price as bigint + ); + + if (previewHf !== 0n && previewHf <= HF_LIQUIDATABLE_SCALED) { + parseError = + "Borrow would make the position immediately liquidatable."; + } + } + } catch (err: any) { + parseError = err?.message || String(err); + } + } + + async function onSubmit(e: React.FormEvent) { + e.preventDefault(); + setLocalError(null); + + try { + const parsed = parseAmount(amount, 0); + + if (parsed <= 0n) { + throw new Error("Borrow amount must be greater than zero."); + } + + if (parsed > MAX_UINT64) { + throw new Error("Borrow amount exceeds uint64 max."); + } + + if (parsed > remainingBorrow) { + throw new Error( + `Borrow exceeds max borrowable amount: ${formatAmount(remainingBorrow, 0)}.` + ); + } + + const address = addressBytesFromHex(wallet.address); + + await submit("borrow", { + marketId, + address, + borrowAmount: parsed, + }); + + setAmount(""); + } catch (err: any) { + setLocalError(err?.message || String(err)); + } + } + + return ( +
+
+

+ Borrow {market.debtAssetId} +

+ Borrower +
+ + + + {!wallet.isConnected && ( + + Connect a wallet with a 20-byte hex address to borrow. + + )} + +
+
+ Current debt:{" "} + + {formatAmount(currentDebt, 0)} + +
+
+ You can borrow up to{" "} + + {formatAmount(remainingBorrow, 0)} {market.debtAssetId} + + {borrowerPosition && borrowerPosition.collateralQuantity > 0n && ( + + {" "} + {`(${tier + ? `${(Number(tier.ltvMaxBps) / 100).toFixed(0)}% of your ${market.collateralAssetId} collateral's value` + : "based on your collateral"}${availableLiquidity < collateralCap + ? ` — limited by market liquidity (${formatAmount(availableLiquidity, 0)} ${market.debtAssetId} available)` + : ""})`} + + )} + {" "}before liquidation risk begins. +
+
+ + + setAmount(e.target.value)} + placeholder="0.0" + inputMode="decimal" + invalid={!!parseError} + /> + + + {localError && {localError}} + + + Borrow + + + ); +} diff --git a/frontend/src/components/forms/BurnNusdForm.tsx b/frontend/src/components/forms/BurnNusdForm.tsx new file mode 100644 index 0000000000..6eb83777d7 --- /dev/null +++ b/frontend/src/components/forms/BurnNusdForm.tsx @@ -0,0 +1,121 @@ +"use client"; + +import { useState } from "react"; +import { useWalletStore } from "@/lib/wallet"; +import { useArborTx } from "@/lib/hooks/useArborTx"; +import { useNasmVault } from "@/lib/hooks/useNasmVault"; +import { addressBytesFromHex } from "@/lib/wallet"; +import { parseAmount, formatAmount } from "@/lib/arbor/format"; +import { + Field, + TextInput, + SubmitButton, + ErrorText, +} from "@/components/forms/FormPrimitives"; + +const MAX_UINT64 = 18446744073709551615n; + +export function BurnNusdForm({ onBurned }: { onBurned?: () => void }) { + const wallet = useWalletStore(); + const { submit, phase } = useArborTx(); + + const [vaultId, setVaultId] = useState(""); + const [nusdAmount, setNusdAmount] = useState(""); + const [localError, setLocalError] = useState(null); + + const { data: vaultData } = useNasmVault(vaultId.trim() || null); + + const busy = phase === "signing" || phase === "submitting" || phase === "waiting"; + + const currentDebt = vaultData?.vault + ? BigInt(String((vaultData.vault as Record).nusdPrincipal ?? "0")) + : null; + + let parseError: string | null = null; + let parsedNusd = 0n; + + if (nusdAmount.trim()) { + try { + parsedNusd = parseAmount(nusdAmount, 6); + if (parsedNusd > MAX_UINT64) parseError = "NUSD amount exceeds uint64 max."; + } catch (err: any) { + parseError = err?.message || String(err); + } + } + + async function onSubmit(e: React.FormEvent) { + e.preventDefault(); + setLocalError(null); + + try { + if (!vaultId.trim()) throw new Error("Vault ID is required."); + + const nusd = parseAmount(nusdAmount, 6); + if (nusd <= 0n) throw new Error("NUSD amount must be greater than zero."); + if (nusd > MAX_UINT64) throw new Error("NUSD amount exceeds uint64 max."); + + const sender = addressBytesFromHex(wallet.address); + + await submit("burn_nusd", { + vaultId: vaultId.trim(), + sender, + nusdAmount: nusd, + }); + + setNusdAmount(""); + onBurned?.(); + } catch (err: any) { + setLocalError(err?.message || String(err)); + } + } + + return ( +
+
+

Burn NUSD

+ Repay & release collateral +
+ + {!wallet.isConnected && ( + Connect the vault owner's wallet to burn NUSD. + )} + + + setVaultId(e.target.value)} + placeholder="my-vault-01" + /> + + + {vaultId.trim() && ( +

+ Current debt: {currentDebt !== null ? formatAmount(currentDebt, 6) + " NUSD" : "loading…"} +

+ )} + + + setNusdAmount(e.target.value)} + placeholder="0.0" + inputMode="decimal" + invalid={!!parseError} + /> + + + {localError && {localError}} + + + Burn NUSD + +
+ ); +} diff --git a/frontend/src/components/forms/CreateMarketForm.tsx b/frontend/src/components/forms/CreateMarketForm.tsx new file mode 100644 index 0000000000..e60d47c02a --- /dev/null +++ b/frontend/src/components/forms/CreateMarketForm.tsx @@ -0,0 +1,234 @@ +"use client"; + +import { useState } from "react"; +import { useWalletStore } from "@/lib/wallet"; +import { useArborTx } from "@/lib/hooks/useArborTx"; +import { MIN_REPORTERS } from "@/lib/arbor/constants"; +import { addressBytesFromHex } from "@/lib/wallet"; +import { hexToBytes } from "@/lib/canopy/decode"; +import { + Field, + TextInput, + SelectInput, + SubmitButton, + ErrorText, +} from "@/components/forms/FormPrimitives"; + +const MAX_UINT64 = 18446744073709551615n; + +function parseAddressList(input: string): Uint8Array[] { + const parts = input + .split(/[,\n]+/) + .map((s) => s.trim()) + .filter(Boolean); + + return parts.map((part) => { + const clean = part.startsWith("0x") ? part.slice(2) : part; + + if (!/^[0-9a-fA-F]{40}$/.test(clean)) { + throw new Error(`Invalid 20-byte hex address: ${part}`); + } + + return hexToBytes(clean); + }); +} + +export function CreateMarketForm() { + const wallet = useWalletStore(); + const { submit, phase } = useArborTx(); + + const [marketId, setMarketId] = useState(""); + const [collateralAssetId, setCollateralAssetId] = useState(""); + const [debtAssetId, setDebtAssetId] = useState(""); + const [assetTier, setAssetTier] = useState("1"); + const [reserveFactorBps, setReserveFactorBps] = useState("1000"); + const [authorizedSubmitters, setAuthorizedSubmitters] = useState(""); + const [localError, setLocalError] = useState(null); + + const busy = + phase === "signing" || + phase === "submitting" || + phase === "waiting"; + + let parseError: string | null = null; + + const tier = Number(assetTier); + const reserveFactor = Number(reserveFactorBps); + + if (!Number.isInteger(tier) || tier < 0 || tier > 3) { + parseError = "Asset tier must be an integer from 0 to 3."; + } else if ( + !Number.isInteger(reserveFactor) || + reserveFactor < 200 || + reserveFactor > 3000 + ) { + parseError = "Reserve factor must be between 200 and 3000 bps."; + } else if (authorizedSubmitters.trim()) { + try { + const submitters = parseAddressList(authorizedSubmitters); + + if (submitters.length < MIN_REPORTERS) { + parseError = `authorized_submitters must contain at least ${MIN_REPORTERS} addresses.`; + } + } catch (err: any) { + parseError = err?.message || String(err); + } + } else { + parseError = `authorized_submitters must contain at least ${MIN_REPORTERS} addresses.`; + } + + async function onSubmit(e: React.FormEvent) { + e.preventDefault(); + setLocalError(null); + + try { + if (!marketId.trim()) { + throw new Error("Market ID is required."); + } + + if (marketId.trim().length > 64) { + throw new Error("Market ID must be 64 characters or less."); + } + + if (!collateralAssetId.trim()) { + throw new Error("Collateral asset ID is required."); + } + + if (!debtAssetId.trim()) { + throw new Error("Debt asset ID is required."); + } + + const parsedTier = Number(assetTier); + + if (!Number.isInteger(parsedTier) || parsedTier < 0 || parsedTier > 3) { + throw new Error("Asset tier must be an integer from 0 to 3."); + } + + const parsedReserveFactor = BigInt(reserveFactorBps); + + if ( + parsedReserveFactor < 200n || + parsedReserveFactor > 3000n || + parsedReserveFactor > MAX_UINT64 + ) { + throw new Error("Reserve factor must be between 200 and 3000 bps."); + } + + const submitters = parseAddressList(authorizedSubmitters); + + if (submitters.length < MIN_REPORTERS) { + throw new Error( + `authorized_submitters must contain at least ${MIN_REPORTERS} addresses.` + ); + } + + const creator = addressBytesFromHex(wallet.address); + + await submit("create_market", { + marketId: marketId.trim(), + collateralAssetId: collateralAssetId.trim(), + debtAssetId: debtAssetId.trim(), + assetTier: parsedTier, + reserveFactorBps: parsedReserveFactor, + creator, + authorizedSubmitters: submitters, + }); + + setMarketId(""); + setCollateralAssetId(""); + setDebtAssetId(""); + setAuthorizedSubmitters(""); + } catch (err: any) { + setLocalError(err?.message || String(err)); + } + } + + return ( +
+
+

+ Create market +

+ Admin +
+ + {!wallet.isConnected && ( + + Connect a wallet with a 20-byte hex address to create a market. + + )} + + + setMarketId(e.target.value)} + placeholder="CNPY-ETH" + /> + + +
+ + setCollateralAssetId(e.target.value)} + placeholder="CNPY" + /> + + + + setDebtAssetId(e.target.value)} + placeholder="ETH" + /> + +
+ +
+ + setAssetTier(e.target.value)} + > + + + + + + + + + setReserveFactorBps(e.target.value)} + placeholder="1000" + inputMode="numeric" + /> + +
+ + +