From 5c100024d7c10a7d640423d9a776624199c7f3be Mon Sep 17 00:00:00 2001 From: Daniel Arroyo Date: Thu, 20 Aug 2026 19:16:58 -0400 Subject: [PATCH] chore: remove stale src/frontend (React/Vite) + cleanup .gitignore Frontend was migrated to Qute/Alpine in 34e5246. The src/frontend/ tree was no longer built, not referenced in any build file (pom.xml, Dockerfile, .dockerignore), and not present on disk. Removing: - 36 tracked-but-deleted React/TS/Vite/Tailwind files - 5 untracked screenshot artifacts in repo root - 4 stale entries in .gitignore (src/frontend/node_modules/, dist/, etc.) --- .gitignore | 4 - src/frontend/index.html | 13 - src/frontend/package-lock.json | 2698 ----------------- src/frontend/package.json | 25 - src/frontend/postcss.config.js | 6 - src/frontend/public/favicon.svg | 11 - src/frontend/src/App.tsx | 141 - src/frontend/src/api/client.ts | 144 - src/frontend/src/api/history.ts | 137 - src/frontend/src/auth/AuthContext.tsx | 77 - src/frontend/src/auth/ChangePasswordPage.tsx | 119 - src/frontend/src/auth/LoginPage.tsx | 128 - .../src/components/CalculadoraSection.tsx | 188 -- .../src/components/FormulasSection.tsx | 111 - .../src/components/HistorySection.tsx | 44 - .../src/components/InsumosSection.tsx | 140 - .../src/components/RunDetailsModal.tsx | 324 -- src/frontend/src/components/RunsTable.tsx | 94 - src/frontend/src/components/SaveIndicator.tsx | 34 - src/frontend/src/components/ShotTable.tsx | 123 - src/frontend/src/components/StatsCards.tsx | 80 - src/frontend/src/components/TabBar.tsx | 45 - src/frontend/src/components/TotalsSummary.tsx | 77 - .../src/components/UsersAdminPage.tsx | 195 -- src/frontend/src/data/defaults.ts | 90 - src/frontend/src/hooks/useHistory.ts | 70 - src/frontend/src/hooks/usePersistedState.ts | 95 - src/frontend/src/index.css | 34 - src/frontend/src/main.tsx | 10 - src/frontend/src/types.ts | 53 - src/frontend/src/utils/calc.ts | 83 - src/frontend/src/utils/format.ts | 16 - src/frontend/tailwind.config.js | 26 - src/frontend/tsconfig.app.json | 21 - src/frontend/tsconfig.json | 7 - src/frontend/tsconfig.node.json | 18 - src/frontend/vite.config.ts | 17 - 37 files changed, 5498 deletions(-) delete mode 100644 src/frontend/index.html delete mode 100644 src/frontend/package-lock.json delete mode 100644 src/frontend/package.json delete mode 100644 src/frontend/postcss.config.js delete mode 100644 src/frontend/public/favicon.svg delete mode 100644 src/frontend/src/App.tsx delete mode 100644 src/frontend/src/api/client.ts delete mode 100644 src/frontend/src/api/history.ts delete mode 100644 src/frontend/src/auth/AuthContext.tsx delete mode 100644 src/frontend/src/auth/ChangePasswordPage.tsx delete mode 100644 src/frontend/src/auth/LoginPage.tsx delete mode 100644 src/frontend/src/components/CalculadoraSection.tsx delete mode 100644 src/frontend/src/components/FormulasSection.tsx delete mode 100644 src/frontend/src/components/HistorySection.tsx delete mode 100644 src/frontend/src/components/InsumosSection.tsx delete mode 100644 src/frontend/src/components/RunDetailsModal.tsx delete mode 100644 src/frontend/src/components/RunsTable.tsx delete mode 100644 src/frontend/src/components/SaveIndicator.tsx delete mode 100644 src/frontend/src/components/ShotTable.tsx delete mode 100644 src/frontend/src/components/StatsCards.tsx delete mode 100644 src/frontend/src/components/TabBar.tsx delete mode 100644 src/frontend/src/components/TotalsSummary.tsx delete mode 100644 src/frontend/src/components/UsersAdminPage.tsx delete mode 100644 src/frontend/src/data/defaults.ts delete mode 100644 src/frontend/src/hooks/useHistory.ts delete mode 100644 src/frontend/src/hooks/usePersistedState.ts delete mode 100644 src/frontend/src/index.css delete mode 100644 src/frontend/src/main.tsx delete mode 100644 src/frontend/src/types.ts delete mode 100644 src/frontend/src/utils/calc.ts delete mode 100644 src/frontend/src/utils/format.ts delete mode 100644 src/frontend/tailwind.config.js delete mode 100644 src/frontend/tsconfig.app.json delete mode 100644 src/frontend/tsconfig.json delete mode 100644 src/frontend/tsconfig.node.json delete mode 100644 src/frontend/vite.config.ts diff --git a/.gitignore b/.gitignore index 142b6d5..c9b5395 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,6 @@ target/ .mvn/ node/ node_modules/ -src/frontend/node_modules/ -src/frontend/dist/ -src/frontend/tsconfig.app.tsbuildinfo -src/frontend/tsconfig.node.tsbuildinfo /data/ .idea/ .vscode/ diff --git a/src/frontend/index.html b/src/frontend/index.html deleted file mode 100644 index ecfb4f8..0000000 --- a/src/frontend/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Calculadora de Craft de Shots — Lineage 2 - - -
- - - diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json deleted file mode 100644 index dc8eb51..0000000 --- a/src/frontend/package-lock.json +++ /dev/null @@ -1,2698 +0,0 @@ -{ - "name": "shot-crafter-calculator", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "shot-crafter-calculator", - "version": "1.0.0", - "dependencies": { - "react": "^18.3.1", - "react-dom": "^18.3.1" - }, - "devDependencies": { - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@vitejs/plugin-react": "^4.3.4", - "autoprefixer": "^10.4.20", - "postcss": "^8.4.49", - "tailwindcss": "^3.4.17", - "typescript": "^5.7.2", - "vite": "^5.4.11" - } - }, - "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.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", - "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.8", - "@babel/types": "^7.29.8", - "@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-plugin-utils": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", - "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.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.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", - "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.8" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", - "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", - "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.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.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", - "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.8", - "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.8", - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.8", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", - "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", - "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/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "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/lzma-linux-x64-gnu": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", - "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^22.20 || ^24.12 || >=25" - } - }, - "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/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.4.tgz", - "integrity": "sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.4.tgz", - "integrity": "sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.4.tgz", - "integrity": "sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.4.tgz", - "integrity": "sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.4.tgz", - "integrity": "sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.4.tgz", - "integrity": "sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.4.tgz", - "integrity": "sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.4.tgz", - "integrity": "sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.4.tgz", - "integrity": "sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.4.tgz", - "integrity": "sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.4.tgz", - "integrity": "sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.4.tgz", - "integrity": "sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.4.tgz", - "integrity": "sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.4.tgz", - "integrity": "sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.4.tgz", - "integrity": "sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.4.tgz", - "integrity": "sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.4.tgz", - "integrity": "sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.4.tgz", - "integrity": "sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.4.tgz", - "integrity": "sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.4.tgz", - "integrity": "sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.4.tgz", - "integrity": "sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.4.tgz", - "integrity": "sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.4.tgz", - "integrity": "sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.4.tgz", - "integrity": "sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.4.tgz", - "integrity": "sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } - }, - "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/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "18.3.31", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", - "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^18.0.0" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, - "license": "MIT" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true, - "license": "MIT" - }, - "node_modules/autoprefixer": { - "version": "10.5.4", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.4.tgz", - "integrity": "sha512-MaU0U/za7N3r6brxD4YB/l4NSrFzLPlANv6wEuQVaIPlD3L4W9rFcQPbL/EilY9BHhHvhfcz3gInDLrEtWT4EA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.6", - "caniuse-lite": "^1.0.30001806", - "fraction.js": "^5.3.4", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.11.13", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.13.tgz", - "integrity": "sha512-k9HNuUVMlqVjQ9UHzfPjIqiDbWw7WqT1AoT7GL8VwvF3r0ZfArtgiSPAlmupyNquNgOJHTuH4CKYf8ttMTWBTQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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.8", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", - "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", - "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.11.12", - "caniuse-lite": "^1.0.30001809", - "electron-to-chromium": "^1.5.402", - "node-releases": "^2.0.53", - "update-browserslist-db": "^1.3.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001809", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001809.tgz", - "integrity": "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==", - "dev": true, - "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/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/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/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "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/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "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==", - "dev": true, - "license": "MIT" - }, - "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/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true, - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.405", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.405.tgz", - "integrity": "sha512-bNglH7lPH5l+yHOes7Zr4VqxhOy4BQ9ZBUX4VdoFgxMpzJk7W1ZoO3Vgd9Pxa9PyjQ76sfm2aKH/nzEcCNRlew==", - "dev": true, - "license": "ISC" - }, - "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/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/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/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "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.8" - }, - "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/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/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/fraction.js": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", - "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "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/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/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/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/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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-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-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-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/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "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==", - "license": "MIT" - }, - "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/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/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "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==", - "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/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/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/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.18", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", - "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", - "dev": true, - "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/node-releases": { - "version": "2.0.53", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz", - "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "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-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "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==", - "dev": true, - "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/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss": { - "version": "8.5.26", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", - "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", - "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.17", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", - "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^6.1.1" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", - "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "license": "MIT" - }, - "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": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.12", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", - "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.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/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/rollup": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.4.tgz", - "integrity": "sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.9" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@napi-rs/lzma-linux-x64-gnu": "1.5.1", - "@rollup/rollup-android-arm-eabi": "4.62.4", - "@rollup/rollup-android-arm64": "4.62.4", - "@rollup/rollup-darwin-arm64": "4.62.4", - "@rollup/rollup-darwin-x64": "4.62.4", - "@rollup/rollup-freebsd-arm64": "4.62.4", - "@rollup/rollup-freebsd-x64": "4.62.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.62.4", - "@rollup/rollup-linux-arm-musleabihf": "4.62.4", - "@rollup/rollup-linux-arm64-gnu": "4.62.4", - "@rollup/rollup-linux-arm64-musl": "4.62.4", - "@rollup/rollup-linux-loong64-gnu": "4.62.4", - "@rollup/rollup-linux-loong64-musl": "4.62.4", - "@rollup/rollup-linux-ppc64-gnu": "4.62.4", - "@rollup/rollup-linux-ppc64-musl": "4.62.4", - "@rollup/rollup-linux-riscv64-gnu": "4.62.4", - "@rollup/rollup-linux-riscv64-musl": "4.62.4", - "@rollup/rollup-linux-s390x-gnu": "4.62.4", - "@rollup/rollup-linux-x64-gnu": "4.62.4", - "@rollup/rollup-linux-x64-musl": "4.62.4", - "@rollup/rollup-openbsd-x64": "4.62.4", - "@rollup/rollup-openharmony-arm64": "4.62.4", - "@rollup/rollup-win32-arm64-msvc": "4.62.4", - "@rollup/rollup-win32-ia32-msvc": "4.62.4", - "@rollup/rollup-win32-x64-gnu": "4.62.4", - "@rollup/rollup-win32-x64-msvc": "4.62.4", - "fsevents": "~2.3.2" - } - }, - "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/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "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/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==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "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": "3.4.19", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", - "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.6.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.2", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.7", - "lilconfig": "^3.1.3", - "micromatch": "^4.0.8", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.47", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", - "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", - "resolve": "^1.22.8", - "sucrase": "^3.35.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/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-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/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/update-browserslist-db": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.1.tgz", - "integrity": "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==", - "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/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/vite": { - "version": "5.4.21", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", - "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "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" - } - } -} diff --git a/src/frontend/package.json b/src/frontend/package.json deleted file mode 100644 index 95c9ab0..0000000 --- a/src/frontend/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "shot-crafter-calculator", - "version": "1.0.0", - "private": true, - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "preview": "vite preview" - }, - "dependencies": { - "react": "^18.3.1", - "react-dom": "^18.3.1" - }, - "devDependencies": { - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@vitejs/plugin-react": "^4.3.4", - "autoprefixer": "^10.4.20", - "postcss": "^8.4.49", - "tailwindcss": "^3.4.17", - "typescript": "^5.7.2", - "vite": "^5.4.11" - } -} diff --git a/src/frontend/postcss.config.js b/src/frontend/postcss.config.js deleted file mode 100644 index 2e7af2b..0000000 --- a/src/frontend/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} diff --git a/src/frontend/public/favicon.svg b/src/frontend/public/favicon.svg deleted file mode 100644 index 89cbf1a..0000000 --- a/src/frontend/public/favicon.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx deleted file mode 100644 index a0ef013..0000000 --- a/src/frontend/src/App.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import { useState } from 'react' -import { AuthProvider, useAuth } from './auth/AuthContext' -import { LoginPage } from './auth/LoginPage' -import { ChangePasswordPage } from './auth/ChangePasswordPage' -import { TabBar, type TabKey } from './components/TabBar' -import { InsumosSection } from './components/InsumosSection' -import { FormulasSection } from './components/FormulasSection' -import { CalculadoraSection } from './components/CalculadoraSection' -import { HistorySection } from './components/HistorySection' -import { UsersAdminPage } from './components/UsersAdminPage' -import { SaveIndicator } from './components/SaveIndicator' -import { usePersistedState } from './hooks/usePersistedState' -import { makeDefaultAppState, makeEmptyAppState } from './data/defaults' - -export default function App() { - return ( - - - - ) -} - -function AppRouter() { - const { user, loading } = useAuth() - if (loading) return - if (!user) return - if (user.mustChangePassword) return - return -} - -function AuthenticatedApp() { - const { user, logout } = useAuth() - const { state, setState, status, errorMessage, reset } = usePersistedState() - const [tab, setTab] = useState('insumos') - - if (!state) return - - const handleResetExamples = () => { - setState(makeDefaultAppState()) - } - - const handleClearAll = () => { - setState(makeEmptyAppState()) - } - - const handleResetServer = async () => { - if (confirm('¿Borrar tu estado guardado en el servidor?')) { - await reset() - } - } - - const isAdmin = user?.isAdmin ?? false - - return ( -
-
-
-
-

- Calculadora de Craft de Shots -

-

- {user?.username ?? ''} - {isAdmin && ( - - admin - - )} - {' · '} - Lineage 2 — Interlude / Clásico -

-
-
- - - - - -
-
- -
- -
- {tab === 'insumos' && ( - - )} - {tab === 'formulas' && ( - - )} - {tab === 'calculadora' && ( - - )} - {tab === 'historial' && } - {tab === 'usuarios' && isAdmin && } -
- -
-

- Auto-guardado activo · Cambios persistidos en el servidor cada ~500ms -

-
-
- ) -} - -function LoadingScreen({ message }: { message: string }) { - return ( -
-
-
-

{message}

-
-
- ) -} diff --git a/src/frontend/src/api/client.ts b/src/frontend/src/api/client.ts deleted file mode 100644 index f032247..0000000 --- a/src/frontend/src/api/client.ts +++ /dev/null @@ -1,144 +0,0 @@ -export class ApiError extends Error { - constructor(public status: number, message: string) { - super(message) - this.name = 'ApiError' - } -} - -export interface User { - id: string - username: string - createdAt: string - mustChangePassword: boolean - isAdmin: boolean -} - -export interface AdminUserSummary { - id: string - username: string - createdAt: string - lastLoginAt: string | null - isAdmin: boolean - mustChangePassword: boolean -} - -export interface AppState { - insumos: { - cristales: Record - soulOre: number - spiritOre: number - venta: Record> - } - formulas: Array<{ - id: string - tipo: string - grado: string - cristalesReq: number - soulOreReq: number | null - spiritOreReq: number | null - shotsObtenidos: number - }> - disponibles: Record> -} - -async function request(path: string, options: RequestInit = {}): Promise { - const res = await fetch(path, { - ...options, - credentials: 'include', - headers: { - 'Content-Type': 'application/json', - ...options.headers, - }, - }) - - if (res.status === 204) { - return undefined as T - } - - const text = await res.text() - let body: unknown = null - if (text) { - try { - body = JSON.parse(text) - } catch { - body = text - } - } - - if (!res.ok) { - const message = - body && typeof body === 'object' && 'error' in body - ? String((body as { error: string }).error) - : `HTTP ${res.status}` - throw new ApiError(res.status, message) - } - - return body as T -} - -export const api = { - async me(): Promise { - try { - return await request('/api/auth/me') - } catch (e) { - if (e instanceof ApiError && e.status === 401) return null - throw e - } - }, - - async login(username: string, password: string): Promise { - return request('/api/auth/login', { - method: 'POST', - body: JSON.stringify({ username, password }), - }) - }, - - async register(username: string, password: string): Promise { - return request('/api/auth/register', { - method: 'POST', - body: JSON.stringify({ username, password }), - }) - }, - - async logout(): Promise { - return request('/api/auth/logout', { method: 'POST' }) - }, - - async changePassword(currentPassword: string, newPassword: string): Promise { - return request('/api/auth/change-password', { - method: 'POST', - body: JSON.stringify({ currentPassword, newPassword }), - }) - }, - - async adminResetPassword(username: string, newPassword: string): Promise { - return request('/api/auth/admin/reset-password', { - method: 'POST', - body: JSON.stringify({ username, newPassword }), - }) - }, - - async adminListUsers(): Promise { - return request('/api/auth/admin/users') - }, - - async getState(): Promise { - try { - return await request('/api/state') - } catch (e) { - if (e instanceof ApiError && e.status === 404) return null - throw e - } - }, - - async putState(state: AppState): Promise { - return request('/api/state', { - method: 'PUT', - body: JSON.stringify(state), - }) - }, - - async resetState(): Promise { - return request('/api/state', { method: 'DELETE' }) - }, -} diff --git a/src/frontend/src/api/history.ts b/src/frontend/src/api/history.ts deleted file mode 100644 index b878d52..0000000 --- a/src/frontend/src/api/history.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { ApiError } from './client' - -async function request(path: string, options: RequestInit = {}): Promise { - const res = await fetch(path, { - ...options, - credentials: 'include', - headers: { - 'Content-Type': 'application/json', - ...options.headers, - }, - }) - - if (res.status === 204) { - return undefined as T - } - - const text = await res.text() - let body: unknown = null - if (text) { - try { - body = JSON.parse(text) - } catch { - body = text - } - } - - if (!res.ok) { - const message = - body && typeof body === 'object' && 'error' in body - ? String((body as { error: string }).error) - : `HTTP ${res.status}` - throw new ApiError(res.status, message) - } - - return body as T -} - -export interface RunItem { - tipo: string - grado: string - cristalesDisponibles: number - cristalesUsados: number - oreNecesario: number - crafteosPosibles: number - shotsObtenidos: number - costoTotal: number - valorVenta: number - ganancia: number -} - -export interface RunSnapshot { - insumos: unknown - formulas: unknown -} - -export interface RunSummary { - id: string - createdAt: string - label: string | null - totalCost: number - totalSale: number - totalProfit: number - totalShots: number - totalCristalesUsed: number - totalOreUsed: number -} - -export interface RunDetails extends RunSummary { - items: RunItem[] - snapshot: RunSnapshot -} - -export interface HistoryStats { - totalRuns: number - totalCost: number - totalSale: number - totalProfit: number - totalShots: number - avgProfit: number - avgCost: number - avgSale: number - bestRun: RunSummary | null - worstRun: RunSummary | null - last5Avg: number - last10Avg: number -} - -export interface RunIn { - label: string | null - totalCost: number - totalSale: number - totalProfit: number - totalShots: number - totalCristalesUsed: number - totalOreUsed: number - items: RunItem[] - snapshot: RunSnapshot -} - -export const historyApi = { - async saveRun(payload: RunIn): Promise { - return request('/api/history/runs', { - method: 'POST', - body: JSON.stringify(payload), - }) - }, - - async listRuns(): Promise { - return request('/api/history/runs') - }, - - async getRun(id: string): Promise { - try { - return await request(`/api/history/runs/${id}`) - } catch (e) { - if (e instanceof ApiError && e.status === 404) { - throw new Error('Producción no encontrada') - } - throw e - } - }, - - async deleteRun(id: string): Promise { - try { - return await request(`/api/history/runs/${id}`, { method: 'DELETE' }) - } catch (e) { - if (e instanceof ApiError && e.status === 404) { - throw new Error('Producción no encontrada') - } - throw e - } - }, - - async getStats(): Promise { - return request('/api/history/stats') - }, -} diff --git a/src/frontend/src/auth/AuthContext.tsx b/src/frontend/src/auth/AuthContext.tsx deleted file mode 100644 index 27ebb65..0000000 --- a/src/frontend/src/auth/AuthContext.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { createContext, useCallback, useContext, useEffect, useState, type ReactNode } from 'react' -import { ApiError, api, type User } from '../api/client' - -interface AuthContextValue { - user: User | null - loading: boolean - login: (username: string, password: string) => Promise - register: (username: string, password: string) => Promise - logout: () => Promise - changePassword: (currentPassword: string, newPassword: string) => Promise -} - -const AuthContext = createContext(null) - -export function AuthProvider({ children }: { children: ReactNode }) { - const [user, setUser] = useState(null) - const [loading, setLoading] = useState(true) - - useEffect(() => { - let cancelled = false - api - .me() - .then((u) => { - if (!cancelled) setUser(u) - }) - .catch((e) => { - if (!(e instanceof ApiError) || e.status !== 401) { - console.error('auth check failed', e) - } - }) - .finally(() => { - if (!cancelled) setLoading(false) - }) - return () => { - cancelled = true - } - }, []) - - const login = useCallback(async (username: string, password: string) => { - const u = await api.login(username, password) - setUser(u) - }, []) - - const register = useCallback(async (username: string, password: string) => { - const u = await api.register(username, password) - setUser(u) - }, []) - - const logout = useCallback(async () => { - await api.logout() - setUser(null) - }, []) - - const changePassword = useCallback(async (currentPassword: string, newPassword: string) => { - const u = await api.changePassword(currentPassword, newPassword) - // Round-trip ANTES de setUser(u). El Set-Cookie de la respuesta a - // change-password no está visible para el fetch siguiente en el mismo - // microtask en algunos navegadores. Si setteamos user primero, React - // re-renderiza AuthenticatedApp, su useEffect dispara api.getState() y - // pega el 401 antes de que el cookie esté aplicada al cookie store. - // Await api.me() ANTES fuerza ese round-trip a completarse. - await api.me() - setUser(u) - }, []) - - return ( - - {children} - - ) -} - -export function useAuth(): AuthContextValue { - const ctx = useContext(AuthContext) - if (!ctx) throw new Error('useAuth debe usarse dentro de ') - return ctx -} diff --git a/src/frontend/src/auth/ChangePasswordPage.tsx b/src/frontend/src/auth/ChangePasswordPage.tsx deleted file mode 100644 index 009cb3c..0000000 --- a/src/frontend/src/auth/ChangePasswordPage.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { useState, type FormEvent } from 'react' -import { useAuth } from './AuthContext' -import { ApiError } from '../api/client' - -export function ChangePasswordPage() { - const { changePassword } = useAuth() - const [currentPassword, setCurrentPassword] = useState('') - const [newPassword, setNewPassword] = useState('') - const [confirmPassword, setConfirmPassword] = useState('') - const [error, setError] = useState(null) - const [submitting, setSubmitting] = useState(false) - - const handleSubmit = async (e: FormEvent) => { - e.preventDefault() - setError(null) - if (newPassword !== confirmPassword) { - setError('La confirmación no coincide con la nueva contraseña.') - return - } - if (newPassword.length < 8) { - setError('La nueva contraseña debe tener al menos 8 caracteres.') - return - } - setSubmitting(true) - try { - await changePassword(currentPassword, newPassword) - } catch (err) { - if (err instanceof ApiError && err.status === 401) { - setError('La contraseña actual es incorrecta.') - } else { - const msg = err instanceof Error ? err.message : 'Error desconocido' - setError(msg) - } - } finally { - setSubmitting(false) - } - } - - return ( -
-
-
-
-

Cambiar contraseña

-

- Por seguridad, cambiá la contraseña provisional antes de seguir. -

-
- -
-
- - setCurrentPassword(e.target.value)} - autoComplete="current-password" - autoFocus - required - className="input-editable w-full" - /> -
- -
- - setNewPassword(e.target.value)} - autoComplete="new-password" - required - minLength={8} - className="input-editable w-full" - /> -
- -
- - setConfirmPassword(e.target.value)} - autoComplete="new-password" - required - minLength={8} - className="input-editable w-full" - /> -
- - {error && ( -

- {error} -

- )} - - -
- -

- La contraseña provisional la encontrás en el log de Docker - (docker logs shot-crafter | grep BOOTSTRAP-ADMIN-PASSWORD). -

-
-
-
- ) -} diff --git a/src/frontend/src/auth/LoginPage.tsx b/src/frontend/src/auth/LoginPage.tsx deleted file mode 100644 index 457d42c..0000000 --- a/src/frontend/src/auth/LoginPage.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import { useState, type FormEvent } from 'react' -import { useAuth } from './AuthContext' - -export function LoginPage() { - const { login, register } = useAuth() - const [mode, setMode] = useState<'login' | 'register'>('login') - const [username, setUsername] = useState('') - const [password, setPassword] = useState('') - const [error, setError] = useState(null) - const [submitting, setSubmitting] = useState(false) - - const handleSubmit = async (e: FormEvent) => { - e.preventDefault() - setError(null) - setSubmitting(true) - try { - if (mode === 'login') { - await login(username, password) - } else { - await register(username, password) - } - } catch (err) { - const msg = err instanceof Error ? err.message : 'Error desconocido' - if (mode === 'login') { - setError('Usuario o contraseña incorrectos.') - } else if (msg.includes('no disponible')) { - setError('Ese username ya está en uso.') - } else if (msg.toLowerCase().includes('datos')) { - setError('Username (3-30 chars, alfanumérico o _) y password (>= 8 chars).') - } else { - setError(msg) - } - } finally { - setSubmitting(false) - } - } - - const toggleMode = () => { - setMode((m) => (m === 'login' ? 'register' : 'login')) - setError(null) - } - - return ( -
-
-
-
-

- Calculadora de Craft de Shots -

-

- Lineage 2 — Interlude / Clásico -

-
- -
-
- - setUsername(e.target.value)} - autoComplete="username" - autoFocus - required - minLength={3} - maxLength={30} - pattern="[a-zA-Z0-9_]{3,30}" - className="input-editable w-full" - /> -
- -
- - setPassword(e.target.value)} - autoComplete={mode === 'login' ? 'current-password' : 'new-password'} - required - minLength={8} - className="input-editable w-full" - /> -
- - {error && ( -

- {error} -

- )} - - -
- -
- -
-
- -

- Cada usuario tiene su propio estado guardado en el servidor. -

-
-
- ) -} diff --git a/src/frontend/src/components/CalculadoraSection.tsx b/src/frontend/src/components/CalculadoraSection.tsx deleted file mode 100644 index 9401bfe..0000000 --- a/src/frontend/src/components/CalculadoraSection.tsx +++ /dev/null @@ -1,188 +0,0 @@ -import { useMemo, useState } from 'react' -import { SHOT_TYPES, type CristalesDisponibles, type Formula, type Insumos } from '../types' -import { ShotTable } from './ShotTable' -import { TotalsSummary } from './TotalsSummary' -import { calcularFila, sumarTotales } from '../utils/calc' -import type { AppState } from '../api/client' -import { useHistory, type HistorySaveStatus } from '../hooks/useHistory' - -interface CalculadoraSectionProps { - state: AppState - onChange: (next: AppState | ((prev: AppState) => AppState)) => void -} - -export function CalculadoraSection({ state, onChange }: CalculadoraSectionProps) { - const insumos: Insumos = state.insumos - const formulas: Formula[] = state.formulas - const disponibles: CristalesDisponibles = state.disponibles - const { saveRun, saveStatus, saveError } = useHistory() - const [label, setLabel] = useState('') - - const handleDisponibles = (tipo: string, grado: string, value: number) => { - onChange((prev) => ({ - ...prev, - disponibles: { - ...prev.disponibles, - [tipo]: { ...prev.disponibles[tipo], [grado]: value }, - }, - })) - } - - const tablas = useMemo(() => { - return SHOT_TYPES.map((tipo) => { - const formulasTipo = formulas.filter((f) => f.tipo === tipo) - const calculos = formulasTipo.map((f) => - calcularFila(f, disponibles[tipo][f.grado], insumos), - ) - const totales = sumarTotales(calculos) - return { tipo, formulas: formulasTipo, calculos, totales } - }) - }, [insumos, formulas, disponibles]) - - const totalesGlobal = useMemo( - () => sumarTotales(tablas.flatMap((t) => t.calculos)), - [tablas], - ) - - const canSave = totalesGlobal.cristalesUsados > 0 && saveStatus !== 'saving' - - const handleSave = async () => { - if (!canSave) return - const items = tablas.flatMap((t) => - t.formulas.map((f, i) => { - const c = t.calculos[i] - return { - tipo: t.tipo, - grado: f.grado, - cristalesDisponibles: c.cristalesDisponibles, - cristalesUsados: c.cristalesUsados, - oreNecesario: c.oreNecesario, - crafteosPosibles: c.crafteosPosibles, - shotsObtenidos: c.shotsObtenidos, - costoTotal: c.costoTotal, - valorVenta: c.valorVenta, - ganancia: c.ganancia, - } - }), - ) - try { - await saveRun({ - label: label.trim() || null, - totalCost: totalesGlobal.costoTotal, - totalSale: totalesGlobal.valorVenta, - totalProfit: totalesGlobal.ganancia, - totalShots: totalesGlobal.shotsObtenidos, - totalCristalesUsed: totalesGlobal.cristalesUsados, - totalOreUsed: totalesGlobal.oreNecesario, - items, - snapshot: { - insumos: insumos as unknown, - formulas: formulas as unknown, - }, - }) - setLabel('') - } catch { - // error ya manejado en saveStatus/saveError - } - } - - return ( -
-
-

- Ingresa solo los cristales disponibles por grado en cada tabla. La ore - necesaria, los crafteos, los shots producidos, el costo y la ganancia se calculan en - tiempo real a partir de los precios de la pestaña Insumos y las recetas de la - pestaña Fórmulas. -

-
- -
-
-
- - setLabel(e.target.value)} - maxLength={100} - placeholder="p.ej. Sesión lunes, crafteo nocturno…" - className="input-editable w-full text-left" - /> -
- -
- -
- - {tablas.map((t) => ( - handleDisponibles(t.tipo, grado, value)} - /> - ))} - - -
- ) -} - -function SaveFeedback({ - status, - error, -}: { - status: HistorySaveStatus - error: string | null -}) { - if (status === 'idle') { - return ( -

- Se guardará la producción actual con los cristales usados ( - {/* placeholder para texto */} verTotales). El cálculo se almacena con los precios y - fórmulas de este momento. -

- ) - } - if (status === 'saving') { - return ( -

- - Guardando en historial… -

- ) - } - if (status === 'saved') { - return ( -

- - Producción guardada ✓. La podés ver en la pestaña Historial. -

- ) - } - return ( -

Error al guardar: {error}

- ) -} diff --git a/src/frontend/src/components/FormulasSection.tsx b/src/frontend/src/components/FormulasSection.tsx deleted file mode 100644 index 49ed476..0000000 --- a/src/frontend/src/components/FormulasSection.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import type { Formula } from '../types' -import { parseNumber } from '../utils/format' -import type { AppState } from '../api/client' - -interface FormulasSectionProps { - state: AppState - onChange: (next: AppState | ((prev: AppState) => AppState)) => void -} - -export function FormulasSection({ state, onChange }: FormulasSectionProps) { - const formulas = state.formulas - - const updateField = (id: string, patch: Partial) => { - onChange((prev) => ({ - ...prev, - formulas: prev.formulas.map((f) => (f.id === id ? { ...f, ...patch } : f)), - })) - } - - return ( -
-
-

Recetas de crafteo

-

- Edita los recursos necesarios por cada acción de crafteo. Los cambios se reflejan en la - calculadora y se persisten automáticamente. -

-
- -
- - - - - - - - - - - - - {formulas.map((f) => { - const isSoul = f.tipo === 'Soulshot' - return ( - - - - - - - - - ) - })} - -
TipoGradoCristales req.Soul Ore req.Spirit Ore req.Shots obtenidos
{f.tipo} - - {f.grado} - - - - updateField(f.id, { cristalesReq: parseNumber(e.target.value) }) - } - className="input-editable" - /> - - - updateField(f.id, { soulOreReq: parseNumber(e.target.value) }) - } - className="input-editable" - /> - - - updateField(f.id, { spiritOreReq: parseNumber(e.target.value) }) - } - className="input-editable" - /> - - - updateField(f.id, { shotsObtenidos: parseNumber(e.target.value) }) - } - className="input-editable" - /> -
-
-
- ) -} diff --git a/src/frontend/src/components/HistorySection.tsx b/src/frontend/src/components/HistorySection.tsx deleted file mode 100644 index c50b342..0000000 --- a/src/frontend/src/components/HistorySection.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { useState } from 'react' -import { useHistory } from '../hooks/useHistory' -import { StatsCards } from './StatsCards' -import { RunsTable } from './RunsTable' -import { RunDetailsModal } from './RunDetailsModal' - -export function HistorySection() { - const { runs, stats, loading, deleteRun } = useHistory() - const [selectedRunId, setSelectedRunId] = useState(null) - - if (loading && !stats) { - return ( -
-

Cargando historial…

-
- ) - } - - return ( -
- {stats && } - -
-
-

- Corridas guardadas -

- {runs.length > 0 && ( - - {runs.length} en total · click en una fila para ver detalle - - )} -
- -
- - setSelectedRunId(null)} /> -
- ) -} diff --git a/src/frontend/src/components/InsumosSection.tsx b/src/frontend/src/components/InsumosSection.tsx deleted file mode 100644 index ff0a5f9..0000000 --- a/src/frontend/src/components/InsumosSection.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import { GRADOS, SHOT_TYPES, type Insumos } from '../types' -import { formatAdena, parseNumber } from '../utils/format' -import type { AppState } from '../api/client' - -interface InsumosSectionProps { - state: AppState - onChange: (next: AppState | ((prev: AppState) => AppState)) => void -} - -export function InsumosSection({ state, onChange }: InsumosSectionProps) { - const insumos = state.insumos - - const updateInsumos = (updater: (curr: Insumos) => Insumos) => { - onChange((prev) => ({ ...prev, insumos: updater(prev.insumos) })) - } - - const updateCristal = (grado: string, value: number) => - updateInsumos((curr) => ({ - ...curr, - cristales: { ...curr.cristales, [grado]: value }, - })) - - const updateSale = (tipo: string, grado: string, value: number) => - updateInsumos((curr) => ({ - ...curr, - venta: { - ...curr.venta, - [tipo]: { ...curr.venta[tipo], [grado]: value }, - }, - })) - - return ( -
-
- - {GRADOS.map((grado) => ( - updateCristal(grado, v)} - /> - ))} - -
- -
- - updateInsumos((curr) => ({ ...curr, soulOre: v }))} - /> - updateInsumos((curr) => ({ ...curr, spiritOre: v }))} - /> - -
- - {SHOT_TYPES.map((tipo) => ( -
- - {GRADOS.map((grado) => ( - updateSale(tipo, grado, v)} - /> - ))} - -
- ))} -
- ) -} - -function Section({ - title, - subtitle, - children, -}: { - title: string - subtitle?: string - children: React.ReactNode -}) { - return ( -
-
-

{title}

- {subtitle &&

{subtitle}

} -
-
{children}
-
- ) -} - -function GradeGrid({ children }: { children: React.ReactNode }) { - return ( -
{children}
- ) -} - -function GradeRow({ - label, - value, - onChange, -}: { - label: string - value: number - onChange: (v: number) => void -}) { - return ( - - ) -} diff --git a/src/frontend/src/components/RunDetailsModal.tsx b/src/frontend/src/components/RunDetailsModal.tsx deleted file mode 100644 index 0c2ccb1..0000000 --- a/src/frontend/src/components/RunDetailsModal.tsx +++ /dev/null @@ -1,324 +0,0 @@ -import { useEffect, useState } from 'react' -import { historyApi, type RunDetails } from '../api/history' -import { formatAdena } from '../utils/format' -import { GRADOS, SHOT_TYPES, type Formula, type Insumos } from '../types' - -interface RunDetailsModalProps { - runId: string | null - onClose: () => void -} - -export function RunDetailsModal({ runId, onClose }: RunDetailsModalProps) { - const [details, setDetails] = useState(null) - const [loading, setLoading] = useState(false) - const [error, setError] = useState(null) - const [showSnapshot, setShowSnapshot] = useState(false) - - useEffect(() => { - if (!runId) { - setDetails(null) - setError(null) - return - } - setLoading(true) - setError(null) - historyApi - .getRun(runId) - .then((d) => setDetails(d)) - .catch((e) => setError(e instanceof Error ? e.message : 'Error')) - .finally(() => setLoading(false)) - }, [runId]) - - if (!runId) return null - - return ( -
-
e.stopPropagation()} - > -
-
-

- {details?.label || 'Detalle de producción'} -

- {details && ( -

- {formatDateTime(details.createdAt)} -

- )} -
- -
- -
- {loading &&

Cargando…

} - {error && ( -

- {error} -

- )} - - {details && ( - <> -
- - - 0 ? 'emerald' : 'rose'} - highlight - /> - -
- -
-

- Desglose por grado -

-
- - - - - - - - - - - - - - - - {SHOT_TYPES.flatMap((tipo) => - GRADOS.map((grado) => { - const item = details.items.find( - (it) => it.tipo === tipo && it.grado === grado, - ) - if (!item) { - return ( - - - - - - ) - } - return ( - - - - - - - - - - - - ) - }), - )} - -
TipoGradoCristalesOreCrafteosShotsCostoVentaGanancia
{tipo} - - {grado} - - - (sin producción) -
{item.tipo} - - {item.grado} - - - {item.cristalesUsados} / {item.cristalesDisponibles} - - {item.oreNecesario} - - {item.crafteosPosibles} - - {item.shotsObtenidos} - - {formatAdena(item.costoTotal)} - - {formatAdena(item.valorVenta)} - - {formatAdena(item.ganancia)} -
-
-
- -
- - {showSnapshot && ( -
- - -
- )} -
- - )} -
- -
- -
-
-
- ) -} - -function SummaryStat({ - label, - value, - tone, - highlight = false, -}: { - label: string - value: string - tone: 'slate' | 'emerald' | 'rose' - highlight?: boolean -}) { - const colorClass = - tone === 'emerald' ? 'text-emerald-700' : tone === 'rose' ? 'text-rose-700' : 'text-slate-700' - return ( -
-

{label}

-

- {value} -

-
- ) -} - -function SnapshotInsumos({ snapshot }: { snapshot: RunDetails['snapshot'] }) { - const insumos = snapshot.insumos as Insumos - if (!insumos || !insumos.cristales) { - return ( -
- Sin datos de insumos. -
- ) - } - return ( -
-

Insumos

- - - {Object.entries(insumos.cristales).map(([grado, precio]) => ( - - - - - ))} - - - - - - - - - -
Cristal {grado}{formatAdena(Number(precio))}
Soul Ore{formatAdena(insumos.soulOre)}
Spirit Ore{formatAdena(insumos.spiritOre)}
-
- ) -} - -function SnapshotFormulas({ snapshot }: { snapshot: RunDetails['snapshot'] }) { - const formulas = snapshot.formulas as Formula[] - if (!formulas || !Array.isArray(formulas)) { - return ( -
- Sin datos de fórmulas. -
- ) - } - return ( -
-

- Fórmulas ({formulas.length}) -

-
- - - - - - - - - - - - - {formulas.map((f) => ( - - - - - - - - - ))} - -
TipoGradoCristSoulSpiritShots
{f.tipo}{f.grado}{f.cristalesReq}{f.soulOreReq ?? '—'}{f.spiritOreReq ?? '—'}{f.shotsObtenidos}
-
-
- ) -} - -function formatDateTime(iso: string): string { - const d = new Date(iso) - if (isNaN(d.getTime())) return iso - return d.toLocaleString('es-ES', { - year: 'numeric', - month: '2-digit', - day: '2-digit', - hour: '2-digit', - minute: '2-digit', - }) -} - -function gananciaColor(value: number): string { - if (value > 0) return 'text-emerald-700' - if (value < 0) return 'text-rose-700' - return 'text-slate-700' -} diff --git a/src/frontend/src/components/RunsTable.tsx b/src/frontend/src/components/RunsTable.tsx deleted file mode 100644 index 1d8b76c..0000000 --- a/src/frontend/src/components/RunsTable.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import type { RunSummary } from '../api/history' -import { formatAdena } from '../utils/format' - -interface RunsTableProps { - runs: RunSummary[] - onSelect: (id: string) => void - onDelete: (id: string) => void -} - -export function RunsTable({ runs, onSelect, onDelete }: RunsTableProps) { - if (runs.length === 0) { - return ( -
-

No hay corridas para mostrar.

-
- ) - } - - return ( -
-
- - - - - - - - - - - - - - - {runs.map((r) => ( - onSelect(r.id)} - > - - - - - - - - - - ))} - -
FechaLabelCristalesShotsCostoVentaGananciaAcción
- {formatDateTime(r.createdAt)} - - {r.label || (sin label)} - {r.totalCristalesUsed}{r.totalShots}{formatAdena(r.totalCost)}{formatAdena(r.totalSale)} - {formatAdena(r.totalProfit)} - - -
-
-
- ) -} - -function formatDateTime(iso: string): string { - const d = new Date(iso) - if (isNaN(d.getTime())) return iso - const yyyy = d.getFullYear() - const mm = String(d.getMonth() + 1).padStart(2, '0') - const dd = String(d.getDate()).padStart(2, '0') - const hh = String(d.getHours()).padStart(2, '0') - const min = String(d.getMinutes()).padStart(2, '0') - return `${yyyy}-${mm}-${dd} ${hh}:${min}` -} - -function gananciaColor(value: number): string { - if (value > 0) return 'text-emerald-700' - if (value < 0) return 'text-rose-700' - return 'text-slate-700' -} diff --git a/src/frontend/src/components/SaveIndicator.tsx b/src/frontend/src/components/SaveIndicator.tsx deleted file mode 100644 index 345082b..0000000 --- a/src/frontend/src/components/SaveIndicator.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import type { SaveStatus } from '../hooks/usePersistedState' - -interface SaveIndicatorProps { - status: SaveStatus - errorMessage: string | null -} - -export function SaveIndicator({ status, errorMessage }: SaveIndicatorProps) { - if (status === 'idle') { - return Guardado automáticamente - } - if (status === 'saving') { - return ( - - - Guardando… - - ) - } - if (status === 'saved') { - return ( - - - Guardado ✓ - - ) - } - return ( - - - Error al guardar - - ) -} diff --git a/src/frontend/src/components/ShotTable.tsx b/src/frontend/src/components/ShotTable.tsx deleted file mode 100644 index 883f957..0000000 --- a/src/frontend/src/components/ShotTable.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import { GRADOS, type Calculo, type Formula, type OreType, type ShotType, type Totales } from '../types' -import { formatAdena, parseNumber } from '../utils/format' - -interface ShotTableProps { - tipo: ShotType - formulas: Formula[] - calculos: Calculo[] - totales: Totales - disponibles: Record - onChangeDisponibles: (grado: string, value: number) => void -} - -export function ShotTable({ - tipo, - formulas, - calculos, - totales, - disponibles, - onChangeDisponibles, -}: ShotTableProps) { - const formulasPorTipo = formulas.filter((f) => f.tipo === tipo) - const calcPorGrado = new Map(calculos.map((c) => [c.grado, c])) - const oreLabel: OreType = tipo === 'Soulshot' ? 'Soul Ore' : 'Spirit Ore' - const colOre = `${oreLabel} nec.` - - return ( -
-
-

{tipo}

-

- Crafteo de {tipo}. Ingresa solo los cristales disponibles por grado. -

-
- -
- - - - - - - - - - - - - - - - {formulasPorTipo.map((f) => { - const c = calcPorGrado.get(f.grado) - if (!c) return null - return ( - - - - - - - - - - - - ) - })} - - - - - - - - - - - - - - -
GradoCristales disp.Cristales usados{colOre}CrafteosShotsCostoVentaGanancia
- - {f.grado} - - - onChangeDisponibles(f.grado, parseNumber(e.target.value))} - className="input-editable" - /> - {formatAdena(c.cristalesUsados)}{formatAdena(c.oreNecesario)}{formatAdena(c.crafteosPosibles)}{formatAdena(c.shotsObtenidos)}{formatAdena(c.costoTotal)}{formatAdena(c.valorVenta)} - {formatAdena(c.ganancia)} -
Σ—{formatAdena(totales.cristalesUsados)}{formatAdena(totales.oreNecesario)}{formatAdena(totales.crafteosPosibles)}{formatAdena(totales.shotsObtenidos)}{formatAdena(totales.costoTotal)}{formatAdena(totales.valorVenta)} - {formatAdena(totales.ganancia)} -
-
- - {GRADOS.some((g) => { - const c = calcPorGrado.get(g) - const f = formulasPorTipo.find((x) => x.grado === g) - return c?.warning || (f && f.cristalesReq === 0) - }) && ( -

- ⚠️ Una o más filas tienen cristales requeridos en 0. Completa la receta en la pestaña - Fórmulas para ver el cálculo. -

- )} -
- ) -} - -function gananciaColor(value: number): string { - if (value > 0) return 'text-emerald-700' - if (value < 0) return 'text-rose-700' - return 'text-slate-700' -} diff --git a/src/frontend/src/components/StatsCards.tsx b/src/frontend/src/components/StatsCards.tsx deleted file mode 100644 index ebe58de..0000000 --- a/src/frontend/src/components/StatsCards.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import type { HistoryStats } from '../api/history' -import { formatAdena } from '../utils/format' - -interface StatsCardsProps { - stats: HistoryStats -} - -export function StatsCards({ stats }: StatsCardsProps) { - if (stats.totalRuns === 0) { - return ( -
-

- Aún no hay producciones guardadas. Ve a la pestaña Calculadora, - configura los cristales disponibles y presiona Guardar producción. -

-
- ) - } - - return ( -
- 0 ? 'emerald' : stats.totalProfit < 0 ? 'rose' : 'slate'} - subtitle={`${stats.totalRuns} corrida${stats.totalRuns === 1 ? '' : 's'}`} - /> - 0 ? 'emerald' : stats.avgProfit < 0 ? 'rose' : 'slate'} - subtitle="por corrida" - /> - - - 0 ? 'emerald' : stats.last5Avg < 0 ? 'rose' : 'slate'} - subtitle="tendencia reciente" - /> -
- ) -} - -function MetricCard({ - label, - value, - subtitle, - tone, -}: { - label: string - value: string - subtitle?: string - tone: 'slate' | 'emerald' | 'rose' -}) { - const colorClass = - tone === 'emerald' - ? 'text-emerald-700' - : tone === 'rose' - ? 'text-rose-700' - : 'text-slate-700' - return ( -
-

{label}

-

{value}

- {subtitle &&

{subtitle}

} -
- ) -} diff --git a/src/frontend/src/components/TabBar.tsx b/src/frontend/src/components/TabBar.tsx deleted file mode 100644 index af5eded..0000000 --- a/src/frontend/src/components/TabBar.tsx +++ /dev/null @@ -1,45 +0,0 @@ -export type TabKey = 'insumos' | 'formulas' | 'calculadora' | 'historial' | 'usuarios' - -interface TabBarProps { - active: TabKey - onChange: (key: TabKey) => void - showUsersTab?: boolean -} - -const TABS: Array<{ key: TabKey; label: string; subtitle: string }> = [ - { key: 'insumos', label: '1. Insumos', subtitle: 'Precios' }, - { key: 'formulas', label: '2. Fórmulas', subtitle: 'Recetas' }, - { key: 'calculadora', label: '3. Calculadora', subtitle: 'Rentabilidad' }, - { key: 'historial', label: '4. Historial', subtitle: 'Producción' }, - { key: 'usuarios', label: '5. Usuarios', subtitle: 'Admin' }, -] - -export function TabBar({ active, onChange, showUsersTab = false }: TabBarProps) { - return ( -
- -
- ) -} diff --git a/src/frontend/src/components/TotalsSummary.tsx b/src/frontend/src/components/TotalsSummary.tsx deleted file mode 100644 index d0350a6..0000000 --- a/src/frontend/src/components/TotalsSummary.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import type { Totales } from '../types' -import { formatAdena } from '../utils/format' - -interface TotalsSummaryProps { - totales: Totales -} - -export function TotalsSummary({ totales }: TotalsSummaryProps) { - const margen = totales.costoTotal > 0 - ? (totales.ganancia / totales.costoTotal) * 100 - : 0 - - return ( -
0 - ? 'bg-emerald-50 border-emerald-200' - : totales.ganancia < 0 - ? 'bg-rose-50 border-rose-200' - : 'bg-slate-50 border-slate-200', - ].join(' ')} - > -
-

Resumen global

-

- Suma de Soulshots, Spiritshots y Blessed Spiritshots -

-
- -
- - - 0 ? 'emerald' : totales.ganancia < 0 ? 'rose' : 'slate'} - highlight - /> - 0 ? 'emerald' : margen < 0 ? 'rose' : 'slate'} - /> -
-
- ) -} - -function Metric({ - label, - value, - tone, - highlight = false, -}: { - label: string - value: string - tone: 'slate' | 'emerald' | 'rose' - highlight?: boolean -}) { - const colorClass = - tone === 'emerald' ? 'text-emerald-700' : tone === 'rose' ? 'text-rose-700' : 'text-slate-800' - return ( -
-

{label}

-

- {value} -

-
- ) -} diff --git a/src/frontend/src/components/UsersAdminPage.tsx b/src/frontend/src/components/UsersAdminPage.tsx deleted file mode 100644 index 67318ca..0000000 --- a/src/frontend/src/components/UsersAdminPage.tsx +++ /dev/null @@ -1,195 +0,0 @@ -import { useCallback, useEffect, useState, type FormEvent } from 'react' -import { ApiError, api, type AdminUserSummary } from '../api/client' - -export function UsersAdminPage() { - const [users, setUsers] = useState([]) - const [loading, setLoading] = useState(true) - const [error, setError] = useState(null) - const [resetFor, setResetFor] = useState(null) - const [resetError, setResetError] = useState(null) - const [resetPassword, setResetPassword] = useState('') - const [resetSubmitting, setResetSubmitting] = useState(false) - - const load = useCallback(async () => { - setLoading(true) - setError(null) - try { - const list = await api.adminListUsers() - setUsers(list) - } catch (e) { - if (e instanceof ApiError) setError(`HTTP ${e.status}: ${e.message}`) - else setError(e instanceof Error ? e.message : 'Error desconocido') - } finally { - setLoading(false) - } - }, []) - - useEffect(() => { - load() - }, [load]) - - const handleReset = async (e: FormEvent) => { - e.preventDefault() - if (!resetFor) return - setResetSubmitting(true) - setResetError(null) - try { - await api.adminResetPassword(resetFor.username, resetPassword) - setResetFor(null) - setResetPassword('') - await load() - } catch (e) { - if (e instanceof ApiError) setResetError(`HTTP ${e.status}: ${e.message}`) - else setResetError(e instanceof Error ? e.message : 'Error desconocido') - } finally { - setResetSubmitting(false) - } - } - - return ( -
-
-
-

Usuarios

-

- Reseteá la contraseña de cualquier usuario. Al resetear, deberá - cambiarla en su próximo login. -

-
- -
- - {error && ( -

- {error} -

- )} - -
- - - - - - - - - - - - - {users.map((u) => ( - - - - - - - - - ))} - {users.length === 0 && !loading && ( - - - - )} - -
UsernameRolEstadoCreadoÚltimo loginAcciones
{u.username} - {u.isAdmin ? ( - - admin - - ) : ( - - usuario - - )} - - {u.mustChangePassword ? ( - - cambiar pass - - ) : ( - - ok - - )} - - {new Date(u.createdAt).toLocaleString()} - - {u.lastLoginAt ? new Date(u.lastLoginAt).toLocaleString() : '—'} - - -
- Sin usuarios para listar. -
-
- - {resetFor && ( -
-
-

- Resetear contraseña de {resetFor.username} -

-

- El usuario deberá cambiar esta contraseña en su próximo login. -

-
- - setResetPassword(e.target.value)} - autoFocus - required - minLength={8} - className="input-editable w-full mb-3" - /> - {resetError && ( -

- {resetError} -

- )} -
- - -
-
-
-
- )} -
- ) -} diff --git a/src/frontend/src/data/defaults.ts b/src/frontend/src/data/defaults.ts deleted file mode 100644 index 6c9d316..0000000 --- a/src/frontend/src/data/defaults.ts +++ /dev/null @@ -1,90 +0,0 @@ -import type { AppState as ApiAppState } from '../api/client' -import type { CristalesDisponibles, Formula, Insumos } from '../types' - -export const DEFAULT_INSUMOS: Insumos = { - cristales: { - D: 1500, - C: 4500, - B: 18000, - A: 60000, - S: 200000, - }, - soulOre: 320, - spiritOre: 450, - venta: { - Soulshot: { D: 7, C: 18, B: 70, A: 220, S: 800 }, - Spiritshot: { D: 22, C: 60, B: 180, A: 400, S: 950 }, - 'Blessed Spiritshot': { D: 60, C: 180, B: 700, A: 1800, S: 4500 }, - }, -} - -export const DEFAULT_FORMULAS: Formula[] = [ - { id: 'Soulshot-D', tipo: 'Soulshot', grado: 'D', cristalesReq: 1, soulOreReq: 3, spiritOreReq: null, shotsObtenidos: 200 }, - { id: 'Soulshot-C', tipo: 'Soulshot', grado: 'C', cristalesReq: 1, soulOreReq: 15, spiritOreReq: null, shotsObtenidos: 600 }, - { id: 'Soulshot-B', tipo: 'Soulshot', grado: 'B', cristalesReq: 1, soulOreReq: 54, spiritOreReq: null, shotsObtenidos: 540 }, - { id: 'Soulshot-A', tipo: 'Soulshot', grado: 'A', cristalesReq: 1, soulOreReq: 60, spiritOreReq: null, shotsObtenidos: 500 }, - { id: 'Soulshot-S', tipo: 'Soulshot', grado: 'S', cristalesReq: 1, soulOreReq: 40, spiritOreReq: null, shotsObtenidos: 350 }, - - { id: 'Spiritshot-D', tipo: 'Spiritshot', grado: 'D', cristalesReq: 1, soulOreReq: null, spiritOreReq: 3, shotsObtenidos: 140 }, - { id: 'Spiritshot-C', tipo: 'Spiritshot', grado: 'C', cristalesReq: 1, soulOreReq: null, spiritOreReq: 10, shotsObtenidos: 270 }, - { id: 'Spiritshot-B', tipo: 'Spiritshot', grado: 'B', cristalesReq: 1, soulOreReq: null, spiritOreReq: 15, shotsObtenidos: 200 }, - { id: 'Spiritshot-A', tipo: 'Spiritshot', grado: 'A', cristalesReq: 1, soulOreReq: null, spiritOreReq: 30, shotsObtenidos: 350 }, - { id: 'Spiritshot-S', tipo: 'Spiritshot', grado: 'S', cristalesReq: 1, soulOreReq: null, spiritOreReq: 15, shotsObtenidos: 200 }, - - { id: 'Blessed Spiritshot-D', tipo: 'Blessed Spiritshot', grado: 'D', cristalesReq: 2, soulOreReq: null, spiritOreReq: 8, shotsObtenidos: 120 }, - { id: 'Blessed Spiritshot-C', tipo: 'Blessed Spiritshot', grado: 'C', cristalesReq: 2, soulOreReq: null, spiritOreReq: 30, shotsObtenidos: 240 }, - { id: 'Blessed Spiritshot-B', tipo: 'Blessed Spiritshot', grado: 'B', cristalesReq: 2, soulOreReq: null, spiritOreReq: 16, shotsObtenidos: 120 }, - { id: 'Blessed Spiritshot-A', tipo: 'Blessed Spiritshot', grado: 'A', cristalesReq: 2, soulOreReq: null, spiritOreReq: 84, shotsObtenidos: 300 }, - { id: 'Blessed Spiritshot-S', tipo: 'Blessed Spiritshot', grado: 'S', cristalesReq: 2, soulOreReq: null, spiritOreReq: 50, shotsObtenidos: 200 }, -] - -export const DEFAULT_CRISTALES_DISP: CristalesDisponibles = { - Soulshot: { D: 0, C: 0, B: 0, A: 0, S: 0 }, - Spiritshot: { D: 0, C: 0, B: 0, A: 0, S: 0 }, - 'Blessed Spiritshot': { D: 0, C: 0, B: 0, A: 0, S: 0 }, -} - -export const EMPTY_INSUMOS: Insumos = { - cristales: { D: 0, C: 0, B: 0, A: 0, S: 0 }, - soulOre: 0, - spiritOre: 0, - venta: { - Soulshot: { D: 0, C: 0, B: 0, A: 0, S: 0 }, - Spiritshot: { D: 0, C: 0, B: 0, A: 0, S: 0 }, - 'Blessed Spiritshot': { D: 0, C: 0, B: 0, A: 0, S: 0 }, - }, -} - -export const EMPTY_FORMULAS: Formula[] = DEFAULT_FORMULAS.map((f) => ({ - ...f, - cristalesReq: 0, - soulOreReq: null, - spiritOreReq: null, - shotsObtenidos: 0, -})) - -export const EMPTY_CRISTALES_DISP: CristalesDisponibles = { - Soulshot: { D: 0, C: 0, B: 0, A: 0, S: 0 }, - Spiritshot: { D: 0, C: 0, B: 0, A: 0, S: 0 }, - 'Blessed Spiritshot': { D: 0, C: 0, B: 0, A: 0, S: 0 }, -} - -export function makeDefaultAppState(): ApiAppState { - return { - insumos: structuredCopy(DEFAULT_INSUMOS), - formulas: structuredCopy(DEFAULT_FORMULAS), - disponibles: structuredCopy(DEFAULT_CRISTALES_DISP), - } -} - -export function makeEmptyAppState(): ApiAppState { - return { - insumos: structuredCopy(EMPTY_INSUMOS), - formulas: structuredCopy(EMPTY_FORMULAS), - disponibles: structuredCopy(EMPTY_CRISTALES_DISP), - } -} - -function structuredCopy(value: T): T { - return JSON.parse(JSON.stringify(value)) -} diff --git a/src/frontend/src/hooks/useHistory.ts b/src/frontend/src/hooks/useHistory.ts deleted file mode 100644 index 0d089a8..0000000 --- a/src/frontend/src/hooks/useHistory.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { useCallback, useEffect, useState } from 'react' -import { historyApi, type HistoryStats, type RunIn, type RunSummary } from '../api/history' - -export type HistorySaveStatus = 'idle' | 'saving' | 'saved' | 'error' - -interface UseHistoryResult { - runs: RunSummary[] - stats: HistoryStats | null - loading: boolean - saveStatus: HistorySaveStatus - saveError: string | null - reload: () => Promise - saveRun: (payload: RunIn) => Promise - deleteRun: (id: string) => Promise -} - -export function useHistory(): UseHistoryResult { - const [runs, setRuns] = useState([]) - const [stats, setStats] = useState(null) - const [loading, setLoading] = useState(true) - const [saveStatus, setSaveStatus] = useState('idle') - const [saveError, setSaveError] = useState(null) - - const reload = useCallback(async () => { - setLoading(true) - try { - const [runsData, statsData] = await Promise.all([ - historyApi.listRuns(), - historyApi.getStats(), - ]) - setRuns(runsData) - setStats(statsData) - } catch (e) { - console.error('history load failed', e) - } finally { - setLoading(false) - } - }, []) - - useEffect(() => { - reload() - }, [reload]) - - const saveRun = useCallback(async (payload: RunIn) => { - setSaveStatus('saving') - setSaveError(null) - try { - const saved = await historyApi.saveRun(payload) - setRuns((prev) => [saved, ...prev]) - const newStats = await historyApi.getStats() - setStats(newStats) - setSaveStatus('saved') - window.setTimeout(() => setSaveStatus((s) => (s === 'saved' ? 'idle' : s)), 3000) - return saved - } catch (e) { - setSaveStatus('error') - setSaveError(e instanceof Error ? e.message : 'Error al guardar') - throw e - } - }, []) - - const deleteRun = useCallback(async (id: string) => { - await historyApi.deleteRun(id) - setRuns((prev) => prev.filter((r) => r.id !== id)) - const newStats = await historyApi.getStats() - setStats(newStats) - }, []) - - return { runs, stats, loading, saveStatus, saveError, reload, saveRun, deleteRun } -} diff --git a/src/frontend/src/hooks/usePersistedState.ts b/src/frontend/src/hooks/usePersistedState.ts deleted file mode 100644 index c42d73d..0000000 --- a/src/frontend/src/hooks/usePersistedState.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { useCallback, useEffect, useRef, useState } from 'react' -import { api, ApiError, type AppState } from '../api/client' -import { makeDefaultAppState } from '../data/defaults' - -export type SaveStatus = 'idle' | 'saving' | 'saved' | 'error' - -interface UsePersistedStateResult { - state: AppState | null - setState: (next: AppState | ((prev: AppState) => AppState)) => void - status: SaveStatus - errorMessage: string | null - reset: () => Promise - reload: () => Promise -} - -const DEBOUNCE_MS = 500 - -export function usePersistedState(): UsePersistedStateResult { - const [state, setStateInternal] = useState(null) - const [status, setStatus] = useState('idle') - const [errorMessage, setErrorMessage] = useState(null) - const stateRef = useRef(null) - const timerRef = useRef(null) - const firstLoad = useRef(true) - - const load = useCallback(async () => { - try { - const loaded = await api.getState() - setStateInternal(loaded ?? makeDefaultAppState()) - } catch (err) { - if (err instanceof ApiError && err.status === 401) { - // No bloquear la UI en 401. Cargar default state. - setStateInternal(makeDefaultAppState()) - } else { - setErrorMessage(err instanceof Error ? err.message : 'Error cargando estado') - } - } - }, []) - - useEffect(() => { - load() - }, [load]) - - useEffect(() => { - stateRef.current = state - }, [state]) - - useEffect(() => { - if (firstLoad.current) { - firstLoad.current = false - return - } - if (!state) return - - setStatus('saving') - if (timerRef.current !== null) { - window.clearTimeout(timerRef.current) - } - timerRef.current = window.setTimeout(async () => { - try { - if (stateRef.current) { - await api.putState(stateRef.current) - } - setStatus('saved') - setErrorMessage(null) - window.setTimeout(() => setStatus((s) => (s === 'saved' ? 'idle' : s)), 1500) - } catch (err) { - setStatus('error') - setErrorMessage(err instanceof Error ? err.message : 'Error al guardar') - } - }, DEBOUNCE_MS) - - return () => { - if (timerRef.current !== null) { - window.clearTimeout(timerRef.current) - } - } - }, [state]) - - const setState = useCallback((next: AppState | ((prev: AppState) => AppState)) => { - setStateInternal((prev) => { - if (typeof next === 'function') { - return (next as (prev: AppState) => AppState)(prev as AppState) - } - return next - }) - }, []) - - const reset = useCallback(async () => { - await api.resetState() - setStateInternal(makeDefaultAppState()) - }, []) - - return { state, setState, status, errorMessage, reset, reload: load } -} diff --git a/src/frontend/src/index.css b/src/frontend/src/index.css deleted file mode 100644 index 95430f3..0000000 --- a/src/frontend/src/index.css +++ /dev/null @@ -1,34 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -@layer base { - html { - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - } - body { - @apply bg-slate-50 text-slate-900; - } -} - -@layer components { - .input-editable { - @apply w-full bg-editable-50 border border-editable-200 rounded px-2 py-1 text-right font-mono text-sm - focus:outline-none focus:ring-2 focus:ring-editable-400 focus:border-editable-400; - } - .input-editable:disabled { - @apply bg-slate-100 text-slate-400 cursor-not-allowed; - } - .cell-calculated { - @apply bg-calculated-100 text-slate-700 font-mono text-sm text-right px-2 py-1; - } - .cell-label { - @apply px-3 py-2 text-sm font-semibold text-slate-700 bg-slate-100 border-b border-slate-200; - } - .cell-input { - @apply px-2 py-1 border-b border-slate-200; - } - .cell-calc { - @apply px-2 py-1 border-b border-slate-200 bg-calculated-50; - } -} diff --git a/src/frontend/src/main.tsx b/src/frontend/src/main.tsx deleted file mode 100644 index 964aeb4..0000000 --- a/src/frontend/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App' -import './index.css' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/src/frontend/src/types.ts b/src/frontend/src/types.ts deleted file mode 100644 index 5b153ef..0000000 --- a/src/frontend/src/types.ts +++ /dev/null @@ -1,53 +0,0 @@ -export type Grado = 'D' | 'C' | 'B' | 'A' | 'S' - -export const GRADOS: Grado[] = ['D', 'C', 'B', 'A', 'S'] - -export type ShotType = 'Soulshot' | 'Spiritshot' | 'Blessed Spiritshot' - -export const SHOT_TYPES: ShotType[] = ['Soulshot', 'Spiritshot', 'Blessed Spiritshot'] - -export type OreType = 'Soul Ore' | 'Spirit Ore' - -export interface Insumos { - cristales: Record - soulOre: number - spiritOre: number - venta: Record> -} - -export interface Formula { - id: string - tipo: string - grado: string - cristalesReq: number - soulOreReq: number | null - spiritOreReq: number | null - shotsObtenidos: number -} - -export type CristalesDisponibles = Record> - -export interface Calculo { - tipo: string - grado: string - cristalesDisponibles: number - cristalesUsados: number - oreNecesario: number - oreLabel: OreType | null - crafteosPosibles: number - shotsObtenidos: number - costoTotal: number - valorVenta: number - ganancia: number - warning: string | null -} - -export interface Totales { - cristalesUsados: number - oreNecesario: number - crafteosPosibles: number - shotsObtenidos: number - costoTotal: number - valorVenta: number - ganancia: number -} diff --git a/src/frontend/src/utils/calc.ts b/src/frontend/src/utils/calc.ts deleted file mode 100644 index e32b553..0000000 --- a/src/frontend/src/utils/calc.ts +++ /dev/null @@ -1,83 +0,0 @@ -import type { Calculo, Formula, Insumos, OreType, Totales } from '../types' - -export function calcularFila( - formula: Formula, - cristalesDisponibles: number, - insumos: Insumos, -): Calculo { - const orePerCraft = formula.soulOreReq ?? formula.spiritOreReq ?? 0 - const oreLabel: OreType | null = - formula.soulOreReq != null ? 'Soul Ore' : formula.spiritOreReq != null ? 'Spirit Ore' : null - - if (formula.cristalesReq <= 0) { - return { - tipo: formula.tipo, - grado: formula.grado, - cristalesDisponibles, - cristalesUsados: 0, - oreNecesario: 0, - oreLabel, - crafteosPosibles: 0, - shotsObtenidos: 0, - costoTotal: 0, - valorVenta: 0, - ganancia: 0, - warning: 'Completa la receta en la pestaña Fórmulas', - } - } - - const crafteosPosibles = Math.floor(cristalesDisponibles / formula.cristalesReq) - const cristalesUsados = crafteosPosibles * formula.cristalesReq - const oreNecesario = crafteosPosibles * orePerCraft - const shotsObtenidos = crafteosPosibles * formula.shotsObtenidos - - const precioCristal = insumos.cristales[formula.grado] - const precioOre = orePerCraft > 0 - ? formula.soulOreReq != null - ? insumos.soulOre - : insumos.spiritOre - : 0 - const precioVenta = insumos.venta[formula.tipo][formula.grado] - - const costoTotal = cristalesUsados * precioCristal + oreNecesario * precioOre - const valorVenta = shotsObtenidos * precioVenta - const ganancia = valorVenta - costoTotal - - return { - tipo: formula.tipo, - grado: formula.grado, - cristalesDisponibles, - cristalesUsados, - oreNecesario, - oreLabel, - crafteosPosibles, - shotsObtenidos, - costoTotal, - valorVenta, - ganancia, - warning: null, - } -} - -export function sumarTotales(calculos: Calculo[]): Totales { - return calculos.reduce( - (acc, c) => ({ - cristalesUsados: acc.cristalesUsados + c.cristalesUsados, - oreNecesario: acc.oreNecesario + c.oreNecesario, - crafteosPosibles: acc.crafteosPosibles + c.crafteosPosibles, - shotsObtenidos: acc.shotsObtenidos + c.shotsObtenidos, - costoTotal: acc.costoTotal + c.costoTotal, - valorVenta: acc.valorVenta + c.valorVenta, - ganancia: acc.ganancia + c.ganancia, - }), - { - cristalesUsados: 0, - oreNecesario: 0, - crafteosPosibles: 0, - shotsObtenidos: 0, - costoTotal: 0, - valorVenta: 0, - ganancia: 0, - }, - ) -} diff --git a/src/frontend/src/utils/format.ts b/src/frontend/src/utils/format.ts deleted file mode 100644 index 07b4e10..0000000 --- a/src/frontend/src/utils/format.ts +++ /dev/null @@ -1,16 +0,0 @@ -const formatter = new Intl.NumberFormat('es-ES', { maximumFractionDigits: 0 }) - -export function formatAdena(n: number): string { - if (!Number.isFinite(n)) return '0' - return formatter.format(Math.round(n)) -} - -export function formatNumber(n: number): string { - return formatter.format(n) -} - -export function parseNumber(value: string): number { - if (value === '' || value === '-') return 0 - const n = Number(value) - return Number.isFinite(n) && n >= 0 ? n : 0 -} diff --git a/src/frontend/tailwind.config.js b/src/frontend/tailwind.config.js deleted file mode 100644 index 691c202..0000000 --- a/src/frontend/tailwind.config.js +++ /dev/null @@ -1,26 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -export default { - content: ['./index.html', './src/**/*.{ts,tsx}'], - theme: { - extend: { - colors: { - editable: { - 50: '#fffbeb', - 100: '#fef3c7', - 200: '#fde68a', - 400: '#fbbf24', - 500: '#f59e0b', - }, - calculated: { - 50: '#f8fafc', - 100: '#f1f5f9', - 200: '#e2e8f0', - }, - }, - fontFamily: { - mono: ['ui-monospace', 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', 'monospace'], - }, - }, - }, - plugins: [], -} diff --git a/src/frontend/tsconfig.app.json b/src/frontend/tsconfig.app.json deleted file mode 100644 index c95ee7f..0000000 --- a/src/frontend/tsconfig.app.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "skipLibCheck": true, - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/src/frontend/tsconfig.json b/src/frontend/tsconfig.json deleted file mode 100644 index 1ffef60..0000000 --- a/src/frontend/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/src/frontend/tsconfig.node.json b/src/frontend/tsconfig.node.json deleted file mode 100644 index 8e5b203..0000000 --- a/src/frontend/tsconfig.node.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "lib": ["ES2023"], - "module": "ESNext", - "skipLibCheck": true, - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["vite.config.ts"] -} diff --git a/src/frontend/vite.config.ts b/src/frontend/vite.config.ts deleted file mode 100644 index fc1203c..0000000 --- a/src/frontend/vite.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' - -export default defineConfig({ - plugins: [react()], - base: './', - build: { - outDir: 'dist', - emptyOutDir: true, - }, - server: { - port: 5173, - proxy: { - '/api': 'http://localhost:8080', - }, - }, -})