From 2bd15aec57c32c521d32d202c6d32c4743a7263e Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 30 Nov 2025 21:43:35 -0300 Subject: [PATCH 001/263] chore(routing): migrate to tanstack router --- package.json | 9 +- pnpm-lock.yaml | 1068 ++++++++++++++++- src/preload/index.d.ts | 3 +- src/renderer/src/app.tsx | 108 +- .../src/components/file-preview/index.tsx | 4 +- .../FinishAnonymizer.styles.ts | 5 + .../finish-anonymizer}/index.tsx | 14 +- .../finish-dataset/FinishDataset.styles.ts | 5 + .../finish-dataset}/index.tsx | 13 +- src/renderer/src/components/index.ts | 101 +- .../onboarding-card/OnboardingCard.styles.ts} | 26 +- .../src/components/onboarding-card/index.tsx | 25 + .../onboarding-grid/index.ts} | 4 +- .../src/components/profile-info/index.tsx | 7 +- src/renderer/src/components/stepper/index.tsx | 3 +- src/renderer/src/components/stepper/utils.ts | 41 +- .../form-group/FormGroup.styles.ts | 0 .../form-group/FormGroup.types.ts | 0 .../form-group/forms/DatosAcusado.tsx | 0 .../form-group/forms/DatosDenunciante.tsx | 0 .../form-group/forms/Decision.tsx | 0 .../form-group/forms/InfoGral.tsx | 0 .../form-group/forms/InfoHecho.tsx | 0 .../form-group/forms/index.ts | 0 .../form-group/forms/options.json | 0 .../validate-dataset}/form-group/index.tsx | 0 .../validate-dataset}/index.tsx | 10 +- .../validate-dataset}/utils.ts | 0 src/renderer/src/features/FeatureRouter.tsx | 16 - .../src/features/ReactQueryProvider.tsx | 49 + .../src/{pages/process => hooks}/useNotify.ts | 14 +- src/renderer/src/hooks/usePredict.ts | 4 +- src/renderer/src/layout/login/index.tsx | 4 +- src/renderer/src/layout/main/Main.types.ts | 5 - .../layout/main/{Main.styles.ts => index.ts} | 0 src/renderer/src/layout/main/index.tsx | 38 - src/renderer/src/pages/finish/Anchor.ts | 7 - src/renderer/src/pages/finish/index.tsx | 13 - src/renderer/src/pages/index.ts | 16 - src/renderer/src/pages/login/index.ts | 2 - src/renderer/src/pages/onboarding/index.tsx | 110 -- src/renderer/src/pages/process/utils.ts | 50 - .../src/pages/validation/anonymizer/index.tsx | 37 - src/renderer/src/pages/validation/index.tsx | 12 - src/renderer/src/routeTree.gen.ts | 337 ++++++ src/renderer/src/routes/__root.tsx | 7 + .../src/routes/app.$feature/finish.tsx | 14 + .../src/routes/app.$feature/index.tsx | 10 + .../src/routes/app.$feature/onboarding.tsx | 131 ++ .../app.$feature/preview.tsx} | 64 +- .../app.$feature/process.tsx} | 104 +- .../src/routes/app.$feature/route.tsx | 52 + .../src/routes/app.$feature/validation.tsx | 51 + .../home._layout/features.tsx} | 21 +- .../Host.tsx => routes/home._layout/host.tsx} | 30 +- .../src/routes/home._layout/index.tsx | 9 + .../src/routes/home._layout/route.tsx | 10 + src/renderer/src/routes/index.tsx | 9 + src/renderer/src/services/aymurai/index.ts | 6 +- src/renderer/src/services/aymurai/schema.ts | 2 +- src/renderer/src/types/react-query.d.ts | 11 + src/renderer/src/utils/process/canContinue.ts | 12 + .../src/utils/process/initProcessState.ts | 13 + vite.config.ts | 9 +- 64 files changed, 2107 insertions(+), 618 deletions(-) create mode 100644 src/renderer/src/components/finish-anonymizer/FinishAnonymizer.styles.ts rename src/renderer/src/{pages/finish/anonymizer => components/finish-anonymizer}/index.tsx (90%) create mode 100644 src/renderer/src/components/finish-dataset/FinishDataset.styles.ts rename src/renderer/src/{pages/finish/dataset => components/finish-dataset}/index.tsx (90%) rename src/renderer/src/{pages/onboarding/Cards.tsx => components/onboarding-card/OnboardingCard.styles.ts} (59%) create mode 100644 src/renderer/src/components/onboarding-card/index.tsx rename src/renderer/src/{pages/onboarding/grid.ts => components/onboarding-grid/index.ts} (75%) rename src/renderer/src/{pages/validation/dataset => components/validate-dataset}/form-group/FormGroup.styles.ts (100%) rename src/renderer/src/{pages/validation/dataset => components/validate-dataset}/form-group/FormGroup.types.ts (100%) rename src/renderer/src/{pages/validation/dataset => components/validate-dataset}/form-group/forms/DatosAcusado.tsx (100%) rename src/renderer/src/{pages/validation/dataset => components/validate-dataset}/form-group/forms/DatosDenunciante.tsx (100%) rename src/renderer/src/{pages/validation/dataset => components/validate-dataset}/form-group/forms/Decision.tsx (100%) rename src/renderer/src/{pages/validation/dataset => components/validate-dataset}/form-group/forms/InfoGral.tsx (100%) rename src/renderer/src/{pages/validation/dataset => components/validate-dataset}/form-group/forms/InfoHecho.tsx (100%) rename src/renderer/src/{pages/validation/dataset => components/validate-dataset}/form-group/forms/index.ts (100%) rename src/renderer/src/{pages/validation/dataset => components/validate-dataset}/form-group/forms/options.json (100%) rename src/renderer/src/{pages/validation/dataset => components/validate-dataset}/form-group/index.tsx (100%) rename src/renderer/src/{pages/validation/dataset => components/validate-dataset}/index.tsx (91%) rename src/renderer/src/{pages/validation/dataset => components/validate-dataset}/utils.ts (100%) delete mode 100644 src/renderer/src/features/FeatureRouter.tsx create mode 100644 src/renderer/src/features/ReactQueryProvider.tsx rename src/renderer/src/{pages/process => hooks}/useNotify.ts (63%) delete mode 100644 src/renderer/src/layout/main/Main.types.ts rename src/renderer/src/layout/main/{Main.styles.ts => index.ts} (100%) delete mode 100644 src/renderer/src/layout/main/index.tsx delete mode 100644 src/renderer/src/pages/finish/Anchor.ts delete mode 100644 src/renderer/src/pages/finish/index.tsx delete mode 100644 src/renderer/src/pages/index.ts delete mode 100644 src/renderer/src/pages/login/index.ts delete mode 100644 src/renderer/src/pages/onboarding/index.tsx delete mode 100644 src/renderer/src/pages/process/utils.ts delete mode 100644 src/renderer/src/pages/validation/anonymizer/index.tsx delete mode 100644 src/renderer/src/pages/validation/index.tsx create mode 100644 src/renderer/src/routeTree.gen.ts create mode 100644 src/renderer/src/routes/__root.tsx create mode 100644 src/renderer/src/routes/app.$feature/finish.tsx create mode 100644 src/renderer/src/routes/app.$feature/index.tsx create mode 100644 src/renderer/src/routes/app.$feature/onboarding.tsx rename src/renderer/src/{pages/preview/index.tsx => routes/app.$feature/preview.tsx} (71%) rename src/renderer/src/{pages/process/index.tsx => routes/app.$feature/process.tsx} (56%) create mode 100644 src/renderer/src/routes/app.$feature/route.tsx create mode 100644 src/renderer/src/routes/app.$feature/validation.tsx rename src/renderer/src/{pages/login/Features.tsx => routes/home._layout/features.tsx} (77%) rename src/renderer/src/{pages/login/Host.tsx => routes/home._layout/host.tsx} (90%) create mode 100644 src/renderer/src/routes/home._layout/index.tsx create mode 100644 src/renderer/src/routes/home._layout/route.tsx create mode 100644 src/renderer/src/routes/index.tsx create mode 100644 src/renderer/src/types/react-query.d.ts create mode 100644 src/renderer/src/utils/process/canContinue.ts create mode 100644 src/renderer/src/utils/process/initProcessState.ts diff --git a/package.json b/package.json index ee45905f..e33c246f 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,8 @@ "dependencies": { "@electron-toolkit/preload": "^3.0.2", "@electron-toolkit/utils": "^4.0.0", + "@tanstack/react-router": "^1.139.12", + "@tanstack/react-router-devtools": "^1.139.12", "electron-squirrel-startup": "^1.0.0" }, "devDependencies": { @@ -41,6 +43,7 @@ "@stitches/react": "^1.2.8", "@tanstack/react-form": "1.11.0", "@tanstack/react-query": "^5.81.1", + "@tanstack/router-plugin": "^1.139.12", "@types/node": "20", "@types/react": "18", "@types/react-dom": "18", @@ -63,7 +66,6 @@ "prettier": "^2.7.1", "react": "18", "react-dom": "18", - "react-router-dom": "6", "regex-escape": "^3.4.10", "typescript": "^5.9.2", "vite": "^6.3.5", @@ -72,9 +74,6 @@ "zustand": "^5.0.7" }, "pnpm": { - "onlyBuiltDependencies": [ - "electron", - "esbuild" - ] + "onlyBuiltDependencies": ["electron", "esbuild"] } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 94834fdb..126177af 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,12 @@ importers: '@electron-toolkit/utils': specifier: ^4.0.0 version: 4.0.0(electron@21.4.4) + '@tanstack/react-router': + specifier: ^1.139.12 + version: 1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/react-router-devtools': + specifier: ^1.139.12 + version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(solid-js@1.9.10)(tsx@4.20.6) electron-squirrel-startup: specifier: ^1.0.0 version: 1.0.1 @@ -48,6 +54,9 @@ importers: '@tanstack/react-query': specifier: ^5.81.1 version: 5.81.1(react@18.3.1) + '@tanstack/router-plugin': + specifier: ^1.139.12 + version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@6.3.5(@types/node@20.19.1)(tsx@4.20.6)) '@types/node': specifier: '20' version: 20.19.1 @@ -62,7 +71,7 @@ importers: version: 3.4.1 '@vitejs/plugin-react': specifier: ^4.5.0 - version: 4.5.0(vite@6.3.5(@types/node@20.19.1)) + version: 4.5.0(vite@6.3.5(@types/node@20.19.1)(tsx@4.20.6)) axios: specifier: ^1.1.3 version: 1.9.0 @@ -86,7 +95,7 @@ importers: version: 3.2.1 electron-vite: specifier: ^3.1.0 - version: 3.1.0(vite@6.3.5(@types/node@20.19.1)) + version: 3.1.0(vite@6.3.5(@types/node@20.19.1)(tsx@4.20.6)) exceljs: specifier: ^4.4.0 version: 4.4.0 @@ -114,9 +123,6 @@ importers: react-dom: specifier: '18' version: 18.3.1(react@18.3.1) - react-router-dom: - specifier: '6' - version: 6.30.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) regex-escape: specifier: ^3.4.10 version: 3.4.11 @@ -125,7 +131,7 @@ importers: version: 5.9.2 vite: specifier: ^6.3.5 - version: 6.3.5(@types/node@20.19.1) + version: 6.3.5(@types/node@20.19.1)(tsx@4.20.6) wait-on: specifier: ^6.0.1 version: 6.0.1 @@ -134,7 +140,7 @@ importers: version: 4.0.14 zustand: specifier: ^5.0.7 - version: 5.0.7(@types/react@18.3.22)(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)) + version: 5.0.7(@types/react@18.3.22)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) packages: @@ -157,14 +163,40 @@ packages: resolution: {integrity: sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==} engines: {node: '>=6.9.0'} + '@babel/core@7.28.5': + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + engines: {node: '>=6.9.0'} + '@babel/generator@7.27.3': resolution: {integrity: sha512-xnlJYj5zepml8NXtjkG0WquFUv8RskFqyFcVgTBp5k+NaA/8uw/K+OSVf8AMGw5e9HKP2ETd5xpK5MLZQD6b4Q==} engines: {node: '>=6.9.0'} + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.27.3': + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.27.2': resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} + '@babel/helper-create-class-features-plugin@7.28.5': + resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.27.1': resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} @@ -175,10 +207,30 @@ packages: peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-module-transforms@7.28.3': + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.27.1': + resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} + engines: {node: '>=6.9.0'} + '@babel/helper-plugin-utils@7.27.1': resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} engines: {node: '>=6.9.0'} + '@babel/helper-replace-supers@7.27.1': + resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} @@ -187,6 +239,10 @@ packages: resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} @@ -195,17 +251,44 @@ packages: resolution: {integrity: sha512-Y+bO6U+I7ZKaM5G5rDUZiYfUvQPUibYmAFe7EnKdnKBbVXDZxvp+MWOH5gYciY0EPk4EScsuFMQBbEfpdRKSCQ==} engines: {node: '>=6.9.0'} + '@babel/helpers@7.28.4': + resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + engines: {node: '>=6.9.0'} + '@babel/parser@7.27.4': resolution: {integrity: sha512-BRmLHGwpUqLFR2jzx9orBuX/ABDkj2jLKOXrHDTN2aOKL+jFDDKaRNo9nyYsIl9h/UE/7lMKdDjKQQyxKKDZ7g==} engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-jsx@7.27.1': + resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.27.1': + resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-arrow-functions@7.27.1': resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-commonjs@7.27.1': + resolution: {integrity: sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-jsx-self@7.27.1': resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} engines: {node: '>=6.9.0'} @@ -218,6 +301,18 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-typescript@7.28.5': + resolution: {integrity: sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-typescript@7.28.5': + resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/runtime@7.27.1': resolution: {integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==} engines: {node: '>=6.9.0'} @@ -230,10 +325,18 @@ packages: resolution: {integrity: sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + '@babel/types@7.27.3': resolution: {integrity: sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==} engines: {node: '>=6.9.0'} + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + '@biomejs/biome@1.9.4': resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} engines: {node: '>=14.21.3'} @@ -609,10 +712,16 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + '@jridgewell/gen-mapping@0.3.8': resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} engines: {node: '>=6.0.0'} + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -627,6 +736,9 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@malept/cross-spawn-promise@1.1.1': resolution: {integrity: sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==} engines: {node: '>= 10'} @@ -664,10 +776,6 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@remix-run/router@1.23.0': - resolution: {integrity: sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==} - engines: {node: '>=14.0.0'} - '@rolldown/pluginutils@1.0.0-beta.9': resolution: {integrity: sha512-e9MeMtVWo186sgvFFJOPGy7/d2j2mZhLJIdVW0C/xDluuOvymEATqz6zKsP0ZmXGzQtqlyjz5sC1sYQUoJG98w==} @@ -676,51 +784,106 @@ packages: cpu: [arm] os: [android] + '@rollup/rollup-android-arm-eabi@4.53.3': + resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} + cpu: [arm] + os: [android] + '@rollup/rollup-android-arm64@4.41.1': resolution: {integrity: sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==} cpu: [arm64] os: [android] + '@rollup/rollup-android-arm64@4.53.3': + resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} + cpu: [arm64] + os: [android] + '@rollup/rollup-darwin-arm64@4.41.1': resolution: {integrity: sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==} cpu: [arm64] os: [darwin] + '@rollup/rollup-darwin-arm64@4.53.3': + resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} + cpu: [arm64] + os: [darwin] + '@rollup/rollup-darwin-x64@4.41.1': resolution: {integrity: sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==} cpu: [x64] os: [darwin] + '@rollup/rollup-darwin-x64@4.53.3': + resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} + cpu: [x64] + os: [darwin] + '@rollup/rollup-freebsd-arm64@4.41.1': resolution: {integrity: sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==} cpu: [arm64] os: [freebsd] + '@rollup/rollup-freebsd-arm64@4.53.3': + resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} + cpu: [arm64] + os: [freebsd] + '@rollup/rollup-freebsd-x64@4.41.1': resolution: {integrity: sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==} cpu: [x64] os: [freebsd] + '@rollup/rollup-freebsd-x64@4.53.3': + resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} + cpu: [x64] + os: [freebsd] + '@rollup/rollup-linux-arm-gnueabihf@4.41.1': resolution: {integrity: sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==} cpu: [arm] os: [linux] + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} + cpu: [arm] + os: [linux] + '@rollup/rollup-linux-arm-musleabihf@4.41.1': resolution: {integrity: sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==} cpu: [arm] os: [linux] + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} + cpu: [arm] + os: [linux] + '@rollup/rollup-linux-arm64-gnu@4.41.1': resolution: {integrity: sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==} cpu: [arm64] os: [linux] + '@rollup/rollup-linux-arm64-gnu@4.53.3': + resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} + cpu: [arm64] + os: [linux] + '@rollup/rollup-linux-arm64-musl@4.41.1': resolution: {integrity: sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==} cpu: [arm64] os: [linux] + '@rollup/rollup-linux-arm64-musl@4.53.3': + resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.53.3': + resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} + cpu: [loong64] + os: [linux] + '@rollup/rollup-linux-loongarch64-gnu@4.41.1': resolution: {integrity: sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==} cpu: [loong64] @@ -731,46 +894,101 @@ packages: cpu: [ppc64] os: [linux] + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} + cpu: [ppc64] + os: [linux] + '@rollup/rollup-linux-riscv64-gnu@4.41.1': resolution: {integrity: sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==} cpu: [riscv64] os: [linux] + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} + cpu: [riscv64] + os: [linux] + '@rollup/rollup-linux-riscv64-musl@4.41.1': resolution: {integrity: sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==} cpu: [riscv64] os: [linux] + '@rollup/rollup-linux-riscv64-musl@4.53.3': + resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} + cpu: [riscv64] + os: [linux] + '@rollup/rollup-linux-s390x-gnu@4.41.1': resolution: {integrity: sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==} cpu: [s390x] os: [linux] + '@rollup/rollup-linux-s390x-gnu@4.53.3': + resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} + cpu: [s390x] + os: [linux] + '@rollup/rollup-linux-x64-gnu@4.41.1': resolution: {integrity: sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==} cpu: [x64] os: [linux] + '@rollup/rollup-linux-x64-gnu@4.53.3': + resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} + cpu: [x64] + os: [linux] + '@rollup/rollup-linux-x64-musl@4.41.1': resolution: {integrity: sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==} cpu: [x64] os: [linux] + '@rollup/rollup-linux-x64-musl@4.53.3': + resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.53.3': + resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} + cpu: [arm64] + os: [openharmony] + '@rollup/rollup-win32-arm64-msvc@4.41.1': resolution: {integrity: sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==} cpu: [arm64] os: [win32] + '@rollup/rollup-win32-arm64-msvc@4.53.3': + resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} + cpu: [arm64] + os: [win32] + '@rollup/rollup-win32-ia32-msvc@4.41.1': resolution: {integrity: sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==} cpu: [ia32] os: [win32] + '@rollup/rollup-win32-ia32-msvc@4.53.3': + resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.53.3': + resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} + cpu: [x64] + os: [win32] + '@rollup/rollup-win32-x64-msvc@4.41.1': resolution: {integrity: sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==} cpu: [x64] os: [win32] + '@rollup/rollup-win32-x64-msvc@4.53.3': + resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} + cpu: [x64] + os: [win32] + '@sideway/address@4.1.5': resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} @@ -804,6 +1022,10 @@ packages: '@tanstack/form-core@1.11.0': resolution: {integrity: sha512-BaEnQ73h4S72AXdjgQowmDBJPHbAvPnWTY2xeY74O7/qfesZKbgPA7DQi5BW1qMv15BkthloJMi9Qljbf5mi7Q==} + '@tanstack/history@1.139.0': + resolution: {integrity: sha512-l6wcxwDBeh/7Dhles23U1O8lp9kNJmAb2yNjekR6olZwCRNAVA8TCXlVCrueELyFlYZqvQkh0ofxnzG62A1Kkg==} + engines: {node: '>=12'} + '@tanstack/query-core@5.81.1': resolution: {integrity: sha512-MAaygDGHHQlfVPYNT+1ZbnY5KsPhFbffDgdQ0YPVhJQyvLby3btnF0oVk9ZEpKEGfl3hEK7YDnNNFT//iX+s0w==} @@ -824,15 +1046,91 @@ packages: peerDependencies: react: ^18 || ^19 + '@tanstack/react-router-devtools@1.139.12': + resolution: {integrity: sha512-deMQGaojEJGFio95o0rDT4OhgtwfgrQIBZAGnXhfyC395n94IuE43uvvv7tkfBzWHQwYK0IvZIeyKMavbvAj7Q==} + engines: {node: '>=12'} + peerDependencies: + '@tanstack/react-router': ^1.139.12 + '@tanstack/router-core': ^1.139.12 + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + peerDependenciesMeta: + '@tanstack/router-core': + optional: true + + '@tanstack/react-router@1.139.12': + resolution: {integrity: sha512-qrIxb8c6XXih6MERZKKwdnYg0OannsQLJ/s+4/wRqKqGCG+QmvAMvnmNP7bfYLgFKi+KsE27HqUkHaSpZSenwQ==} + engines: {node: '>=12'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + '@tanstack/react-store@0.7.0': resolution: {integrity: sha512-S/Rq17HaGOk+tQHV/yrePMnG1xbsKZIl/VsNWnNXt4XW+tTY8dTlvpJH2ZQ3GRALsusG5K6Q3unAGJ2pd9W/Ng==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@tanstack/react-store@0.8.0': + resolution: {integrity: sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/router-core@1.139.12': + resolution: {integrity: sha512-HCDi4fpnAFeDDogT0C61yd2nJn0FrIyFDhyHG3xJji8emdn8Ni4rfyrN4Av46xKkXTPUGdbsqih45+uuNtunew==} + engines: {node: '>=12'} + + '@tanstack/router-devtools-core@1.139.12': + resolution: {integrity: sha512-VARlT9alLnROnPsZtHrSZsqYksIdBBQ24yGzEper5K1+1e0fzpcKLnMYLK9cwr//uWA2xmQayznvBnwcTmnUlg==} + engines: {node: '>=12'} + peerDependencies: + '@tanstack/router-core': ^1.139.12 + csstype: ^3.0.10 + solid-js: '>=1.9.5' + peerDependenciesMeta: + csstype: + optional: true + + '@tanstack/router-generator@1.139.12': + resolution: {integrity: sha512-HGs35aBml+2TVwoynsEc00/9Duw19GeT1fX+JzrY0TKNfMzq/nbjR+xxU8M1w3+gHqfKiITmW70XSZoWkXu9tw==} + engines: {node: '>=12'} + + '@tanstack/router-plugin@1.139.12': + resolution: {integrity: sha512-xX39CcU6GLMaahr6YGNQYRZOQsd1WefgCH99PtY0cxZr9VNAIpJMYPsQY8h/g8A4JI10rHI1tdKxZAvodWjZxw==} + engines: {node: '>=12'} + peerDependencies: + '@rsbuild/core': '>=1.0.2' + '@tanstack/react-router': ^1.139.12 + vite: '>=5.0.0 || >=6.0.0 || >=7.0.0' + vite-plugin-solid: ^2.11.10 + webpack: '>=5.92.0' + peerDependenciesMeta: + '@rsbuild/core': + optional: true + '@tanstack/react-router': + optional: true + vite: + optional: true + vite-plugin-solid: + optional: true + webpack: + optional: true + + '@tanstack/router-utils@1.139.0': + resolution: {integrity: sha512-jT7D6NimWqoFSkid4vCno8gvTyfL1+NHpgm3es0B2UNhKKRV3LngOGilm1m6v8Qvk/gy6Fh/tvB+s+hBl6GhOg==} + engines: {node: '>=12'} + '@tanstack/store@0.7.0': resolution: {integrity: sha512-CNIhdoUsmD2NolYuaIs8VfWM467RK6oIBAW4nPEKZhg1smZ+/CwtCdpURgp7nxSqOaV9oKkzdWD80+bC66F/Jg==} + '@tanstack/store@0.8.0': + resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} + + '@tanstack/virtual-file-routes@1.139.0': + resolution: {integrity: sha512-9PImF1d1tovTUIpjFVa0W7Fwj/MHif7BaaczgJJfbv3sDt1Gh+oW9W9uCw9M3ndEJynnp5ZD/TTs0RGubH5ssg==} + engines: {node: '>=12'} + '@tootallnate/once@2.0.0': resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} @@ -858,6 +1156,9 @@ packages: '@types/estree@1.0.7': resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/fs-extra@9.0.13': resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} @@ -918,6 +1219,11 @@ packages: abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -966,6 +1272,10 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + ansis@4.2.0: + resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + engines: {node: '>=14'} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -999,6 +1309,10 @@ packages: resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} engines: {node: '>=0.8'} + ast-types@0.16.1: + resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + engines: {node: '>=4'} + astral-regex@2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} @@ -1027,6 +1341,9 @@ packages: axios@1.9.0: resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==} + babel-dead-code-elimination@1.0.10: + resolution: {integrity: sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -1191,6 +1508,10 @@ packages: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -1250,6 +1571,9 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-es@2.0.0: + resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + core-util-is@1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} @@ -1383,6 +1707,10 @@ packages: devalue@5.1.1: resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==} + diff@8.0.2: + resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} + engines: {node: '>=0.3.1'} + dir-compare@3.3.0: resolution: {integrity: sha512-J7/et3WlGUCxjdnD3HAAzQ6nsnc0WL6DD7WcwJb7c39iH1+AWfg+9OqzJNaI6PkBwBvm1mhZNL9iY/nRiZXlPg==} @@ -1564,6 +1892,11 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} @@ -1623,6 +1956,15 @@ packages: picomatch: optional: true + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} @@ -1765,6 +2107,9 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1811,6 +2156,11 @@ packages: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} + goober@2.1.18: + resolution: {integrity: sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==} + peerDependencies: + csstype: ^3.0.10 + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -2028,6 +2378,10 @@ packages: resolution: {integrity: sha512-YKBKVkKhty7s8rxddb40oOkuP0NbaeXrQvLin6QMHL7Ypiy2RW9LwOVrVgZRyOrhQlayMd9t+D8yDy8MKFTSDQ==} engines: {node: '>= 18.0.0'} + isbot@5.1.32: + resolution: {integrity: sha512-VNfjM73zz2IBZmdShMfAUg10prm6t7HFUQmNAEOAVS4YH92ZrZcvkMcGX6cIgBJAzWDzPent/EeAtYEHNPNPBQ==} + engines: {node: '>=18'} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -2604,6 +2958,9 @@ packages: resolution: {integrity: sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ==} engines: {node: '>=4'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + pe-library@0.4.1: resolution: {integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==} engines: {node: '>=12', npm: '>=6'} @@ -2628,6 +2985,10 @@ packages: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + pidtree@0.6.0: resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} engines: {node: '>=0.10'} @@ -2653,6 +3014,10 @@ packages: resolution: {integrity: sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + postject@1.0.0-alpha.6: resolution: {integrity: sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==} engines: {node: '>=14.0.0'} @@ -2667,6 +3032,11 @@ packages: engines: {node: '>=10.13.0'} hasBin: true + prettier@3.7.3: + resolution: {integrity: sha512-QgODejq9K3OzoBbuyobZlUhznP5SKwPqp+6Q6xw6o8gnhr4O85L2U915iM2IDcfF2NPXVaM9zlo9tdwipnYwzg==} + engines: {node: '>=14'} + hasBin: true + proc-log@2.0.1: resolution: {integrity: sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -2726,19 +3096,6 @@ packages: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} - react-router-dom@6.30.1: - resolution: {integrity: sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==} - engines: {node: '>=14.0.0'} - peerDependencies: - react: '>=16.8' - react-dom: '>=16.8' - - react-router@6.30.1: - resolution: {integrity: sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - react: '>=16.8' - react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -2769,6 +3126,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + recast@0.23.11: + resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} + engines: {node: '>= 4'} + rechoir@0.8.0: resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} engines: {node: '>= 10.13.0'} @@ -2795,6 +3156,9 @@ packages: resolution: {integrity: sha512-rzB7NnQpOkPHBWFPP3prUMqOP6yg3HkRGgcvR+lDyvyHoY3fZLFLYDkPXh78SPVBAE6VTCk/V+j8we4djg6o4g==} engines: {node: '>=4', npm: '>=2'} + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.10: resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} engines: {node: '>= 0.4'} @@ -2849,6 +3213,11 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rollup@4.53.3: + resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + run-con@1.2.12: resolution: {integrity: sha512-5257ILMYIF4RztL9uoZ7V9Q97zHtNHn5bN3NobeAnzB1P3ASLgg8qocM2u+R18ttp+VEM78N2LK8XcNVtnSRrg==} hasBin: true @@ -2905,6 +3274,26 @@ packages: resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} engines: {node: '>=10'} + seroval-plugins@1.3.3: + resolution: {integrity: sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval-plugins@1.4.0: + resolution: {integrity: sha512-zir1aWzoiax6pbBVjoYVd0O1QQXgIL3eVGBMsBsNmM8Ukq90yGaWlfx0AB9dTS8GPqrOrbXn79vmItCUP9U3BQ==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval@1.3.2: + resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==} + engines: {node: '>=10'} + + seroval@1.4.0: + resolution: {integrity: sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==} + engines: {node: '>=10'} + setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} @@ -2967,6 +3356,9 @@ packages: resolution: {integrity: sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + solid-js@1.9.10: + resolution: {integrity: sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -2978,6 +3370,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + spawn-command@0.0.2: resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} @@ -3098,10 +3494,20 @@ packages: tiny-each-async@2.0.3: resolution: {integrity: sha512-5ROII7nElnAirvFn8g7H7MtpfV1daMcyfTGQwsn/x2VtyV+VPiO5CjReCJtWLvoKTDEDmZocf3cNPraiMnBXLA==} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + tiny-warning@1.0.3: + resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} + tinyglobby@0.2.14: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + tmp-promise@3.0.3: resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} @@ -3141,6 +3547,11 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.20.6: + resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} + engines: {node: '>=18.0.0'} + hasBin: true + tunnel@0.0.6: resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} @@ -3187,6 +3598,10 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} + unplugin@2.3.11: + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} + engines: {node: '>=18.12.0'} + unzip-crx-3@0.2.0: resolution: {integrity: sha512-0+JiUq/z7faJ6oifVB5nSwt589v1KCduqIJupNVDoWSXZtWDmjDGO3RAEOvwJ07w90aoXoP4enKsR7ecMrJtWQ==} @@ -3211,6 +3626,11 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + username@5.1.0: resolution: {integrity: sha512-PCKbdWw85JsYMvmCv5GH3kXmM66rCd9m1hBEDutPNv94b/pqCMT4NtcKyeWYvLFiE8b+ha1Jdl8XAaUdPn5QTg==} engines: {node: '>=8'} @@ -3272,6 +3692,46 @@ packages: yaml: optional: true + vite@7.2.4: + resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + wait-on@6.0.1: resolution: {integrity: sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==} engines: {node: '>=10.0.0'} @@ -3283,6 +3743,9 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -3370,6 +3833,9 @@ packages: resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} engines: {node: '>= 10'} + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.0.14: resolution: {integrity: sha512-nGFJTnJN6cM2v9kXL+SOBq3AtjQby3Mv5ySGFof5UGRHrRioSJ5iG680cYNjE/yWk671nROcpPj4hAS8nyLhSw==} @@ -3428,6 +3894,26 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/core@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.1 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/generator@7.27.3': dependencies: '@babel/parser': 7.27.4 @@ -3436,6 +3922,18 @@ snapshots: '@jridgewell/trace-mapping': 0.3.25 jsesc: 3.1.0 + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.27.3': + dependencies: + '@babel/types': 7.28.5 + '@babel/helper-compilation-targets@7.27.2': dependencies: '@babel/compat-data': 7.27.3 @@ -3444,6 +3942,28 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.28.5 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-member-expression-to-functions@7.28.5': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-imports@7.27.1': dependencies: '@babel/traverse': 7.27.4 @@ -3460,12 +3980,52 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-module-transforms@7.27.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.27.4 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.27.1': + dependencies: + '@babel/types': 7.28.5 + '@babel/helper-plugin-utils@7.27.1': {} + '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + '@babel/helper-string-parser@7.27.1': {} '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-option@7.27.1': {} '@babel/helpers@7.27.4': @@ -3473,15 +4033,42 @@ snapshots: '@babel/template': 7.27.2 '@babel/types': 7.27.3 + '@babel/helpers@7.28.4': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + '@babel/parser@7.27.4': dependencies: '@babel/types': 7.27.3 + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 @@ -3492,6 +4079,28 @@ snapshots: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-transform-typescript@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) + transitivePeerDependencies: + - supports-color + + '@babel/preset-typescript@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) + transitivePeerDependencies: + - supports-color + '@babel/runtime@7.27.1': {} '@babel/template@7.27.2': @@ -3512,11 +4121,28 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + '@babel/types@7.27.3': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@biomejs/biome@1.9.4': optionalDependencies: '@biomejs/cli-darwin-arm64': 1.9.4 @@ -4065,12 +4691,22 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/gen-mapping@0.3.8': dependencies: '@jridgewell/set-array': 1.2.1 '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/set-array@1.2.1': {} @@ -4082,6 +4718,11 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + '@malept/cross-spawn-promise@1.1.1': dependencies: cross-spawn: 7.0.6 @@ -4124,70 +4765,134 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@remix-run/router@1.23.0': {} - '@rolldown/pluginutils@1.0.0-beta.9': {} '@rollup/rollup-android-arm-eabi@4.41.1': optional: true + '@rollup/rollup-android-arm-eabi@4.53.3': + optional: true + '@rollup/rollup-android-arm64@4.41.1': optional: true + '@rollup/rollup-android-arm64@4.53.3': + optional: true + '@rollup/rollup-darwin-arm64@4.41.1': optional: true + '@rollup/rollup-darwin-arm64@4.53.3': + optional: true + '@rollup/rollup-darwin-x64@4.41.1': optional: true + '@rollup/rollup-darwin-x64@4.53.3': + optional: true + '@rollup/rollup-freebsd-arm64@4.41.1': optional: true + '@rollup/rollup-freebsd-arm64@4.53.3': + optional: true + '@rollup/rollup-freebsd-x64@4.41.1': optional: true + '@rollup/rollup-freebsd-x64@4.53.3': + optional: true + '@rollup/rollup-linux-arm-gnueabihf@4.41.1': optional: true + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + optional: true + '@rollup/rollup-linux-arm-musleabihf@4.41.1': optional: true + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + optional: true + '@rollup/rollup-linux-arm64-gnu@4.41.1': optional: true + '@rollup/rollup-linux-arm64-gnu@4.53.3': + optional: true + '@rollup/rollup-linux-arm64-musl@4.41.1': optional: true + '@rollup/rollup-linux-arm64-musl@4.53.3': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.53.3': + optional: true + '@rollup/rollup-linux-loongarch64-gnu@4.41.1': optional: true '@rollup/rollup-linux-powerpc64le-gnu@4.41.1': optional: true + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + optional: true + '@rollup/rollup-linux-riscv64-gnu@4.41.1': optional: true + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + optional: true + '@rollup/rollup-linux-riscv64-musl@4.41.1': optional: true + '@rollup/rollup-linux-riscv64-musl@4.53.3': + optional: true + '@rollup/rollup-linux-s390x-gnu@4.41.1': optional: true + '@rollup/rollup-linux-s390x-gnu@4.53.3': + optional: true + '@rollup/rollup-linux-x64-gnu@4.41.1': optional: true + '@rollup/rollup-linux-x64-gnu@4.53.3': + optional: true + '@rollup/rollup-linux-x64-musl@4.41.1': optional: true + '@rollup/rollup-linux-x64-musl@4.53.3': + optional: true + + '@rollup/rollup-openharmony-arm64@4.53.3': + optional: true + '@rollup/rollup-win32-arm64-msvc@4.41.1': optional: true + '@rollup/rollup-win32-arm64-msvc@4.53.3': + optional: true + '@rollup/rollup-win32-ia32-msvc@4.41.1': optional: true + '@rollup/rollup-win32-ia32-msvc@4.53.3': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.53.3': + optional: true + '@rollup/rollup-win32-x64-msvc@4.41.1': optional: true + '@rollup/rollup-win32-x64-msvc@4.53.3': + optional: true + '@sideway/address@4.1.5': dependencies: '@hapi/hoek': 9.3.0 @@ -4216,6 +4921,8 @@ snapshots: dependencies: '@tanstack/store': 0.7.0 + '@tanstack/history@1.139.0': {} + '@tanstack/query-core@5.81.1': {} '@tanstack/react-form@1.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': @@ -4233,6 +4940,41 @@ snapshots: '@tanstack/query-core': 5.81.1 react: 18.3.1 + '@tanstack/react-router-devtools@1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(solid-js@1.9.10)(tsx@4.20.6)': + dependencies: + '@tanstack/react-router': 1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/router-devtools-core': 1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(solid-js@1.9.10)(tsx@4.20.6) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + vite: 7.2.4(@types/node@20.19.1)(tsx@4.20.6) + optionalDependencies: + '@tanstack/router-core': 1.139.12 + transitivePeerDependencies: + - '@types/node' + - csstype + - jiti + - less + - lightningcss + - sass + - sass-embedded + - solid-js + - stylus + - sugarss + - terser + - tsx + - yaml + + '@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tanstack/history': 1.139.0 + '@tanstack/react-store': 0.8.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/router-core': 1.139.12 + isbot: 5.1.32 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + '@tanstack/react-store@0.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/store': 0.7.0 @@ -4240,8 +4982,100 @@ snapshots: react-dom: 18.3.1(react@18.3.1) use-sync-external-store: 1.5.0(react@18.3.1) + '@tanstack/react-store@0.8.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tanstack/store': 0.8.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + use-sync-external-store: 1.6.0(react@18.3.1) + + '@tanstack/router-core@1.139.12': + dependencies: + '@tanstack/history': 1.139.0 + '@tanstack/store': 0.8.0 + cookie-es: 2.0.0 + seroval: 1.4.0 + seroval-plugins: 1.4.0(seroval@1.4.0) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/router-devtools-core@1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(solid-js@1.9.10)(tsx@4.20.6)': + dependencies: + '@tanstack/router-core': 1.139.12 + clsx: 2.1.1 + goober: 2.1.18(csstype@3.1.3) + solid-js: 1.9.10 + tiny-invariant: 1.3.3 + vite: 7.2.4(@types/node@20.19.1)(tsx@4.20.6) + optionalDependencies: + csstype: 3.1.3 + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + + '@tanstack/router-generator@1.139.12': + dependencies: + '@tanstack/router-core': 1.139.12 + '@tanstack/router-utils': 1.139.0 + '@tanstack/virtual-file-routes': 1.139.0 + prettier: 3.7.3 + recast: 0.23.11 + source-map: 0.7.6 + tsx: 4.20.6 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + '@tanstack/router-plugin@1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@6.3.5(@types/node@20.19.1)(tsx@4.20.6))': + dependencies: + '@babel/core': 7.28.5 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@tanstack/router-core': 1.139.12 + '@tanstack/router-generator': 1.139.12 + '@tanstack/router-utils': 1.139.0 + '@tanstack/virtual-file-routes': 1.139.0 + babel-dead-code-elimination: 1.0.10 + chokidar: 3.6.0 + unplugin: 2.3.11 + zod: 3.25.76 + optionalDependencies: + '@tanstack/react-router': 1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + vite: 6.3.5(@types/node@20.19.1)(tsx@4.20.6) + transitivePeerDependencies: + - supports-color + + '@tanstack/router-utils@1.139.0': + dependencies: + '@babel/core': 7.28.5 + '@babel/generator': 7.28.5 + '@babel/parser': 7.28.5 + '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) + ansis: 4.2.0 + diff: 8.0.2 + pathe: 2.0.3 + tinyglobby: 0.2.15 + transitivePeerDependencies: + - supports-color + '@tanstack/store@0.7.0': {} + '@tanstack/store@0.8.0': {} + + '@tanstack/virtual-file-routes@1.139.0': {} + '@tootallnate/once@2.0.0': {} '@types/babel__core@7.20.5': @@ -4278,6 +5112,8 @@ snapshots: '@types/estree@1.0.7': {} + '@types/estree@1.0.8': {} + '@types/fs-extra@9.0.13': dependencies: '@types/node': 16.18.126 @@ -4329,7 +5165,7 @@ snapshots: '@types/node': 16.18.126 optional: true - '@vitejs/plugin-react@4.5.0(vite@6.3.5(@types/node@20.19.1))': + '@vitejs/plugin-react@4.5.0(vite@6.3.5(@types/node@20.19.1)(tsx@4.20.6))': dependencies: '@babel/core': 7.27.4 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.27.4) @@ -4337,7 +5173,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.9 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.3.5(@types/node@20.19.1) + vite: 6.3.5(@types/node@20.19.1)(tsx@4.20.6) transitivePeerDependencies: - supports-color @@ -4345,6 +5181,8 @@ snapshots: abbrev@1.1.1: {} + acorn@8.15.0: {} + agent-base@6.0.2: dependencies: debug: 4.4.1 @@ -4391,6 +5229,8 @@ snapshots: ansi-styles@6.2.1: {} + ansis@4.2.0: {} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 @@ -4480,6 +5320,10 @@ snapshots: assert-plus@1.0.0: optional: true + ast-types@0.16.1: + dependencies: + tslib: 2.8.1 + astral-regex@2.0.0: {} async-exit-hook@2.0.1: {} @@ -4506,6 +5350,15 @@ snapshots: transitivePeerDependencies: - debug + babel-dead-code-elimination@1.0.10: + dependencies: + '@babel/core': 7.28.5 + '@babel/parser': 7.27.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + balanced-match@1.0.2: {} base64-js@1.5.1: {} @@ -4720,6 +5573,8 @@ snapshots: clone@1.0.4: {} + clsx@2.1.1: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -4779,6 +5634,8 @@ snapshots: convert-source-map@2.0.0: {} + cookie-es@2.0.0: {} + core-util-is@1.0.2: optional: true @@ -4894,6 +5751,8 @@ snapshots: devalue@5.1.1: {} + diff@8.0.2: {} + dir-compare@3.3.0: dependencies: buffer-equal: 1.0.1 @@ -5098,7 +5957,7 @@ snapshots: electron-to-chromium@1.5.161: {} - electron-vite@3.1.0(vite@6.3.5(@types/node@20.19.1)): + electron-vite@3.1.0(vite@6.3.5(@types/node@20.19.1)(tsx@4.20.6)): dependencies: '@babel/core': 7.27.4 '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.27.4) @@ -5106,7 +5965,7 @@ snapshots: esbuild: 0.25.5 magic-string: 0.30.17 picocolors: 1.1.1 - vite: 6.3.5(@types/node@20.19.1) + vite: 6.3.5(@types/node@20.19.1)(tsx@4.20.6) transitivePeerDependencies: - supports-color @@ -5209,6 +6068,8 @@ snapshots: escape-string-regexp@4.0.0: optional: true + esprima@4.0.1: {} + eventemitter3@5.0.1: {} exceljs@4.4.0: @@ -5293,6 +6154,10 @@ snapshots: optionalDependencies: picomatch: 4.0.2 + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + filelist@1.0.4: dependencies: minimatch: 5.1.6 @@ -5459,6 +6324,10 @@ snapshots: get-stream@6.0.1: {} + get-tsconfig@4.13.0: + dependencies: + resolve-pkg-maps: 1.0.0 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -5537,6 +6406,10 @@ snapshots: gopd: 1.2.0 optional: true + goober@2.1.18(csstype@3.1.3): + dependencies: + csstype: 3.1.3 + gopd@1.2.0: {} got@11.8.6: @@ -5736,6 +6609,8 @@ snapshots: isbinaryfile@5.0.4: {} + isbot@5.1.32: {} + isexe@2.0.0: {} jackspeak@3.4.3: @@ -6301,6 +7176,8 @@ snapshots: dependencies: pify: 2.3.0 + pathe@2.0.3: {} + pe-library@0.4.1: {} pend@1.2.0: {} @@ -6315,6 +7192,8 @@ snapshots: picomatch@4.0.2: {} + picomatch@4.0.3: {} + pidtree@0.6.0: {} pify@2.3.0: {} @@ -6338,6 +7217,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + postject@1.0.0-alpha.6: dependencies: commander: 9.5.0 @@ -6347,6 +7232,8 @@ snapshots: prettier@2.8.8: {} + prettier@3.7.3: {} + proc-log@2.0.1: {} process-nextick-args@2.0.1: {} @@ -6390,18 +7277,6 @@ snapshots: react-refresh@0.17.0: {} - react-router-dom@6.30.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@remix-run/router': 1.23.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-router: 6.30.1(react@18.3.1) - - react-router@6.30.1(react@18.3.1): - dependencies: - '@remix-run/router': 1.23.0 - react: 18.3.1 - react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -6447,6 +7322,14 @@ snapshots: dependencies: picomatch: 2.3.1 + recast@0.23.11: + dependencies: + ast-types: 0.16.1 + esprima: 4.0.1 + source-map: 0.6.1 + tiny-invariant: 1.3.3 + tslib: 2.8.1 + rechoir@0.8.0: dependencies: resolve: 1.22.10 @@ -6470,6 +7353,8 @@ snapshots: dependencies: get-installed-path: 2.1.1 + resolve-pkg-maps@1.0.0: {} + resolve@1.22.10: dependencies: is-core-module: 2.16.1 @@ -6548,6 +7433,34 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.41.1 fsevents: 2.3.3 + rollup@4.53.3: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.53.3 + '@rollup/rollup-android-arm64': 4.53.3 + '@rollup/rollup-darwin-arm64': 4.53.3 + '@rollup/rollup-darwin-x64': 4.53.3 + '@rollup/rollup-freebsd-arm64': 4.53.3 + '@rollup/rollup-freebsd-x64': 4.53.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 + '@rollup/rollup-linux-arm-musleabihf': 4.53.3 + '@rollup/rollup-linux-arm64-gnu': 4.53.3 + '@rollup/rollup-linux-arm64-musl': 4.53.3 + '@rollup/rollup-linux-loong64-gnu': 4.53.3 + '@rollup/rollup-linux-ppc64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-musl': 4.53.3 + '@rollup/rollup-linux-s390x-gnu': 4.53.3 + '@rollup/rollup-linux-x64-gnu': 4.53.3 + '@rollup/rollup-linux-x64-musl': 4.53.3 + '@rollup/rollup-openharmony-arm64': 4.53.3 + '@rollup/rollup-win32-arm64-msvc': 4.53.3 + '@rollup/rollup-win32-ia32-msvc': 4.53.3 + '@rollup/rollup-win32-x64-gnu': 4.53.3 + '@rollup/rollup-win32-x64-msvc': 4.53.3 + fsevents: 2.3.3 + run-con@1.2.12: dependencies: deep-extend: 0.6.0 @@ -6599,6 +7512,18 @@ snapshots: type-fest: 0.13.1 optional: true + seroval-plugins@1.3.3(seroval@1.3.2): + dependencies: + seroval: 1.3.2 + + seroval-plugins@1.4.0(seroval@1.4.0): + dependencies: + seroval: 1.4.0 + + seroval@1.3.2: {} + + seroval@1.4.0: {} + setimmediate@1.0.5: {} shebang-command@1.2.0: @@ -6659,6 +7584,12 @@ snapshots: ip-address: 9.0.5 smart-buffer: 4.2.0 + solid-js@1.9.10: + dependencies: + csstype: 3.1.3 + seroval: 1.3.2 + seroval-plugins: 1.3.3(seroval@1.3.2) + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -6668,6 +7599,8 @@ snapshots: source-map@0.6.1: {} + source-map@0.7.6: {} + spawn-command@0.0.2: {} spdx-correct@3.2.0: @@ -6792,11 +7725,20 @@ snapshots: tiny-each-async@2.0.3: optional: true + tiny-invariant@1.3.3: {} + + tiny-warning@1.0.3: {} + tinyglobby@0.2.14: dependencies: fdir: 6.4.5(picomatch@4.0.2) picomatch: 4.0.2 + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + tmp-promise@3.0.3: dependencies: tmp: 0.2.3 @@ -6827,6 +7769,13 @@ snapshots: tslib@2.8.1: {} + tsx@4.20.6: + dependencies: + esbuild: 0.25.5 + get-tsconfig: 4.13.0 + optionalDependencies: + fsevents: 2.3.3 + tunnel@0.0.6: optional: true @@ -6857,6 +7806,13 @@ snapshots: universalify@2.0.1: {} + unplugin@2.3.11: + dependencies: + '@jridgewell/remapping': 2.3.5 + acorn: 8.15.0 + picomatch: 4.0.3 + webpack-virtual-modules: 0.6.2 + unzip-crx-3@0.2.0: dependencies: jszip: 3.10.1 @@ -6894,6 +7850,10 @@ snapshots: dependencies: react: 18.3.1 + use-sync-external-store@1.6.0(react@18.3.1): + dependencies: + react: 18.3.1 + username@5.1.0: dependencies: execa: 1.0.0 @@ -6917,7 +7877,7 @@ snapshots: extsprintf: 1.4.1 optional: true - vite@6.3.5(@types/node@20.19.1): + vite@6.3.5(@types/node@20.19.1)(tsx@4.20.6): dependencies: esbuild: 0.25.5 fdir: 6.4.5(picomatch@4.0.2) @@ -6928,6 +7888,20 @@ snapshots: optionalDependencies: '@types/node': 20.19.1 fsevents: 2.3.3 + tsx: 4.20.6 + + vite@7.2.4(@types/node@20.19.1)(tsx@4.20.6): + dependencies: + esbuild: 0.25.5 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.53.3 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 20.19.1 + fsevents: 2.3.3 + tsx: 4.20.6 wait-on@6.0.1: dependencies: @@ -6945,6 +7919,8 @@ snapshots: webidl-conversions@3.0.1: {} + webpack-virtual-modules@0.6.2: {} + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -7039,10 +8015,12 @@ snapshots: compress-commons: 4.1.2 readable-stream: 3.6.2 + zod@3.25.76: {} + zod@4.0.14: {} - zustand@5.0.7(@types/react@18.3.22)(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)): + zustand@5.0.7(@types/react@18.3.22)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): optionalDependencies: '@types/react': 18.3.22 react: 18.3.1 - use-sync-external-store: 1.5.0(react@18.3.1) + use-sync-external-store: 1.6.0(react@18.3.1) diff --git a/src/preload/index.d.ts b/src/preload/index.d.ts index ed98bddf..5d8869bd 100644 --- a/src/preload/index.d.ts +++ b/src/preload/index.d.ts @@ -19,5 +19,4 @@ declare global { } } -export { }; - +export {}; diff --git a/src/renderer/src/app.tsx b/src/renderer/src/app.tsx index b7fdab0c..19aa0160 100644 --- a/src/renderer/src/app.tsx +++ b/src/renderer/src/app.tsx @@ -1,65 +1,73 @@ -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { - Navigate, + createMemoryHistory, + createRouter, RouterProvider, - createMemoryRouter as createRouter, -} from "react-router-dom"; +} from "@tanstack/react-router"; import { ThemeProvider } from "@/components"; -import LoginLayout from "@/layout/login"; -import MainLayout from "@/layout/main"; -import { - Finish, - LoginFeatures, - LoginHost, - Onboarding, - Preview, - Process, - Validation, -} from "@/pages"; +import * as TanstackReactQuery from "@/features/ReactQueryProvider"; + +// Import the generated route tree +import { routeTree } from "./routeTree.gen"; + +const TanStackQueryProviderContext = TanstackReactQuery.getContext(); -const router = createRouter([ - { - path: "/", - element: , - }, - { - path: "/login", - element: , - children: [ - { index: true, element: }, - { path: "host", element: }, - { path: "features", element: }, - ], - }, - { - // Main as a layout element - path: "app/:feature", - element: , - children: [ - // 1. Onboarding. Explanation of the workflow to process files - { path: "onboarding", element: }, - // 2. Preview. Process the file to get its text contents - { path: "preview", element: }, - // 3. Process. Passes the text contents to the AI to extract predictions - { path: "process", element: }, - // 4. Validation. Validate the predictions/anonymize the file - { path: "validation", element: }, - // 5. Finish. Show the results and download output files - { path: "finish", element: }, - ], - }, -]); +// Create a new router instance +const memoryHistory = createMemoryHistory({ + initialEntries: ["/home/host"], // Pass your initial url +}); +const router = createRouter({ + routeTree, + history: memoryHistory, + context: { ...TanStackQueryProviderContext }, +}); + +declare module "@tanstack/react-router" { + interface Register { + router: typeof router; + } +} -const queryClient = new QueryClient(); +// const router = createRouter([ +// { +// path: "/", +// element: , +// }, +// { +// path: "/login", +// element: , +// children: [ +// { index: true, element: }, +// { path: "host", element: }, +// { path: "features", element: }, +// ], +// }, +// { +// // Main as a layout element +// path: "app/:feature", +// element: , +// children: [ +// // 1. Onboarding. Explanation of the workflow to process files +// { path: "onboarding", element: }, +// // 2. Preview. Process the file to get its text contents +// { path: "preview", element: }, +// // 3. Process. Passes the text contents to the AI to extract predictions +// { path: "process", element: }, +// // 4. Validation. Validate the predictions/anonymize the file +// { path: "validation", element: }, +// // 5. Finish. Show the results and download output files +// { path: "finish", element: }, +// ], +// }, +// ]); export default function App() { return ( - + {/* Stitches global styles */} - + ); } diff --git a/src/renderer/src/components/file-preview/index.tsx b/src/renderer/src/components/file-preview/index.tsx index 64e2974a..e3c86cec 100644 --- a/src/renderer/src/components/file-preview/index.tsx +++ b/src/renderer/src/components/file-preview/index.tsx @@ -7,14 +7,14 @@ import { useFileParser } from "@/services/aymurai/useFileParser"; import type { DocFile } from "@/types/file"; import { Feature } from "@/types/features"; -import { useParams } from "react-router-dom"; +import { useParams } from "@tanstack/react-router"; import * as S from "./FilePreview.styles"; interface Props { file: DocFile; } export default function FilePreview({ file }: Props) { - const { feature } = useParams<{ feature: Feature }>(); + const { feature } = useParams({from:'/app/$feature/preview'}); const dispatch = useFileDispatch(); const { data: parsedFile, isError, isPending } = useFileParser(file.data); diff --git a/src/renderer/src/components/finish-anonymizer/FinishAnonymizer.styles.ts b/src/renderer/src/components/finish-anonymizer/FinishAnonymizer.styles.ts new file mode 100644 index 00000000..83a1f063 --- /dev/null +++ b/src/renderer/src/components/finish-anonymizer/FinishAnonymizer.styles.ts @@ -0,0 +1,5 @@ +import { styled } from "@/styles"; + +export const Anchor = styled("a", { + mr: "auto", +}); \ No newline at end of file diff --git a/src/renderer/src/pages/finish/anonymizer/index.tsx b/src/renderer/src/components/finish-anonymizer/index.tsx similarity index 90% rename from src/renderer/src/pages/finish/anonymizer/index.tsx rename to src/renderer/src/components/finish-anonymizer/index.tsx index 97c6f0fa..481c5518 100644 --- a/src/renderer/src/pages/finish/anonymizer/index.tsx +++ b/src/renderer/src/components/finish-anonymizer/index.tsx @@ -13,9 +13,8 @@ import { useFileDispatch, useFiles } from "@/hooks"; import { Footer, Section } from "@/layout/main"; import { removeAllFiles } from "@/reducers/file/actions"; import { anonymize } from "@/services/aymurai"; -import { useNavigate } from "react-router-dom"; - -import Anchor from "../Anchor"; +import { useNavigate, useParams } from "@tanstack/react-router"; +import * as S from './FinishAnonymizer.styles'; const changeExtension = (name: string) => { const parts = name.split("."); @@ -24,7 +23,8 @@ const changeExtension = (name: string) => { }; type AnonymizeStatus = "loading" | "success" | "error"; -export default function Anonymizer() { +export function FinishAnonymizer() { + const params = useParams({from:'/app/$feature/finish'}) // We are sure that there is only one file, because we came from // anonimization workflow const file = useFiles()[0]; @@ -46,7 +46,7 @@ export default function Anonymizer() { const handleRestart = () => { dispatch(removeAllFiles()); - navigate("/onboarding"); + navigate({to:"/app/$feature/onboarding",params}); }; useEffect(() => { @@ -87,13 +87,13 @@ export default function Anonymizer() {
- DataGenero - + diff --git a/src/renderer/src/components/finish-dataset/FinishDataset.styles.ts b/src/renderer/src/components/finish-dataset/FinishDataset.styles.ts new file mode 100644 index 00000000..83a1f063 --- /dev/null +++ b/src/renderer/src/components/finish-dataset/FinishDataset.styles.ts @@ -0,0 +1,5 @@ +import { styled } from "@/styles"; + +export const Anchor = styled("a", { + mr: "auto", +}); \ No newline at end of file diff --git a/src/renderer/src/pages/finish/dataset/index.tsx b/src/renderer/src/components/finish-dataset/index.tsx similarity index 90% rename from src/renderer/src/pages/finish/dataset/index.tsx rename to src/renderer/src/components/finish-dataset/index.tsx index 8b4dcebf..fde96ece 100644 --- a/src/renderer/src/pages/finish/dataset/index.tsx +++ b/src/renderer/src/components/finish-dataset/index.tsx @@ -1,5 +1,4 @@ import { useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; import { Button, @@ -16,9 +15,11 @@ import { removeAllFiles } from "@/reducers/file/actions"; import filesystem from "@/services/filesystem"; import type { DocFile } from "@/types/file"; import { submitValidations } from "@/utils/file"; -import Anchor from "../Anchor"; +import { useNavigate, useParams } from "@tanstack/react-router"; +import * as S from './FinishDataset.styles'; -export default function Finish() { +export function FinishDataset() { + const params = useParams({from:'/app/$feature/finish'}) const files = useFiles(); const dispatch = useFileDispatch(); const navigate = useNavigate(); @@ -27,7 +28,7 @@ export default function Finish() { const handleRestart = () => { dispatch(removeAllFiles()); - navigate("/onboarding"); + navigate({to:'/app/$feature/onboarding', params}); }; const checkForErrors = (fileName: string) => @@ -90,13 +91,13 @@ export default function Finish() {
- DataGenero - + -
- - ); -} - -export default function Onboarding() { - return ( - - } - ANONYMIZER={ - - } - /> - ); -} diff --git a/src/renderer/src/pages/process/utils.ts b/src/renderer/src/pages/process/utils.ts deleted file mode 100644 index 006c16b1..00000000 --- a/src/renderer/src/pages/process/utils.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { PredictStatus } from "@/hooks/usePredict"; -import type { DocFile } from "@/types/file"; - -type ProcessState = { name: string; status: PredictStatus }; -/** - * Creates the initial state for the `/process` page - * @param files `DocFile[]` state - * @returns An `ProcessState[]` array containing the name of each file and its processing state - */ -export function initProcessState(files: DocFile[]): ProcessState[] { - return files.map(({ data }) => ({ name: data.name, status: "processing" })); -} - -/** - * Checks if the prediction process is completed - * @param state Current files state - * @returns `true` if the prediction process is completed, `false` otherwise - */ -export function isPredictionCompleted(state: ProcessState[]) { - return !state.some(({ status }) => status === "processing"); -} - -export function canContinue(state: ProcessState[]) { - const atLeastOneCompleted = state.some( - ({ status }) => status === "completed", - ); - const hasFinishedProcessing = !state.some( - ({ status }) => status === "processing", - ); - - return hasFinishedProcessing && atLeastOneCompleted; -} - -/** - * Updates the status of a file in the state - * @param name Name of the file to be updated - * @param newValue New `PredictStatus` value to be updated - * @param state `ProcessState[]` state in `/process` page - * @returns A new array with the status of the given file changed - */ -export function replace( - name: string, - value: Partial, - state: ProcessState[], -) { - return state.map((process) => { - if (process.name === name) return { ...process, ...value }; - return process; - }); -} diff --git a/src/renderer/src/pages/validation/anonymizer/index.tsx b/src/renderer/src/pages/validation/anonymizer/index.tsx deleted file mode 100644 index bb93eb1d..00000000 --- a/src/renderer/src/pages/validation/anonymizer/index.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Button, Grid } from "@/components"; -import FileAnnotator from "@/components/file-annotator"; -import { useFiles } from "@/hooks"; -import { Footer } from "@/layout/main"; -import { useNavigate } from "react-router-dom"; - -export default function Validation() { - const file = useFiles()[0]!; - const navigate = useNavigate(); - - const handleContinue = () => navigate("/finish/anonymizer"); - - return ( - <> - - - - -
- -
- - ); -} diff --git a/src/renderer/src/pages/validation/index.tsx b/src/renderer/src/pages/validation/index.tsx deleted file mode 100644 index 8acf2995..00000000 --- a/src/renderer/src/pages/validation/index.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import FeatureRouter from "@/features/FeatureRouter"; -import Anonymizer from "./anonymizer"; -import Dataset from "./dataset"; - -export default function Validation() { - return ( - } - ANONYMIZER={} - /> - ); -} diff --git a/src/renderer/src/routeTree.gen.ts b/src/renderer/src/routeTree.gen.ts new file mode 100644 index 00000000..ceb86f2b --- /dev/null +++ b/src/renderer/src/routeTree.gen.ts @@ -0,0 +1,337 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { createFileRoute } from '@tanstack/react-router' + +import { Route as rootRouteImport } from './routes/__root' +import { Route as IndexRouteImport } from './routes/index' +import { Route as HomeLayoutRouteRouteImport } from './routes/home._layout/route' +import { Route as AppFeatureRouteRouteImport } from './routes/app.$feature/route' +import { Route as HomeLayoutIndexRouteImport } from './routes/home._layout/index' +import { Route as AppFeatureIndexRouteImport } from './routes/app.$feature/index' +import { Route as HomeLayoutHostRouteImport } from './routes/home._layout/host' +import { Route as HomeLayoutFeaturesRouteImport } from './routes/home._layout/features' +import { Route as AppFeatureValidationRouteImport } from './routes/app.$feature/validation' +import { Route as AppFeatureProcessRouteImport } from './routes/app.$feature/process' +import { Route as AppFeaturePreviewRouteImport } from './routes/app.$feature/preview' +import { Route as AppFeatureOnboardingRouteImport } from './routes/app.$feature/onboarding' +import { Route as AppFeatureFinishRouteImport } from './routes/app.$feature/finish' + +const HomeRouteImport = createFileRoute('/home')() + +const HomeRoute = HomeRouteImport.update({ + id: '/home', + path: '/home', + getParentRoute: () => rootRouteImport, +} as any) +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) +const HomeLayoutRouteRoute = HomeLayoutRouteRouteImport.update({ + id: '/_layout', + getParentRoute: () => HomeRoute, +} as any) +const AppFeatureRouteRoute = AppFeatureRouteRouteImport.update({ + id: '/app/$feature', + path: '/app/$feature', + getParentRoute: () => rootRouteImport, +} as any) +const HomeLayoutIndexRoute = HomeLayoutIndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => HomeLayoutRouteRoute, +} as any) +const AppFeatureIndexRoute = AppFeatureIndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => AppFeatureRouteRoute, +} as any) +const HomeLayoutHostRoute = HomeLayoutHostRouteImport.update({ + id: '/host', + path: '/host', + getParentRoute: () => HomeLayoutRouteRoute, +} as any) +const HomeLayoutFeaturesRoute = HomeLayoutFeaturesRouteImport.update({ + id: '/features', + path: '/features', + getParentRoute: () => HomeLayoutRouteRoute, +} as any) +const AppFeatureValidationRoute = AppFeatureValidationRouteImport.update({ + id: '/validation', + path: '/validation', + getParentRoute: () => AppFeatureRouteRoute, +} as any) +const AppFeatureProcessRoute = AppFeatureProcessRouteImport.update({ + id: '/process', + path: '/process', + getParentRoute: () => AppFeatureRouteRoute, +} as any) +const AppFeaturePreviewRoute = AppFeaturePreviewRouteImport.update({ + id: '/preview', + path: '/preview', + getParentRoute: () => AppFeatureRouteRoute, +} as any) +const AppFeatureOnboardingRoute = AppFeatureOnboardingRouteImport.update({ + id: '/onboarding', + path: '/onboarding', + getParentRoute: () => AppFeatureRouteRoute, +} as any) +const AppFeatureFinishRoute = AppFeatureFinishRouteImport.update({ + id: '/finish', + path: '/finish', + getParentRoute: () => AppFeatureRouteRoute, +} as any) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute + '/app/$feature': typeof AppFeatureRouteRouteWithChildren + '/home': typeof HomeLayoutRouteRouteWithChildren + '/app/$feature/finish': typeof AppFeatureFinishRoute + '/app/$feature/onboarding': typeof AppFeatureOnboardingRoute + '/app/$feature/preview': typeof AppFeaturePreviewRoute + '/app/$feature/process': typeof AppFeatureProcessRoute + '/app/$feature/validation': typeof AppFeatureValidationRoute + '/home/features': typeof HomeLayoutFeaturesRoute + '/home/host': typeof HomeLayoutHostRoute + '/app/$feature/': typeof AppFeatureIndexRoute + '/home/': typeof HomeLayoutIndexRoute +} +export interface FileRoutesByTo { + '/': typeof IndexRoute + '/home': typeof HomeLayoutIndexRoute + '/app/$feature/finish': typeof AppFeatureFinishRoute + '/app/$feature/onboarding': typeof AppFeatureOnboardingRoute + '/app/$feature/preview': typeof AppFeaturePreviewRoute + '/app/$feature/process': typeof AppFeatureProcessRoute + '/app/$feature/validation': typeof AppFeatureValidationRoute + '/home/features': typeof HomeLayoutFeaturesRoute + '/home/host': typeof HomeLayoutHostRoute + '/app/$feature': typeof AppFeatureIndexRoute +} +export interface FileRoutesById { + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/app/$feature': typeof AppFeatureRouteRouteWithChildren + '/home': typeof HomeRouteWithChildren + '/home/_layout': typeof HomeLayoutRouteRouteWithChildren + '/app/$feature/finish': typeof AppFeatureFinishRoute + '/app/$feature/onboarding': typeof AppFeatureOnboardingRoute + '/app/$feature/preview': typeof AppFeaturePreviewRoute + '/app/$feature/process': typeof AppFeatureProcessRoute + '/app/$feature/validation': typeof AppFeatureValidationRoute + '/home/_layout/features': typeof HomeLayoutFeaturesRoute + '/home/_layout/host': typeof HomeLayoutHostRoute + '/app/$feature/': typeof AppFeatureIndexRoute + '/home/_layout/': typeof HomeLayoutIndexRoute +} +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: + | '/' + | '/app/$feature' + | '/home' + | '/app/$feature/finish' + | '/app/$feature/onboarding' + | '/app/$feature/preview' + | '/app/$feature/process' + | '/app/$feature/validation' + | '/home/features' + | '/home/host' + | '/app/$feature/' + | '/home/' + fileRoutesByTo: FileRoutesByTo + to: + | '/' + | '/home' + | '/app/$feature/finish' + | '/app/$feature/onboarding' + | '/app/$feature/preview' + | '/app/$feature/process' + | '/app/$feature/validation' + | '/home/features' + | '/home/host' + | '/app/$feature' + id: + | '__root__' + | '/' + | '/app/$feature' + | '/home' + | '/home/_layout' + | '/app/$feature/finish' + | '/app/$feature/onboarding' + | '/app/$feature/preview' + | '/app/$feature/process' + | '/app/$feature/validation' + | '/home/_layout/features' + | '/home/_layout/host' + | '/app/$feature/' + | '/home/_layout/' + fileRoutesById: FileRoutesById +} +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute + AppFeatureRouteRoute: typeof AppFeatureRouteRouteWithChildren + HomeRoute: typeof HomeRouteWithChildren +} + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/home': { + id: '/home' + path: '/home' + fullPath: '/home' + preLoaderRoute: typeof HomeRouteImport + parentRoute: typeof rootRouteImport + } + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + '/home/_layout': { + id: '/home/_layout' + path: '/home' + fullPath: '/home' + preLoaderRoute: typeof HomeLayoutRouteRouteImport + parentRoute: typeof HomeRoute + } + '/app/$feature': { + id: '/app/$feature' + path: '/app/$feature' + fullPath: '/app/$feature' + preLoaderRoute: typeof AppFeatureRouteRouteImport + parentRoute: typeof rootRouteImport + } + '/home/_layout/': { + id: '/home/_layout/' + path: '/' + fullPath: '/home/' + preLoaderRoute: typeof HomeLayoutIndexRouteImport + parentRoute: typeof HomeLayoutRouteRoute + } + '/app/$feature/': { + id: '/app/$feature/' + path: '/' + fullPath: '/app/$feature/' + preLoaderRoute: typeof AppFeatureIndexRouteImport + parentRoute: typeof AppFeatureRouteRoute + } + '/home/_layout/host': { + id: '/home/_layout/host' + path: '/host' + fullPath: '/home/host' + preLoaderRoute: typeof HomeLayoutHostRouteImport + parentRoute: typeof HomeLayoutRouteRoute + } + '/home/_layout/features': { + id: '/home/_layout/features' + path: '/features' + fullPath: '/home/features' + preLoaderRoute: typeof HomeLayoutFeaturesRouteImport + parentRoute: typeof HomeLayoutRouteRoute + } + '/app/$feature/validation': { + id: '/app/$feature/validation' + path: '/validation' + fullPath: '/app/$feature/validation' + preLoaderRoute: typeof AppFeatureValidationRouteImport + parentRoute: typeof AppFeatureRouteRoute + } + '/app/$feature/process': { + id: '/app/$feature/process' + path: '/process' + fullPath: '/app/$feature/process' + preLoaderRoute: typeof AppFeatureProcessRouteImport + parentRoute: typeof AppFeatureRouteRoute + } + '/app/$feature/preview': { + id: '/app/$feature/preview' + path: '/preview' + fullPath: '/app/$feature/preview' + preLoaderRoute: typeof AppFeaturePreviewRouteImport + parentRoute: typeof AppFeatureRouteRoute + } + '/app/$feature/onboarding': { + id: '/app/$feature/onboarding' + path: '/onboarding' + fullPath: '/app/$feature/onboarding' + preLoaderRoute: typeof AppFeatureOnboardingRouteImport + parentRoute: typeof AppFeatureRouteRoute + } + '/app/$feature/finish': { + id: '/app/$feature/finish' + path: '/finish' + fullPath: '/app/$feature/finish' + preLoaderRoute: typeof AppFeatureFinishRouteImport + parentRoute: typeof AppFeatureRouteRoute + } + } +} + +interface AppFeatureRouteRouteChildren { + AppFeatureFinishRoute: typeof AppFeatureFinishRoute + AppFeatureOnboardingRoute: typeof AppFeatureOnboardingRoute + AppFeaturePreviewRoute: typeof AppFeaturePreviewRoute + AppFeatureProcessRoute: typeof AppFeatureProcessRoute + AppFeatureValidationRoute: typeof AppFeatureValidationRoute + AppFeatureIndexRoute: typeof AppFeatureIndexRoute +} + +const AppFeatureRouteRouteChildren: AppFeatureRouteRouteChildren = { + AppFeatureFinishRoute: AppFeatureFinishRoute, + AppFeatureOnboardingRoute: AppFeatureOnboardingRoute, + AppFeaturePreviewRoute: AppFeaturePreviewRoute, + AppFeatureProcessRoute: AppFeatureProcessRoute, + AppFeatureValidationRoute: AppFeatureValidationRoute, + AppFeatureIndexRoute: AppFeatureIndexRoute, +} + +const AppFeatureRouteRouteWithChildren = AppFeatureRouteRoute._addFileChildren( + AppFeatureRouteRouteChildren, +) + +interface HomeLayoutRouteRouteChildren { + HomeLayoutFeaturesRoute: typeof HomeLayoutFeaturesRoute + HomeLayoutHostRoute: typeof HomeLayoutHostRoute + HomeLayoutIndexRoute: typeof HomeLayoutIndexRoute +} + +const HomeLayoutRouteRouteChildren: HomeLayoutRouteRouteChildren = { + HomeLayoutFeaturesRoute: HomeLayoutFeaturesRoute, + HomeLayoutHostRoute: HomeLayoutHostRoute, + HomeLayoutIndexRoute: HomeLayoutIndexRoute, +} + +const HomeLayoutRouteRouteWithChildren = HomeLayoutRouteRoute._addFileChildren( + HomeLayoutRouteRouteChildren, +) + +interface HomeRouteChildren { + HomeLayoutRouteRoute: typeof HomeLayoutRouteRouteWithChildren +} + +const HomeRouteChildren: HomeRouteChildren = { + HomeLayoutRouteRoute: HomeLayoutRouteRouteWithChildren, +} + +const HomeRouteWithChildren = HomeRoute._addFileChildren(HomeRouteChildren) + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, + AppFeatureRouteRoute: AppFeatureRouteRouteWithChildren, + HomeRoute: HomeRouteWithChildren, +} +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() diff --git a/src/renderer/src/routes/__root.tsx b/src/renderer/src/routes/__root.tsx new file mode 100644 index 00000000..fa1706d2 --- /dev/null +++ b/src/renderer/src/routes/__root.tsx @@ -0,0 +1,7 @@ +import { createRootRoute, Outlet } from "@tanstack/react-router"; + +export const Route = createRootRoute({ component: RootLayout }); + +function RootLayout() { + return ; +} diff --git a/src/renderer/src/routes/app.$feature/finish.tsx b/src/renderer/src/routes/app.$feature/finish.tsx new file mode 100644 index 00000000..c936de99 --- /dev/null +++ b/src/renderer/src/routes/app.$feature/finish.tsx @@ -0,0 +1,14 @@ +import { FinishAnonymizer, FinishDataset } from '@/components' +import { Feature } from '@/types/features' +import { createFileRoute, useParams } from '@tanstack/react-router' + +export const Route = createFileRoute('/app/$feature/finish')({ + component: RouteComponent, +}) + +function RouteComponent() { + const {feature} = useParams({from:'/app/$feature/finish'}) + + if (feature === Feature.Dataset) return + return +} diff --git a/src/renderer/src/routes/app.$feature/index.tsx b/src/renderer/src/routes/app.$feature/index.tsx new file mode 100644 index 00000000..59d8c054 --- /dev/null +++ b/src/renderer/src/routes/app.$feature/index.tsx @@ -0,0 +1,10 @@ +import { createFileRoute, redirect } from "@tanstack/react-router"; + +export const Route = createFileRoute("/app/$feature/")({ + beforeLoad: ({ params }) => { + throw redirect({ + to: "/app/$feature/onboarding", + params: { feature: params.feature }, + }); + }, +}); diff --git a/src/renderer/src/routes/app.$feature/onboarding.tsx b/src/renderer/src/routes/app.$feature/onboarding.tsx new file mode 100644 index 00000000..4977fb66 --- /dev/null +++ b/src/renderer/src/routes/app.$feature/onboarding.tsx @@ -0,0 +1,131 @@ +import { + createFileRoute, + useNavigate, + useParams, +} from "@tanstack/react-router"; +import { useRef } from "react"; + +import { useFileDispatch } from "@/hooks"; +import { addFiles } from "@/reducers/file/actions"; + +import { + Button, + HiddenInput, + OnboardingCard, + OnboardingGrid, + Stack, + Text, + Title, +} from "@/components"; +import { Footer, Section } from "@/layout/main"; +import { Feature } from "@/types/features"; + +// FIRST step of the processing workflow +export const Route = createFileRoute("/app/$feature/onboarding")({ + component: RouteComponent, +}); + +interface GenericOnboardingProps { + description: string; + actionText: string; + steps: string[]; + multipleFiles: boolean; +} +function GenericOnboarding({ + description, + actionText, + steps, + multipleFiles, +}: GenericOnboardingProps) { + const { feature } = useParams({ from: "/app/$feature/onboarding" }); + const inputRef = useRef(null); + const dispatch = useFileDispatch(); + const navigate = useNavigate(); + + const handleSelectFile = () => { + inputRef.current?.click(); + }; + + const handleAddedFiles: React.ChangeEventHandler = (e) => { + const rawFiles = e.target.files; + + // Check if any file was added + if (rawFiles) { + const files = Array.from(rawFiles); + + dispatch(addFiles(files)); + navigate({ + to: "/app/$feature/preview", + params: { feature }, + }); + } + }; + + return ( + <> + {/* Onboarding description */} +
+ + ¿Cómo funciona AymurAI? + {description} + + + {steps.map((step, index) => ( + + ))} + +
+ + {/* Input file */} +
+ + Formatos válidos: .docx, .pdf + +
+ + ); +} + +function RouteComponent() { + const { feature } = useParams({ + from: "/app/$feature/onboarding", + }); + + if (feature === Feature.Dataset) + return ( + + ); + else + return ( + + ); +} diff --git a/src/renderer/src/pages/preview/index.tsx b/src/renderer/src/routes/app.$feature/preview.tsx similarity index 71% rename from src/renderer/src/pages/preview/index.tsx rename to src/renderer/src/routes/app.$feature/preview.tsx index 20c32849..d9f0a124 100644 --- a/src/renderer/src/pages/preview/index.tsx +++ b/src/renderer/src/routes/app.$feature/preview.tsx @@ -1,6 +1,3 @@ -import { type ChangeEventHandler, useRef } from "react"; -import { useNavigate } from "react-router-dom"; - import { Button, Card, @@ -11,7 +8,6 @@ import { Subtitle, Text, } from "@/components"; -import FeatureRouter from "@/features/FeatureRouter"; import { useFileDispatch, useFiles } from "@/hooks"; import { Footer, Section } from "@/layout/main"; import { @@ -19,12 +15,24 @@ import { filterUnselected, removeAllFiles, } from "@/reducers/file/actions"; +import { Feature } from "@/types/features"; +import { + createFileRoute, + useNavigate, + useParams, +} from "@tanstack/react-router"; +import { useRef } from "react"; + +export const Route = createFileRoute("/app/$feature/preview")({ + component: RouteComponent, +}); interface GenericPreviewProps { title: string; supportMultipleFiles: boolean; } function GenericPreview({ title, supportMultipleFiles }: GenericPreviewProps) { + const { feature } = useParams({ from: "/app/$feature/preview" }); const inputRef = useRef(null); const navigate = useNavigate(); @@ -35,14 +43,17 @@ function GenericPreview({ title, supportMultipleFiles }: GenericPreviewProps) { const handlePrevious = () => { dispatch(removeAllFiles()); - navigate("../onboarding"); + navigate({ + to: "/app/$feature/onboarding", + params: { feature }, + }); }; const handleSelectFile = () => { inputRef.current?.click(); }; - const handleAddedFiles: ChangeEventHandler = (e) => { + const handleAddedFiles: React.ChangeEventHandler = (e) => { const rawFiles = e.target.files; // Check if any file was added @@ -55,7 +66,10 @@ function GenericPreview({ title, supportMultipleFiles }: GenericPreviewProps) { const handleConfirmFiles = () => { dispatch(filterUnselected()); - navigate("../process"); + navigate({ + to: "/app/$feature/process", + params: { feature }, + }); }; return ( @@ -110,21 +124,23 @@ function GenericPreview({ title, supportMultipleFiles }: GenericPreviewProps) { ); } -export default function Preview() { - return ( - - } - ANONYMIZER={ - - } - /> - ); +function RouteComponent() { + const { feature } = useParams({ + from: "/app/$feature/onboarding", + }); + + if (feature === Feature.Dataset) + return ( + + ); + else + return ( + + ); } diff --git a/src/renderer/src/pages/process/index.tsx b/src/renderer/src/routes/app.$feature/process.tsx similarity index 56% rename from src/renderer/src/pages/process/index.tsx rename to src/renderer/src/routes/app.$feature/process.tsx index 5369e2aa..9817fd56 100644 --- a/src/renderer/src/pages/process/index.tsx +++ b/src/renderer/src/routes/app.$feature/process.tsx @@ -1,7 +1,3 @@ -import { Bell } from "phosphor-react"; -import { useState } from "react"; -import { useNavigate } from "react-router-dom"; - import { Button, Card, @@ -13,22 +9,60 @@ import { Toast, } from "@/components"; import { useFileDispatch, useFiles } from "@/hooks"; -import type { PredictStatus } from "@/hooks/usePredict"; +import useNotify from "@/hooks/useNotify"; +import { PredictStatus } from "@/hooks/usePredict"; import { Footer, Section } from "@/layout/main"; import { filterUnprocessed, removeAllPredictions, } from "@/reducers/file/actions"; +import { Feature } from "@/types/features"; +import { canContinue } from "@/utils/process/canContinue"; +import { + initProcessState, + ProcessState, +} from "@/utils/process/initProcessState"; +import { + createFileRoute, + useNavigate, + useParams, +} from "@tanstack/react-router"; +import { Bell } from "phosphor-react"; +import { useState } from "react"; -import FeatureRouter from "@/features/FeatureRouter"; -import useNotify from "./useNotify"; -import { canContinue, initProcessState, replace } from "./utils"; +export const Route = createFileRoute("/app/$feature/process")({ + component: RouteComponent, +}); + +/** + * Updates the status of a file in the state + * @param name Name of the file to be updated + * @param newValue New `PredictStatus` value to be updated + * @param state `ProcessState[]` state in `/process` page + * @returns A new array with the status of the given file changed + */ +function replace( + name: string, + value: Partial, + state: ProcessState[], +) { + return state.map((process) => { + if (process.name === name) return { ...process, ...value }; + return process; + }); +} interface GenericProcessProps { title: string; + finishText: string; supportMultipleFiles: boolean; } -function GenericProcess({ title, supportMultipleFiles }: GenericProcessProps) { +function GenericProcess({ + title, + supportMultipleFiles, + finishText, +}: GenericProcessProps) { + const { feature } = useParams({ from: "/app/$feature/process" }); const navigate = useNavigate(); const dispatch = useFileDispatch(); const files = useFiles(); @@ -46,22 +80,26 @@ function GenericProcess({ title, supportMultipleFiles }: GenericProcessProps) { }; const handlePrevious = () => { - navigate("../preview"); + navigate({ + to: "/app/$feature/preview", + params: { feature }, + }); dispatch(removeAllPredictions()); }; const handleNext = () => { dispatch(filterUnprocessed()); - navigate("../validation"); + navigate({ + to: "/app/$feature/validation", + params: { feature }, + }); }; return ( <>
}> - {supportMultipleFiles - ? "Se finalizó el análisis de tus documentos." - : "Se finalizó el análisis del documento."} + {finishText} {title} @@ -96,21 +134,25 @@ function GenericProcess({ title, supportMultipleFiles }: GenericProcessProps) { ); } -export default function Process() { - return ( - - } - ANONYMIZER={ - - } - /> - ); +function RouteComponent() { + const { feature } = useParams({ + from: "/app/$feature/process", + }); + + if (feature === Feature.Dataset) + return ( + + ); + else + return ( + + ); } diff --git a/src/renderer/src/routes/app.$feature/route.tsx b/src/renderer/src/routes/app.$feature/route.tsx new file mode 100644 index 00000000..3a66f584 --- /dev/null +++ b/src/renderer/src/routes/app.$feature/route.tsx @@ -0,0 +1,52 @@ +import { createFileRoute, Outlet, redirect } from "@tanstack/react-router"; +import { z } from "zod"; + +import { ProfileInfo, Stepper, Title } from "@/components"; +import FileProvider from "@/context/File"; +import { Header, Layout } from "@/layout/main"; +import { Feature } from "@/types/features"; + +// Validation schema for feature parameter +const featureParamSchema = z.object({ + feature: z.enum([Feature.Dataset, Feature.Anonymizer]), +}); + +export const Route = createFileRoute("/app/$feature")({ + // Parse and validate params + params: { + parse: (params) => { + try { + return featureParamSchema.parse(params); + } catch { + throw redirect({ to: "/home/features" }); + } + }, + stringify: (params) => params, + }, + component: AppLayoutRoute, +}); + +function AppLayoutRoute() { + const { feature } = Route.useParams(); + + // Determine title based on feature + const title = feature === Feature.Dataset ? "Set de datos" : "Anonimizador"; + + return ( + +
+ {/* Title & Profile picture & Logout */} + + AymurAI {title} + + + +
+ + + {/* Child routes render here */} + + +
+ ); +} diff --git a/src/renderer/src/routes/app.$feature/validation.tsx b/src/renderer/src/routes/app.$feature/validation.tsx new file mode 100644 index 00000000..62b62826 --- /dev/null +++ b/src/renderer/src/routes/app.$feature/validation.tsx @@ -0,0 +1,51 @@ +import { Button, FileAnnotator, Grid, ValidateDataset } from "@/components"; +import { useFiles } from "@/hooks"; +import { Footer } from "@/layout/main"; +import { Feature } from "@/types/features"; +import { createFileRoute, useNavigate, useParams } from "@tanstack/react-router"; + +export const Route = createFileRoute("/app/$feature/validation")({ + component: ValidationRoute, +}); + +function ValidateAnonymizer() { + const {feature} = useParams({ + from: "/app/$feature/validation" + }) + const file = useFiles()[0]!; + const navigate = useNavigate(); + + const handleContinue = () => navigate({to: "/app/$feature/finish", params: {feature}}); + + return ( + <> + + + + +
+ +
+ + ); +} + +function ValidationRoute() { + const { feature } = Route.useParams(); + + if (feature === Feature.Dataset) return ; + return ; +} diff --git a/src/renderer/src/pages/login/Features.tsx b/src/renderer/src/routes/home._layout/features.tsx similarity index 77% rename from src/renderer/src/pages/login/Features.tsx rename to src/renderer/src/routes/home._layout/features.tsx index d406498b..013f5144 100644 --- a/src/renderer/src/pages/login/Features.tsx +++ b/src/renderer/src/routes/home._layout/features.tsx @@ -1,17 +1,25 @@ import { Button, Stack, Subtitle } from "@/components"; import { Feature } from "@/types/features"; +import { createFileRoute, useNavigate } from "@tanstack/react-router"; import { ArrowBendUpLeft, Database, Detective } from "phosphor-react"; -import { useNavigate } from "react-router-dom"; -export function Features() { + +export const Route = createFileRoute("/home/_layout/features")({ + component: RouteComponent, +}); + +function RouteComponent() { const navigate = useNavigate(); const handleBack = () => { - navigate("/login"); + navigate({to:'/home'}); }; const handleSelectFeature = (feature: Feature) => () => { - navigate(`/app/${feature}/onboarding`); + navigate({ + to:"/app/$feature/onboarding", + params: {feature} + }) }; return ( @@ -40,5 +48,8 @@ export function Features() { Volver al inicio - ); + ) } + + + diff --git a/src/renderer/src/pages/login/Host.tsx b/src/renderer/src/routes/home._layout/host.tsx similarity index 90% rename from src/renderer/src/pages/login/Host.tsx rename to src/renderer/src/routes/home._layout/host.tsx index 111a2dbb..5918fbbb 100644 --- a/src/renderer/src/pages/login/Host.tsx +++ b/src/renderer/src/routes/home._layout/host.tsx @@ -1,15 +1,13 @@ +import { Button, Input, Label, Stack, Subtitle } from "@/components"; +import { useConnectToHost, useRunLocalServer } from "@/services/aymurai"; +import { localStore } from "@/store/useLocal"; +import { createFileRoute, useNavigate } from "@tanstack/react-router"; import { AxiosError } from "axios"; import { ArrowBendUpLeft, HardDrives, Monitor } from "phosphor-react"; import { useState } from "react"; -import { useNavigate } from "react-router-dom"; import { ZodError } from "zod"; -import { Button, Input, Label, Stack, Subtitle } from "@/components"; - -import { useConnectToHost, useRunLocalServer } from "@/services/aymurai"; -import { localStore } from "@/store/useLocal"; - -const errorMessage = (err: Error) => { +function errorMessage(err: Error): string { if (err instanceof AxiosError) { if (err.code === "ERR_NETWORK") return "No se pudo conectar al servidor"; return "Error de conexión"; @@ -20,9 +18,13 @@ const errorMessage = (err: Error) => { } return "Error desconocido"; -}; +} + +export const Route = createFileRoute("/home/_layout/host")({ + component: RouteComponent, +}); -export function Host() { +function RouteComponent() { const navigate = useNavigate(); const [isLocal, setIsLocal] = useState(null); @@ -31,7 +33,10 @@ export function Host() { const { setServerHost } = localStore.useServerHostActions(); const { mutate: connectToHost, isPending, error, reset } = useConnectToHost(); const { run: runLocalServer, isRunning } = useRunLocalServer({ - onSuccess: () => navigate("/login/features"), + onSuccess: () => + navigate({ + to: "/home/features", + }), }); const handleBack = () => { @@ -48,7 +53,10 @@ export function Host() { const tryConnection = () => { connectToHost(remoteHost, { - onSuccess: () => navigate("/login/features"), + onSuccess: () => + navigate({ + to: "/home/features", + }), }); }; diff --git a/src/renderer/src/routes/home._layout/index.tsx b/src/renderer/src/routes/home._layout/index.tsx new file mode 100644 index 00000000..ffb5dc51 --- /dev/null +++ b/src/renderer/src/routes/home._layout/index.tsx @@ -0,0 +1,9 @@ +import { createFileRoute, Navigate } from "@tanstack/react-router"; + +export const Route = createFileRoute("/home/_layout/")({ + component: Index, +}); + +function Index() { + return ; +} diff --git a/src/renderer/src/routes/home._layout/route.tsx b/src/renderer/src/routes/home._layout/route.tsx new file mode 100644 index 00000000..36dcf428 --- /dev/null +++ b/src/renderer/src/routes/home._layout/route.tsx @@ -0,0 +1,10 @@ +import LoginLayout from "@/layout/login"; +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/home/_layout")({ + component: RouteComponent, +}); + +function RouteComponent() { + return ; +} diff --git a/src/renderer/src/routes/index.tsx b/src/renderer/src/routes/index.tsx new file mode 100644 index 00000000..696125a5 --- /dev/null +++ b/src/renderer/src/routes/index.tsx @@ -0,0 +1,9 @@ +import { createFileRoute, Navigate } from "@tanstack/react-router"; + +export const Route = createFileRoute("/")({ + component: RouteComponent, +}); + +function RouteComponent() { + return ; +} diff --git a/src/renderer/src/services/aymurai/index.ts b/src/renderer/src/services/aymurai/index.ts index cf47d5a9..fb0233fd 100644 --- a/src/renderer/src/services/aymurai/index.ts +++ b/src/renderer/src/services/aymurai/index.ts @@ -3,6 +3,6 @@ export { anonymize } from "./anonymize"; export { getParagraphs } from "./document-extract"; export { predict }; - export * from "./useConnectToHost"; - export * from "./useFileParser"; - export * from "./useRunLocalServer"; +export * from "./useConnectToHost"; +export * from "./useFileParser"; +export * from "./useRunLocalServer"; diff --git a/src/renderer/src/services/aymurai/schema.ts b/src/renderer/src/services/aymurai/schema.ts index 3e2bba7c..96c806da 100644 --- a/src/renderer/src/services/aymurai/schema.ts +++ b/src/renderer/src/services/aymurai/schema.ts @@ -2,4 +2,4 @@ import z from "zod"; export const healthcheckSchema = z.object({ status: z.enum(["ok"]), -}); \ No newline at end of file +}); diff --git a/src/renderer/src/types/react-query.d.ts b/src/renderer/src/types/react-query.d.ts new file mode 100644 index 00000000..5d56ad7f --- /dev/null +++ b/src/renderer/src/types/react-query.d.ts @@ -0,0 +1,11 @@ +import "@tanstack/react-query"; + +declare module "@tanstack/react-query" { + interface Register { + queryMeta: MyMeta; + mutationMeta: { + invalidates?: Array; + awaits?: boolean; + }; + } +} diff --git a/src/renderer/src/utils/process/canContinue.ts b/src/renderer/src/utils/process/canContinue.ts new file mode 100644 index 00000000..340d99c3 --- /dev/null +++ b/src/renderer/src/utils/process/canContinue.ts @@ -0,0 +1,12 @@ +import { ProcessState } from "./initProcessState"; + +export function canContinue(state: ProcessState[]) { + const atLeastOneCompleted = state.some( + ({ status }) => status === "completed", + ); + const hasFinishedProcessing = !state.some( + ({ status }) => status === "processing", + ); + + return hasFinishedProcessing && atLeastOneCompleted; +} diff --git a/src/renderer/src/utils/process/initProcessState.ts b/src/renderer/src/utils/process/initProcessState.ts new file mode 100644 index 00000000..e0f730d8 --- /dev/null +++ b/src/renderer/src/utils/process/initProcessState.ts @@ -0,0 +1,13 @@ +import type { PredictStatus } from "@/hooks/usePredict"; +import { DocFile } from "@/types/file"; + +export type ProcessState = { name: string; status: PredictStatus }; + +/** + * Creates the initial state for the `/process` page + * @param files `DocFile[]` state + * @returns An `ProcessState[]` array containing the name of each file and its processing state + */ +export function initProcessState(files: DocFile[]): ProcessState[] { + return files.map(({ data }) => ({ name: data.name, status: "processing" })); +} diff --git a/vite.config.ts b/vite.config.ts index 0a11fd2d..0067f57f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,9 +1,16 @@ +import { tanstackRouter } from "@tanstack/router-plugin/vite"; import react from "@vitejs/plugin-react"; import { resolve } from "node:path"; import { defineConfig } from "vite"; export default defineConfig({ - plugins: [react()], + plugins: [ + tanstackRouter({ + target: "react", + autoCodeSplitting: true, + }), + react(), + ], root: "src/renderer", server: { port: 3000, From c5bd48054f5c94f2c0323c4e7250226f77878ab1 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 30 Nov 2025 21:48:08 -0300 Subject: [PATCH 002/263] build: move tanstack router dependencies to devDependencies --- package.json | 9 ++++++--- pnpm-lock.yaml | 12 ++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index e33c246f..c8dfe6e7 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,6 @@ "dependencies": { "@electron-toolkit/preload": "^3.0.2", "@electron-toolkit/utils": "^4.0.0", - "@tanstack/react-router": "^1.139.12", - "@tanstack/react-router-devtools": "^1.139.12", "electron-squirrel-startup": "^1.0.0" }, "devDependencies": { @@ -43,6 +41,8 @@ "@stitches/react": "^1.2.8", "@tanstack/react-form": "1.11.0", "@tanstack/react-query": "^5.81.1", + "@tanstack/react-router": "^1.139.12", + "@tanstack/react-router-devtools": "^1.139.12", "@tanstack/router-plugin": "^1.139.12", "@types/node": "20", "@types/react": "18", @@ -74,6 +74,9 @@ "zustand": "^5.0.7" }, "pnpm": { - "onlyBuiltDependencies": ["electron", "esbuild"] + "onlyBuiltDependencies": [ + "electron", + "esbuild" + ] } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 126177af..af8cb3a4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,12 +14,6 @@ importers: '@electron-toolkit/utils': specifier: ^4.0.0 version: 4.0.0(electron@21.4.4) - '@tanstack/react-router': - specifier: ^1.139.12 - version: 1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@tanstack/react-router-devtools': - specifier: ^1.139.12 - version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(solid-js@1.9.10)(tsx@4.20.6) electron-squirrel-startup: specifier: ^1.0.0 version: 1.0.1 @@ -54,6 +48,12 @@ importers: '@tanstack/react-query': specifier: ^5.81.1 version: 5.81.1(react@18.3.1) + '@tanstack/react-router': + specifier: ^1.139.12 + version: 1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/react-router-devtools': + specifier: ^1.139.12 + version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(solid-js@1.9.10)(tsx@4.20.6) '@tanstack/router-plugin': specifier: ^1.139.12 version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@6.3.5(@types/node@20.19.1)(tsx@4.20.6)) From 1462f73261f32f9b98a0e5fb5b10543f429e07b3 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 30 Nov 2025 21:49:31 -0300 Subject: [PATCH 003/263] fix(styling): import styled function from stitches instance --- .../src/components/onboarding-card/OnboardingCard.styles.ts | 2 +- src/renderer/src/components/onboarding-grid/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/components/onboarding-card/OnboardingCard.styles.ts b/src/renderer/src/components/onboarding-card/OnboardingCard.styles.ts index 7eabe324..57ab1c5f 100644 --- a/src/renderer/src/components/onboarding-card/OnboardingCard.styles.ts +++ b/src/renderer/src/components/onboarding-card/OnboardingCard.styles.ts @@ -1,5 +1,5 @@ import { Card as BaseCard } from "@/components"; -import { styled } from "@stitches/react"; +import { styled } from "@/styles"; /** * Styled card, containing step, image and description diff --git a/src/renderer/src/components/onboarding-grid/index.ts b/src/renderer/src/components/onboarding-grid/index.ts index c5cd1628..ecf7ff3a 100644 --- a/src/renderer/src/components/onboarding-grid/index.ts +++ b/src/renderer/src/components/onboarding-grid/index.ts @@ -1,4 +1,4 @@ -import { styled } from "@stitches/react"; +import { styled } from "@/styles"; export const OnboardingGrid = styled("div", { display: "grid", From 0e5527dbf85dd658bbd511fec7ec3123e4df1d6d Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 30 Nov 2025 22:05:41 -0300 Subject: [PATCH 004/263] fix(routing): used wrong parms in route, switched to correct path --- src/renderer/src/routes/app.$feature/preview.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/src/routes/app.$feature/preview.tsx b/src/renderer/src/routes/app.$feature/preview.tsx index d9f0a124..bae9aedd 100644 --- a/src/renderer/src/routes/app.$feature/preview.tsx +++ b/src/renderer/src/routes/app.$feature/preview.tsx @@ -126,7 +126,7 @@ function GenericPreview({ title, supportMultipleFiles }: GenericPreviewProps) { function RouteComponent() { const { feature } = useParams({ - from: "/app/$feature/onboarding", + from: "/app/$feature/preview", }); if (feature === Feature.Dataset) From 542b7340dde05f973ce48f1f56542c694d79d190 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 30 Nov 2025 22:12:41 -0300 Subject: [PATCH 005/263] fix(schema): make predict alt values nullable --- src/renderer/src/schema/predict.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/renderer/src/schema/predict.ts b/src/renderer/src/schema/predict.ts index 4fd68fbe..26767532 100644 --- a/src/renderer/src/schema/predict.ts +++ b/src/renderer/src/schema/predict.ts @@ -8,9 +8,9 @@ export const predictSchema = z.object({ start_char: z.number(), end_char: z.number(), attrs: z.object({ - aymurai_alt_start_char: z.number(), - aymurai_alt_end_char: z.number(), - aymurai_alt_text: z.string(), + aymurai_alt_start_char: z.number().nullable(), + aymurai_alt_end_char: z.number().nullable(), + aymurai_alt_text: z.string().nullable(), aymurai_label: z.string(), aymurai_label_subclass: z.array(z.string()).nullable(), }), From be5a54dd04d1e8a06ef9b921a586e71a320c2b44 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 1 Dec 2025 11:28:07 -0300 Subject: [PATCH 006/263] chore: fix pr comments --- src/renderer/src/components/stepper/utils.ts | 10 ++++--- .../src/routes/app.$feature/onboarding.tsx | 28 +++++++++---------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/renderer/src/components/stepper/utils.ts b/src/renderer/src/components/stepper/utils.ts index c373b615..82a9aafa 100644 --- a/src/renderer/src/components/stepper/utils.ts +++ b/src/renderer/src/components/stepper/utils.ts @@ -1,4 +1,4 @@ -import type { ParsedLocation } from '@tanstack/react-router'; +import type { ParsedLocation } from "@tanstack/react-router"; const ROUTE_STEPS = { preview: 1, @@ -8,13 +8,15 @@ const ROUTE_STEPS = { } as const; type RouteSegment = keyof typeof ROUTE_STEPS; -type StepNumber = typeof ROUTE_STEPS[RouteSegment] | 0; +type StepNumber = (typeof ROUTE_STEPS)[RouteSegment] | 0; export const getStep = (location: ParsedLocation): StepNumber => { // Extract the last segment of the pathname // For routes like /app/$feature/preview, this gets 'preview' - const segments = location.pathname.split('/').filter(Boolean); - const lastSegment = segments[segments.length - 1]; + const segments = location.pathname.split("/").filter(Boolean); + const lastSegment = segments.at(-1); + + if (!lastSegment) return 0; // Type-safe check: only return step if lastSegment is a valid RouteSegment if (isValidRouteSegment(lastSegment)) { diff --git a/src/renderer/src/routes/app.$feature/onboarding.tsx b/src/renderer/src/routes/app.$feature/onboarding.tsx index 4977fb66..2496ba3a 100644 --- a/src/renderer/src/routes/app.$feature/onboarding.tsx +++ b/src/renderer/src/routes/app.$feature/onboarding.tsx @@ -114,18 +114,18 @@ function RouteComponent() { multipleFiles={true} /> ); - else - return ( - - ); + + return ( + + ); } From 076f54d8982ee06f7004e8fe6615cfa966e93528 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 1 Dec 2025 11:33:44 -0300 Subject: [PATCH 007/263] chore: remove comments --- src/renderer/src/app.tsx | 35 +---------------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/src/renderer/src/app.tsx b/src/renderer/src/app.tsx index 19aa0160..5d088bad 100644 --- a/src/renderer/src/app.tsx +++ b/src/renderer/src/app.tsx @@ -1,7 +1,7 @@ import { + RouterProvider, createMemoryHistory, createRouter, - RouterProvider, } from "@tanstack/react-router"; import { ThemeProvider } from "@/components"; @@ -28,39 +28,6 @@ declare module "@tanstack/react-router" { } } -// const router = createRouter([ -// { -// path: "/", -// element: , -// }, -// { -// path: "/login", -// element: , -// children: [ -// { index: true, element: }, -// { path: "host", element: }, -// { path: "features", element: }, -// ], -// }, -// { -// // Main as a layout element -// path: "app/:feature", -// element: , -// children: [ -// // 1. Onboarding. Explanation of the workflow to process files -// { path: "onboarding", element: }, -// // 2. Preview. Process the file to get its text contents -// { path: "preview", element: }, -// // 3. Process. Passes the text contents to the AI to extract predictions -// { path: "process", element: }, -// // 4. Validation. Validate the predictions/anonymize the file -// { path: "validation", element: }, -// // 5. Finish. Show the results and download output files -// { path: "finish", element: }, -// ], -// }, -// ]); - export default function App() { return ( From 9dae04fb5c8b759e599977bda38f793efe537270 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 6 Dec 2025 01:16:46 -0300 Subject: [PATCH 008/263] fix: using react query to download anonymized file --- .../components/finish-anonymizer/index.tsx | 50 +++++++----------- .../src/features/ReactQueryProvider.tsx | 9 +++- .../src/services/aymurai/anonymize.ts | 31 ----------- src/renderer/src/services/aymurai/index.ts | 3 +- src/renderer/src/services/aymurai/queries.ts | 52 +++++++++++++++++++ src/renderer/src/types/axios.d.ts | 6 +++ 6 files changed, 87 insertions(+), 64 deletions(-) create mode 100644 src/renderer/src/services/aymurai/queries.ts create mode 100644 src/renderer/src/types/axios.d.ts diff --git a/src/renderer/src/components/finish-anonymizer/index.tsx b/src/renderer/src/components/finish-anonymizer/index.tsx index 481c5518..29d98f98 100644 --- a/src/renderer/src/components/finish-anonymizer/index.tsx +++ b/src/renderer/src/components/finish-anonymizer/index.tsx @@ -1,5 +1,3 @@ -import { useEffect, useState } from "react"; - import { Button, Card, @@ -12,9 +10,10 @@ import { import { useFileDispatch, useFiles } from "@/hooks"; import { Footer, Section } from "@/layout/main"; import { removeAllFiles } from "@/reducers/file/actions"; -import { anonymize } from "@/services/aymurai"; +import { aymuraiService } from "@/services/aymurai"; +import { useQuery } from "@tanstack/react-query"; import { useNavigate, useParams } from "@tanstack/react-router"; -import * as S from './FinishAnonymizer.styles'; +import * as S from "./FinishAnonymizer.styles"; const changeExtension = (name: string) => { const parts = name.split("."); @@ -22,46 +21,39 @@ const changeExtension = (name: string) => { return `${[...parts].join(".")}_anonimizado.odt`; }; -type AnonymizeStatus = "loading" | "success" | "error"; export function FinishAnonymizer() { - const params = useParams({from:'/app/$feature/finish'}) + const params = useParams({ from: "/app/$feature/finish" }); // We are sure that there is only one file, because we came from // anonimization workflow const file = useFiles()[0]; const dispatch = useFileDispatch(); const navigate = useNavigate(); - const [status, setStatus] = useState(null); - const [fileURI, setFileURI] = useState(null); + + const { + data: fileURI, + isLoading, + isError, + } = useQuery(aymuraiService.anonymize(file)); + const downloadDocument = async () => { if (!fileURI) { console.error("Tried to download a file that is not ready."); return; } const link = document.createElement("a"); - link.setAttribute("href", fileURI); - link.setAttribute("download", changeExtension(file.data.name)); + link.href = fileURI; + link.download = changeExtension(file.data.name); link.click(); + + URL.revokeObjectURL(fileURI); }; const handleRestart = () => { dispatch(removeAllFiles()); - navigate({to:"/app/$feature/onboarding",params}); + navigate({ to: "/app/$feature/onboarding", params }); }; - useEffect(() => { - setStatus("loading"); - - anonymize(file) - .then((blob) => { - setFileURI(URL.createObjectURL(blob)); - setStatus("success"); - }) - .catch(() => { - setStatus("error"); - }); - }, []); - return ( <>
@@ -80,8 +72,8 @@ export function FinishAnonymizer() { > @@ -97,11 +89,7 @@ export function FinishAnonymizer() { -
diff --git a/src/renderer/src/features/ReactQueryProvider.tsx b/src/renderer/src/features/ReactQueryProvider.tsx index d2038722..52e7fff3 100644 --- a/src/renderer/src/features/ReactQueryProvider.tsx +++ b/src/renderer/src/features/ReactQueryProvider.tsx @@ -1,12 +1,19 @@ import { - matchQuery, MutationCache, QueryClient, QueryClientProvider, + matchQuery, } from "@tanstack/react-query"; export function getContext() { const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: Number.POSITIVE_INFINITY, + refetchOnWindowFocus: false, + retry: false, + }, + }, mutationCache: new MutationCache({ onSettled: async (_data, _err, _vars, _ctx, mutation) => { if (!mutation.meta) return; diff --git a/src/renderer/src/services/aymurai/anonymize.ts b/src/renderer/src/services/aymurai/anonymize.ts index a051c870..7a15e2c0 100644 --- a/src/renderer/src/services/aymurai/anonymize.ts +++ b/src/renderer/src/services/aymurai/anonymize.ts @@ -1,8 +1,6 @@ import type { PredictLabel } from "@/types/aymurai"; import type { DocFile } from "@/types/file"; -import api from "../api"; - interface Body { data: { // The paragraph @@ -22,32 +20,3 @@ const body = (file: DocFile): Body => { })), }; }; - -/** - * Anonymize a document - * @param file File to be processed - * @param serverUrl String with the URL of the AyMurAI api - * @param body Body containing the plain text and the annotations - * @returns The anonymized document in a `Blob` - */ -export const anonymize = async (file: DocFile) => { - // Add file to `FormData` - const formData = new FormData(); - formData.append("file", file.data); - // TODO: add annotations whenever the backend implements it - formData.append("annotations", JSON.stringify(body(file))); - - const response = await api.post( - "/anonymizer/anonymize-document", - formData, - { - headers: { - "Content-Type": "multipart/form-data", - Accept: "application/octet-stream", - }, - responseType: "arraybuffer", - }, - ); - - return new Blob([response.data]); -}; diff --git a/src/renderer/src/services/aymurai/index.ts b/src/renderer/src/services/aymurai/index.ts index fb0233fd..3756690e 100644 --- a/src/renderer/src/services/aymurai/index.ts +++ b/src/renderer/src/services/aymurai/index.ts @@ -1,8 +1,9 @@ import predict from "./predict"; -export { anonymize } from "./anonymize"; export { getParagraphs } from "./document-extract"; export { predict }; export * from "./useConnectToHost"; export * from "./useFileParser"; export * from "./useRunLocalServer"; + +export * as aymuraiService from "./queries"; diff --git a/src/renderer/src/services/aymurai/queries.ts b/src/renderer/src/services/aymurai/queries.ts new file mode 100644 index 00000000..786143b1 --- /dev/null +++ b/src/renderer/src/services/aymurai/queries.ts @@ -0,0 +1,52 @@ +import type { PredictLabel } from "@/types/aymurai"; +import type { DocFile } from "@/types/file"; +import { queryOptions } from "@tanstack/react-query"; +import api from "../api"; + +interface Body { + data: { + // The paragraph + document: string; + labels: PredictLabel[]; + }[]; +} + +const body = (file: DocFile): Body => { + const paragraphs = file.paragraphs ?? []; + const labels = file.predictions ?? []; + + return { + data: paragraphs.map((p) => ({ + document: p.value, + labels: labels.filter((l) => l.paragraphId === p.id), + })), + }; +}; + +export const anonymize = (file: DocFile) => + queryOptions({ + queryKey: ["anonymize"], + queryFn: async () => { + const formData = new FormData(); + formData.append("file", file.data); + // TODO: add annotations whenever the backend implements it + formData.append("annotations", JSON.stringify(body(file))); + + const response = await api.post( + "/anonymizer/anonymize-document", + formData, + { + headers: { + "Content-Type": "multipart/form-data", + Accept: "application/octet-stream", + }, + responseType: "blob", + }, + ); + + console.log(response); + + return response; + }, + select: (data) => URL.createObjectURL(data), + }); diff --git a/src/renderer/src/types/axios.d.ts b/src/renderer/src/types/axios.d.ts new file mode 100644 index 00000000..b83a7743 --- /dev/null +++ b/src/renderer/src/types/axios.d.ts @@ -0,0 +1,6 @@ +import "axios"; + +declare module "axios" { + // This is due an intercepter we have set where we return `response.data` directly. + export interface AxiosResponse extends Promise {} +} From cedb2a26b0049b1538607eda0e8280af25027a7c Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 6 Dec 2025 01:17:55 -0300 Subject: [PATCH 009/263] chore: remove deprecated code and functions --- src/renderer/src/hooks/index.ts | 1 - src/renderer/src/hooks/useFileParser.ts | 36 ---------------- src/renderer/src/hooks/usePredict.ts | 6 +-- .../src/services/aymurai/anonymize.ts | 22 ---------- .../src/services/aymurai/document-extract.ts | 41 ------------------- src/renderer/src/services/aymurai/index.ts | 1 - 6 files changed, 3 insertions(+), 104 deletions(-) delete mode 100644 src/renderer/src/hooks/useFileParser.ts delete mode 100644 src/renderer/src/services/aymurai/anonymize.ts delete mode 100644 src/renderer/src/services/aymurai/document-extract.ts diff --git a/src/renderer/src/hooks/index.ts b/src/renderer/src/hooks/index.ts index 35d11f01..4971d85c 100644 --- a/src/renderer/src/hooks/index.ts +++ b/src/renderer/src/hooks/index.ts @@ -1,7 +1,6 @@ import { useFileDispatch, useFiles } from "./useFiles"; import useForm from "./useForm"; -export { useFileParser } from "./useFileParser"; export { usePredict } from "./usePredict"; export { useFileDispatch, useFiles, useForm }; diff --git a/src/renderer/src/hooks/useFileParser.ts b/src/renderer/src/hooks/useFileParser.ts deleted file mode 100644 index 3618c0bb..00000000 --- a/src/renderer/src/hooks/useFileParser.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { addParagraphs } from "@/reducers/file/actions"; -import { useEffect } from "react"; - -import { getParagraphs } from "@/services/aymurai"; -import type { DocFile } from "@/types/file"; - -import { useFileDispatch } from "./useFiles"; - -/** - * Fetches the paragraphs of a file and adds them to the state. Also, returns the paragraphs - * @param file File to be analyzed - * @returns List of paragraphs with their metadata - * @deprecated Replaced by React Query implementation - */ -export function useFileParser(file: DocFile) { - const dispatch = useFileDispatch(); - - useEffect(() => { - let loaded = false; - const fetchParagraphs = async () => { - // Prevents the function from running multiple times or if the paragraphs've already been loaded - if (!loaded && !file.paragraphs) { - const response = await getParagraphs(file.data); - dispatch(addParagraphs(response, file.data.name)); - } - }; - - fetchParagraphs(); - - return () => { - loaded = true; - }; - }, [file]); - - return file.paragraphs; -} diff --git a/src/renderer/src/hooks/usePredict.ts b/src/renderer/src/hooks/usePredict.ts index 37de8459..96cc8ae9 100644 --- a/src/renderer/src/hooks/usePredict.ts +++ b/src/renderer/src/hooks/usePredict.ts @@ -1,6 +1,6 @@ import { useCallback, useEffect, useRef, useState } from "react"; -import { useFileDispatch, useFileParser } from "@/hooks"; +import { useFileDispatch } from "@/hooks"; import { addPredictions, removePredictions } from "@/reducers/file/actions"; import { predict } from "@/services/aymurai"; @@ -17,14 +17,14 @@ export function usePredict( file: DocFile, { onStatusChange }: UsePredictOptions, ) { - const { feature } = useParams({from: '/app/$feature/process'}); + const { feature } = useParams({ from: "/app/$feature/process" }); const [progress, setProgress] = useState(0); const [status, setStatus] = useState("processing"); const dispatch = useFileDispatch(); - const paragraphs = useFileParser(file); const isAnonimizing = feature === Feature.Anonymizer; + const paragraphs = file.paragraphs; // Store static values const controller = useRef(new AbortController()); diff --git a/src/renderer/src/services/aymurai/anonymize.ts b/src/renderer/src/services/aymurai/anonymize.ts deleted file mode 100644 index 7a15e2c0..00000000 --- a/src/renderer/src/services/aymurai/anonymize.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { PredictLabel } from "@/types/aymurai"; -import type { DocFile } from "@/types/file"; - -interface Body { - data: { - // The paragraph - document: string; - labels: PredictLabel[]; - }[]; -} - -const body = (file: DocFile): Body => { - const paragraphs = file.paragraphs ?? []; - const labels = file.predictions ?? []; - - return { - data: paragraphs.map((p) => ({ - document: p.value, - labels: labels.filter((l) => l.paragraphId === p.id), - })), - }; -}; diff --git a/src/renderer/src/services/aymurai/document-extract.ts b/src/renderer/src/services/aymurai/document-extract.ts deleted file mode 100644 index 35ab7004..00000000 --- a/src/renderer/src/services/aymurai/document-extract.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { Paragraph } from "@/types/file"; -import { getParagraphId } from "@/utils/file/getParagraphId"; - -import api from "../api"; - -interface ParagraphsResponse { - document: string[]; - header: null; - footer: null; - document_id: string; -} - -/** - * Sends a file to the backend to be analyzed and retrieve a list of paragraphs - * @param file File to be analyzed - * @param serverUrl String with the URL of the AyMurAI api - * @returns A list of paragraphs with their metadata - * @deprecated Replaced by React Query implementation - */ -export async function getParagraphs(file: File): Promise { - const formData = new FormData(); - formData.append("file", file); - try { - const response = await api.post( - "/document-extract", - formData, - { - headers: { "Content-Type": "multipart/form-data" }, - }, - ); - return response.data.document.map((p, i) => ({ - value: p, - document_id: response.data.document_id, - id: getParagraphId(p, i), - })); - } catch (e) { - const { message } = e as Error; - console.error("Could not connect to server: ", message); - return []; - } -} diff --git a/src/renderer/src/services/aymurai/index.ts b/src/renderer/src/services/aymurai/index.ts index 3756690e..af651c7a 100644 --- a/src/renderer/src/services/aymurai/index.ts +++ b/src/renderer/src/services/aymurai/index.ts @@ -1,5 +1,4 @@ import predict from "./predict"; -export { getParagraphs } from "./document-extract"; export { predict }; export * from "./useConnectToHost"; From ca20777ab101eca14c978ad6f94aae17cd8532f7 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 6 Dec 2025 16:10:21 -0300 Subject: [PATCH 010/263] fix: don't revoke api response blob url --- .../components/finish-anonymizer/index.tsx | 2 +- .../src/routes/app.$feature/process.tsx | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/renderer/src/components/finish-anonymizer/index.tsx b/src/renderer/src/components/finish-anonymizer/index.tsx index 29d98f98..c31d6246 100644 --- a/src/renderer/src/components/finish-anonymizer/index.tsx +++ b/src/renderer/src/components/finish-anonymizer/index.tsx @@ -46,7 +46,7 @@ export function FinishAnonymizer() { link.click(); - URL.revokeObjectURL(fileURI); + document.removeChild(link); }; const handleRestart = () => { diff --git a/src/renderer/src/routes/app.$feature/process.tsx b/src/renderer/src/routes/app.$feature/process.tsx index 9817fd56..e5926043 100644 --- a/src/renderer/src/routes/app.$feature/process.tsx +++ b/src/renderer/src/routes/app.$feature/process.tsx @@ -10,7 +10,7 @@ import { } from "@/components"; import { useFileDispatch, useFiles } from "@/hooks"; import useNotify from "@/hooks/useNotify"; -import { PredictStatus } from "@/hooks/usePredict"; +import type { PredictStatus } from "@/hooks/usePredict"; import { Footer, Section } from "@/layout/main"; import { filterUnprocessed, @@ -19,8 +19,8 @@ import { import { Feature } from "@/types/features"; import { canContinue } from "@/utils/process/canContinue"; import { + type ProcessState, initProcessState, - ProcessState, } from "@/utils/process/initProcessState"; import { createFileRoute, @@ -147,12 +147,12 @@ function RouteComponent() { supportMultipleFiles={true} /> ); - else - return ( - - ); + + return ( + + ); } From c99c0ce9fda22808670ac506f60a59e73a3c443b Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 6 Dec 2025 16:10:36 -0300 Subject: [PATCH 011/263] chore: add format package script and ignore route tree gen file --- biome.json | 2 +- package.json | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/biome.json b/biome.json index 0b2c7ab3..676bcd39 100644 --- a/biome.json +++ b/biome.json @@ -7,7 +7,7 @@ }, "files": { "ignoreUnknown": false, - "ignore": ["node_modules", "build", ".husky", "out"] + "ignore": ["node_modules", "build", ".husky", "out", "routeTree.gen.ts"] }, "formatter": { "enabled": true, diff --git a/package.json b/package.json index c8dfe6e7..7bd7fd99 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "build": "npm run typecheck && electron-vite build", "lint": "biome check", "lint:fix": "biome check --write", + "format": "biome format", + "format:fix": "biome format --write", "typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false", "typecheck:web": "tsc --noEmit -p tsconfig.web.json --composite false", "typecheck": "npm run typecheck:node && npm run typecheck:web", @@ -74,9 +76,6 @@ "zustand": "^5.0.7" }, "pnpm": { - "onlyBuiltDependencies": [ - "electron", - "esbuild" - ] + "onlyBuiltDependencies": ["electron", "esbuild"] } } From 9ab8896cfa3a0e919dfc7b4efef1fe46c5df4e9f Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 6 Dec 2025 16:11:27 -0300 Subject: [PATCH 012/263] chore: format code --- .../src/components/file-preview/index.tsx | 2 +- .../FinishAnonymizer.styles.ts | 2 +- .../finish-dataset/FinishDataset.styles.ts | 2 +- .../src/components/finish-dataset/index.tsx | 6 +++--- src/renderer/src/components/index.ts | 6 +++--- .../src/components/validate-dataset/index.tsx | 6 +++--- src/renderer/src/layout/login/index.tsx | 2 +- .../src/routes/app.$feature/finish.tsx | 18 +++++++++--------- .../src/routes/app.$feature/validation.tsx | 15 ++++++++++----- .../src/routes/home._layout/features.tsx | 14 +++++--------- 10 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/renderer/src/components/file-preview/index.tsx b/src/renderer/src/components/file-preview/index.tsx index e3c86cec..a4c3d7e4 100644 --- a/src/renderer/src/components/file-preview/index.tsx +++ b/src/renderer/src/components/file-preview/index.tsx @@ -14,7 +14,7 @@ interface Props { file: DocFile; } export default function FilePreview({ file }: Props) { - const { feature } = useParams({from:'/app/$feature/preview'}); + const { feature } = useParams({ from: "/app/$feature/preview" }); const dispatch = useFileDispatch(); const { data: parsedFile, isError, isPending } = useFileParser(file.data); diff --git a/src/renderer/src/components/finish-anonymizer/FinishAnonymizer.styles.ts b/src/renderer/src/components/finish-anonymizer/FinishAnonymizer.styles.ts index 83a1f063..642cdc8c 100644 --- a/src/renderer/src/components/finish-anonymizer/FinishAnonymizer.styles.ts +++ b/src/renderer/src/components/finish-anonymizer/FinishAnonymizer.styles.ts @@ -2,4 +2,4 @@ import { styled } from "@/styles"; export const Anchor = styled("a", { mr: "auto", -}); \ No newline at end of file +}); diff --git a/src/renderer/src/components/finish-dataset/FinishDataset.styles.ts b/src/renderer/src/components/finish-dataset/FinishDataset.styles.ts index 83a1f063..642cdc8c 100644 --- a/src/renderer/src/components/finish-dataset/FinishDataset.styles.ts +++ b/src/renderer/src/components/finish-dataset/FinishDataset.styles.ts @@ -2,4 +2,4 @@ import { styled } from "@/styles"; export const Anchor = styled("a", { mr: "auto", -}); \ No newline at end of file +}); diff --git a/src/renderer/src/components/finish-dataset/index.tsx b/src/renderer/src/components/finish-dataset/index.tsx index fde96ece..a1cd1247 100644 --- a/src/renderer/src/components/finish-dataset/index.tsx +++ b/src/renderer/src/components/finish-dataset/index.tsx @@ -16,10 +16,10 @@ import filesystem from "@/services/filesystem"; import type { DocFile } from "@/types/file"; import { submitValidations } from "@/utils/file"; import { useNavigate, useParams } from "@tanstack/react-router"; -import * as S from './FinishDataset.styles'; +import * as S from "./FinishDataset.styles"; export function FinishDataset() { - const params = useParams({from:'/app/$feature/finish'}) + const params = useParams({ from: "/app/$feature/finish" }); const files = useFiles(); const dispatch = useFileDispatch(); const navigate = useNavigate(); @@ -28,7 +28,7 @@ export function FinishDataset() { const handleRestart = () => { dispatch(removeAllFiles()); - navigate({to:'/app/$feature/onboarding', params}); + navigate({ to: "/app/$feature/onboarding", params }); }; const checkForErrors = (fileName: string) => diff --git a/src/renderer/src/components/index.ts b/src/renderer/src/components/index.ts index ee14a802..0eb80d4a 100644 --- a/src/renderer/src/components/index.ts +++ b/src/renderer/src/components/index.ts @@ -8,8 +8,8 @@ export { default as FileCheck } from "./file-check"; export { default as FilePreview } from "./file-preview"; export { default as FileProcessing } from "./file-processing"; export { default as FileStepper } from "./file-stepper"; -export { FinishAnonymizer } from './finish-anonymizer'; -export { FinishDataset } from './finish-dataset'; +export { FinishAnonymizer } from "./finish-anonymizer"; +export { FinishDataset } from "./finish-dataset"; export { default as Grid } from "./grid"; export { default as HiddenInput } from "./hidden-input"; export { default as Input } from "./input"; @@ -31,5 +31,5 @@ export { default as ThemeProvider } from "./theme-provider"; export { default as Title } from "./title"; export { default as Toast } from "./toast"; export { default as Tooltip } from "./tooltip"; -export { ValidateDataset } from './validate-dataset'; +export { ValidateDataset } from "./validate-dataset"; export { default as ValidationForm } from "./validation-form"; diff --git a/src/renderer/src/components/validate-dataset/index.tsx b/src/renderer/src/components/validate-dataset/index.tsx index add33e58..00b67514 100644 --- a/src/renderer/src/components/validate-dataset/index.tsx +++ b/src/renderer/src/components/validate-dataset/index.tsx @@ -17,7 +17,7 @@ import { moveNext, movePrevious } from "./utils"; export function ValidateDataset() { // HOOKS - const {feature} = useParams({from:'/app/$feature/validation'}) + const { feature } = useParams({ from: "/app/$feature/validation" }); const files = useFiles(); const [checked, setChecked] = useState(false); const [selected, setSelected] = useState(0); @@ -41,8 +41,8 @@ export function ValidateDataset() { const handleContinue = () => { navigate({ - to:'/app/$feature/finish', - params: {feature} + to: "/app/$feature/finish", + params: { feature }, }); }; diff --git a/src/renderer/src/layout/login/index.tsx b/src/renderer/src/layout/login/index.tsx index 95707e8d..a84d5c34 100644 --- a/src/renderer/src/layout/login/index.tsx +++ b/src/renderer/src/layout/login/index.tsx @@ -10,7 +10,7 @@ export default function LoginLayout({ canGoBack = false }: LoginLayoutProps) { const navigate = useNavigate(); const handleGoBack = () => { - navigate({to:"/home"}); + navigate({ to: "/home" }); }; return ( diff --git a/src/renderer/src/routes/app.$feature/finish.tsx b/src/renderer/src/routes/app.$feature/finish.tsx index c936de99..aeead319 100644 --- a/src/renderer/src/routes/app.$feature/finish.tsx +++ b/src/renderer/src/routes/app.$feature/finish.tsx @@ -1,14 +1,14 @@ -import { FinishAnonymizer, FinishDataset } from '@/components' -import { Feature } from '@/types/features' -import { createFileRoute, useParams } from '@tanstack/react-router' +import { FinishAnonymizer, FinishDataset } from "@/components"; +import { Feature } from "@/types/features"; +import { createFileRoute, useParams } from "@tanstack/react-router"; -export const Route = createFileRoute('/app/$feature/finish')({ +export const Route = createFileRoute("/app/$feature/finish")({ component: RouteComponent, -}) +}); function RouteComponent() { - const {feature} = useParams({from:'/app/$feature/finish'}) - - if (feature === Feature.Dataset) return - return + const { feature } = useParams({ from: "/app/$feature/finish" }); + + if (feature === Feature.Dataset) return ; + return ; } diff --git a/src/renderer/src/routes/app.$feature/validation.tsx b/src/renderer/src/routes/app.$feature/validation.tsx index 62b62826..78a7cfb9 100644 --- a/src/renderer/src/routes/app.$feature/validation.tsx +++ b/src/renderer/src/routes/app.$feature/validation.tsx @@ -2,20 +2,25 @@ import { Button, FileAnnotator, Grid, ValidateDataset } from "@/components"; import { useFiles } from "@/hooks"; import { Footer } from "@/layout/main"; import { Feature } from "@/types/features"; -import { createFileRoute, useNavigate, useParams } from "@tanstack/react-router"; +import { + createFileRoute, + useNavigate, + useParams, +} from "@tanstack/react-router"; export const Route = createFileRoute("/app/$feature/validation")({ component: ValidationRoute, }); function ValidateAnonymizer() { - const {feature} = useParams({ - from: "/app/$feature/validation" - }) + const { feature } = useParams({ + from: "/app/$feature/validation", + }); const file = useFiles()[0]!; const navigate = useNavigate(); - const handleContinue = () => navigate({to: "/app/$feature/finish", params: {feature}}); + const handleContinue = () => + navigate({ to: "/app/$feature/finish", params: { feature } }); return ( <> diff --git a/src/renderer/src/routes/home._layout/features.tsx b/src/renderer/src/routes/home._layout/features.tsx index 013f5144..3878344a 100644 --- a/src/renderer/src/routes/home._layout/features.tsx +++ b/src/renderer/src/routes/home._layout/features.tsx @@ -3,7 +3,6 @@ import { Feature } from "@/types/features"; import { createFileRoute, useNavigate } from "@tanstack/react-router"; import { ArrowBendUpLeft, Database, Detective } from "phosphor-react"; - export const Route = createFileRoute("/home/_layout/features")({ component: RouteComponent, }); @@ -12,14 +11,14 @@ function RouteComponent() { const navigate = useNavigate(); const handleBack = () => { - navigate({to:'/home'}); + navigate({ to: "/home" }); }; const handleSelectFeature = (feature: Feature) => () => { navigate({ - to:"/app/$feature/onboarding", - params: {feature} - }) + to: "/app/$feature/onboarding", + params: { feature }, + }); }; return ( @@ -48,8 +47,5 @@ function RouteComponent() { Volver al inicio - ) + ); } - - - From a981184adc0f84e9751aaa8b4d6a533dbfd28e05 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 6 Dec 2025 16:12:36 -0300 Subject: [PATCH 013/263] chore: lint code --- electron.vite.config.ts | 2 +- src/main/createWindow.ts | 2 +- src/main/env.ts | 2 +- src/main/utils/subprocess.ts | 2 +- src/renderer/src/hooks/useNotify.ts | 4 ++-- src/renderer/src/routes/__root.tsx | 2 +- src/renderer/src/routes/app.$feature/route.tsx | 2 +- src/renderer/src/routes/home._layout/index.tsx | 4 ++-- src/renderer/src/routes/index.tsx | 4 ++-- src/renderer/src/utils/process/canContinue.ts | 2 +- src/renderer/src/utils/process/initProcessState.ts | 2 +- vite.config.ts | 2 +- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/electron.vite.config.ts b/electron.vite.config.ts index c8bca9e9..ea0d70e6 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -1,6 +1,6 @@ +import { resolve } from "node:path"; import react from "@vitejs/plugin-react"; import { defineConfig, externalizeDepsPlugin } from "electron-vite"; -import { resolve } from "node:path"; export default defineConfig({ main: { diff --git a/src/main/createWindow.ts b/src/main/createWindow.ts index 52276cc5..966ea137 100644 --- a/src/main/createWindow.ts +++ b/src/main/createWindow.ts @@ -1,6 +1,6 @@ +import { join } from "node:path"; import { is } from "@electron-toolkit/utils"; import { BrowserWindow, shell } from "electron"; -import { join } from "node:path"; import { DEV_PORT, EXTERNAL_URLS, isDebug, isProduction } from "./env"; import { resolveHTMLPath } from "./utils"; diff --git a/src/main/env.ts b/src/main/env.ts index a03106fe..4b7c0e76 100644 --- a/src/main/env.ts +++ b/src/main/env.ts @@ -1,8 +1,8 @@ /// -import { is } from "@electron-toolkit/utils"; import { homedir } from "node:os"; import path from "node:path"; +import { is } from "@electron-toolkit/utils"; // ------------------------ // CONFIG VARIABLES diff --git a/src/main/utils/subprocess.ts b/src/main/utils/subprocess.ts index 0eadd043..0dd06696 100644 --- a/src/main/utils/subprocess.ts +++ b/src/main/utils/subprocess.ts @@ -1,6 +1,6 @@ -import { app } from "electron"; import { exec, spawn } from "node:child_process"; import path from "node:path"; +import { app } from "electron"; export const run = () => { const batFilePath = path.join(app.getPath("exe"), "../run_server.bat"); diff --git a/src/renderer/src/hooks/useNotify.ts b/src/renderer/src/hooks/useNotify.ts index 5b73389c..081c4a0d 100644 --- a/src/renderer/src/hooks/useNotify.ts +++ b/src/renderer/src/hooks/useNotify.ts @@ -1,7 +1,7 @@ import taskbar from "@/services/taskbar"; -import { - initProcessState, +import type { ProcessState, + initProcessState, } from "@/utils/process/initProcessState"; import { useEffect, useState } from "react"; diff --git a/src/renderer/src/routes/__root.tsx b/src/renderer/src/routes/__root.tsx index fa1706d2..dba14522 100644 --- a/src/renderer/src/routes/__root.tsx +++ b/src/renderer/src/routes/__root.tsx @@ -1,4 +1,4 @@ -import { createRootRoute, Outlet } from "@tanstack/react-router"; +import { Outlet, createRootRoute } from "@tanstack/react-router"; export const Route = createRootRoute({ component: RootLayout }); diff --git a/src/renderer/src/routes/app.$feature/route.tsx b/src/renderer/src/routes/app.$feature/route.tsx index 3a66f584..353731e7 100644 --- a/src/renderer/src/routes/app.$feature/route.tsx +++ b/src/renderer/src/routes/app.$feature/route.tsx @@ -1,4 +1,4 @@ -import { createFileRoute, Outlet, redirect } from "@tanstack/react-router"; +import { Outlet, createFileRoute, redirect } from "@tanstack/react-router"; import { z } from "zod"; import { ProfileInfo, Stepper, Title } from "@/components"; diff --git a/src/renderer/src/routes/home._layout/index.tsx b/src/renderer/src/routes/home._layout/index.tsx index ffb5dc51..14db4ead 100644 --- a/src/renderer/src/routes/home._layout/index.tsx +++ b/src/renderer/src/routes/home._layout/index.tsx @@ -1,9 +1,9 @@ -import { createFileRoute, Navigate } from "@tanstack/react-router"; +import { Navigate, createFileRoute } from "@tanstack/react-router"; export const Route = createFileRoute("/home/_layout/")({ component: Index, }); function Index() { - return ; + return ; } diff --git a/src/renderer/src/routes/index.tsx b/src/renderer/src/routes/index.tsx index 696125a5..c762a8f9 100644 --- a/src/renderer/src/routes/index.tsx +++ b/src/renderer/src/routes/index.tsx @@ -1,9 +1,9 @@ -import { createFileRoute, Navigate } from "@tanstack/react-router"; +import { Navigate, createFileRoute } from "@tanstack/react-router"; export const Route = createFileRoute("/")({ component: RouteComponent, }); function RouteComponent() { - return ; + return ; } diff --git a/src/renderer/src/utils/process/canContinue.ts b/src/renderer/src/utils/process/canContinue.ts index 340d99c3..019e44b5 100644 --- a/src/renderer/src/utils/process/canContinue.ts +++ b/src/renderer/src/utils/process/canContinue.ts @@ -1,4 +1,4 @@ -import { ProcessState } from "./initProcessState"; +import type { ProcessState } from "./initProcessState"; export function canContinue(state: ProcessState[]) { const atLeastOneCompleted = state.some( diff --git a/src/renderer/src/utils/process/initProcessState.ts b/src/renderer/src/utils/process/initProcessState.ts index e0f730d8..f6d5bb91 100644 --- a/src/renderer/src/utils/process/initProcessState.ts +++ b/src/renderer/src/utils/process/initProcessState.ts @@ -1,5 +1,5 @@ import type { PredictStatus } from "@/hooks/usePredict"; -import { DocFile } from "@/types/file"; +import type { DocFile } from "@/types/file"; export type ProcessState = { name: string; status: PredictStatus }; diff --git a/vite.config.ts b/vite.config.ts index 0067f57f..84782767 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,6 +1,6 @@ +import { resolve } from "node:path"; import { tanstackRouter } from "@tanstack/router-plugin/vite"; import react from "@vitejs/plugin-react"; -import { resolve } from "node:path"; import { defineConfig } from "vite"; export default defineConfig({ From 0912fd0b5d51c29c6a3b439266f278ac09165786 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 6 Dec 2025 16:28:15 -0300 Subject: [PATCH 014/263] fix: add file name to anonymize query key --- src/renderer/src/services/aymurai/queries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/src/services/aymurai/queries.ts b/src/renderer/src/services/aymurai/queries.ts index 786143b1..43188769 100644 --- a/src/renderer/src/services/aymurai/queries.ts +++ b/src/renderer/src/services/aymurai/queries.ts @@ -25,7 +25,7 @@ const body = (file: DocFile): Body => { export const anonymize = (file: DocFile) => queryOptions({ - queryKey: ["anonymize"], + queryKey: ["anonymize", file.data.name], queryFn: async () => { const formData = new FormData(); formData.append("file", file.data); From afb803e257b52ffc6b1730a3fa7b0ec3a56ab2e6 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 6 Dec 2025 17:01:19 -0300 Subject: [PATCH 015/263] chore: remove global axios interceptor --- src/renderer/src/services/api.ts | 2 -- src/renderer/src/services/aymurai/predict.ts | 7 +++---- src/renderer/src/services/aymurai/queries.ts | 2 +- src/renderer/src/services/aymurai/useConnectToHost.ts | 2 +- src/renderer/src/services/aymurai/useFileParser.ts | 6 ++++-- src/renderer/src/services/aymurai/useRunLocalServer.ts | 2 +- src/renderer/src/types/axios.d.ts | 6 ------ 7 files changed, 10 insertions(+), 17 deletions(-) delete mode 100644 src/renderer/src/types/axios.d.ts diff --git a/src/renderer/src/services/api.ts b/src/renderer/src/services/api.ts index 45fab131..d01bc28f 100644 --- a/src/renderer/src/services/api.ts +++ b/src/renderer/src/services/api.ts @@ -6,6 +6,4 @@ const api = axios.create({ baseURL: AYMURAI_API_URL, }); -api.interceptors.response.use((response) => response.data); - export default api; diff --git a/src/renderer/src/services/aymurai/predict.ts b/src/renderer/src/services/aymurai/predict.ts index 2b9df0ba..af696fd4 100644 --- a/src/renderer/src/services/aymurai/predict.ts +++ b/src/renderer/src/services/aymurai/predict.ts @@ -32,7 +32,7 @@ export default async function predict( signal: controller.signal, }, ); - const parsed = predictSchema.parse(response); + const parsed = predictSchema.parse(response.data); const data = parsed.labels.map( (l) => @@ -50,11 +50,10 @@ export default async function predict( // If the POST is cancelled by the controller, just return an empty prediction if (e instanceof CanceledError) { return []; - // Otherwise, throw again the same error } + // Otherwise, throw again the same error console.error(e); - const { message } = e as Error; - throw new Error(message); + throw e; } } diff --git a/src/renderer/src/services/aymurai/queries.ts b/src/renderer/src/services/aymurai/queries.ts index 43188769..ed8ed884 100644 --- a/src/renderer/src/services/aymurai/queries.ts +++ b/src/renderer/src/services/aymurai/queries.ts @@ -46,7 +46,7 @@ export const anonymize = (file: DocFile) => console.log(response); - return response; + return response.data; }, select: (data) => URL.createObjectURL(data), }); diff --git a/src/renderer/src/services/aymurai/useConnectToHost.ts b/src/renderer/src/services/aymurai/useConnectToHost.ts index daae0c3f..8855e71b 100644 --- a/src/renderer/src/services/aymurai/useConnectToHost.ts +++ b/src/renderer/src/services/aymurai/useConnectToHost.ts @@ -8,7 +8,7 @@ export const useConnectToHost = () => { mutationKey: ["healthcheck"], mutationFn: (host: string) => { const url = new URL(host).toString().replace(/\/$/, ""); - return api.get(`${url}/server/healthcheck`); + return api.get(`${url}/server/healthcheck`).then((r) => r.data); }, schema: z.object({ status: z.string(), diff --git a/src/renderer/src/services/aymurai/useFileParser.ts b/src/renderer/src/services/aymurai/useFileParser.ts index 19bf431e..5174ade6 100644 --- a/src/renderer/src/services/aymurai/useFileParser.ts +++ b/src/renderer/src/services/aymurai/useFileParser.ts @@ -11,14 +11,16 @@ export function useFileParser(file: File) { const dispatch = useFileDispatch(); const query = useSchemedQuery({ - queryKey: ["file-parser", file.name], + queryKey: ["file-parser", file.name, file.size], queryFn: async () => { const formData = new FormData(); formData.append("file", file); - return api.post("/misc/document-extract", formData, { + const response = await api.post("/misc/document-extract", formData, { headers: { "Content-Type": "multipart/form-data" }, }); + + return response.data; }, schema: documentExtractSchema, retry: false, diff --git a/src/renderer/src/services/aymurai/useRunLocalServer.ts b/src/renderer/src/services/aymurai/useRunLocalServer.ts index 8701f0be..eea189ce 100644 --- a/src/renderer/src/services/aymurai/useRunLocalServer.ts +++ b/src/renderer/src/services/aymurai/useRunLocalServer.ts @@ -17,7 +17,7 @@ export const useRunLocalServer = ({ onSuccess }: UseRunLocalServerProps) => { isSuccess, } = useSchemedMutation({ schema: healthcheckSchema, - mutationFn: () => api.get("/server/healthcheck"), + mutationFn: () => api.get("/server/healthcheck").then((r) => r.data), retryDelay: 1000, retry: 10, onMutate: () => { diff --git a/src/renderer/src/types/axios.d.ts b/src/renderer/src/types/axios.d.ts deleted file mode 100644 index b83a7743..00000000 --- a/src/renderer/src/types/axios.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import "axios"; - -declare module "axios" { - // This is due an intercepter we have set where we return `response.data` directly. - export interface AxiosResponse extends Promise {} -} From d80226cc7eacf05a70ce10c9790d5e44245e678b Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 6 Dec 2025 17:01:44 -0300 Subject: [PATCH 016/263] chore: type global router context --- src/renderer/src/routes/__root.tsx | 11 +++++++++-- src/renderer/src/routes/app.$feature/preview.tsx | 14 +++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/renderer/src/routes/__root.tsx b/src/renderer/src/routes/__root.tsx index dba14522..38c4bcbc 100644 --- a/src/renderer/src/routes/__root.tsx +++ b/src/renderer/src/routes/__root.tsx @@ -1,6 +1,13 @@ -import { Outlet, createRootRoute } from "@tanstack/react-router"; +import { Outlet, createRootRouteWithContext } from "@tanstack/react-router"; +import type { QueryClient } from "@tanstack/react-query"; -export const Route = createRootRoute({ component: RootLayout }); +export interface RouterContext { + queryClient: QueryClient; +} + +export const Route = createRootRouteWithContext()({ + component: RootLayout, +}); function RootLayout() { return ; diff --git a/src/renderer/src/routes/app.$feature/preview.tsx b/src/renderer/src/routes/app.$feature/preview.tsx index bae9aedd..c3eddba4 100644 --- a/src/renderer/src/routes/app.$feature/preview.tsx +++ b/src/renderer/src/routes/app.$feature/preview.tsx @@ -136,11 +136,11 @@ function RouteComponent() { title="1. Previsualización de archivos" /> ); - else - return ( - - ); + + return ( + + ); } From 7caf825cc6e3254c649e881650aec18147e1d0e0 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 6 Dec 2025 17:01:52 -0300 Subject: [PATCH 017/263] chore: set stale time to default --- src/renderer/src/features/ReactQueryProvider.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/renderer/src/features/ReactQueryProvider.tsx b/src/renderer/src/features/ReactQueryProvider.tsx index 52e7fff3..33c23f18 100644 --- a/src/renderer/src/features/ReactQueryProvider.tsx +++ b/src/renderer/src/features/ReactQueryProvider.tsx @@ -9,7 +9,6 @@ export function getContext() { const queryClient = new QueryClient({ defaultOptions: { queries: { - staleTime: Number.POSITIVE_INFINITY, refetchOnWindowFocus: false, retry: false, }, From 2da311cebc9728431177ad6f8855f18e2f425331 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 6 Dec 2025 17:29:59 -0300 Subject: [PATCH 018/263] chore: kill cache when entering home layout --- src/renderer/src/routes/home._layout/route.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/src/routes/home._layout/route.tsx b/src/renderer/src/routes/home._layout/route.tsx index 36dcf428..f28124e6 100644 --- a/src/renderer/src/routes/home._layout/route.tsx +++ b/src/renderer/src/routes/home._layout/route.tsx @@ -3,6 +3,7 @@ import { createFileRoute } from "@tanstack/react-router"; export const Route = createFileRoute("/home/_layout")({ component: RouteComponent, + onEnter: ({ context }) => context.queryClient.removeQueries(), }); function RouteComponent() { From 9123e6ff047ddc6da0528d1de827a4af68752d0f Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 6 Dec 2025 18:50:13 -0300 Subject: [PATCH 019/263] docs: update readme --- README.md | 65 ++++++++++++++++++++++------------------------------ package.json | 4 ++-- 2 files changed, 30 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index e86517d7..559f844f 100644 --- a/README.md +++ b/README.md @@ -9,37 +9,29 @@ tools - ⚡ **Electron** as the _deployment and packaging tool_. It also serves the purpose of communicating the webapp with the _NodeJS_ process. - 🪡 **Stitches** as the _styling library_ -- 🛣️ **React Router** as the _routing library_ to navigate across the webapp +- 🛣️ **Tanstack React Router** as the _routing library_ to navigate across the webapp - 📄 **Mammoth** + **ExcelJS** as the _libraries_ to read and write `.docx` and datasheet files ### Other technologies -- **npm** as the _package manager_ -- **ESLint** as the _code linter_ +- **pnpm** as _package manager_ +- **biome** as code _linter and formatter_ ##  Getting started 1. Clone the repository -1. Add your [Google OAuth Client ID](https://developers.google.com/identity/protocols/oauth2) -as an `.env` file - ```bash - $ vim .env - - REACT_APP_CLIENT_ID="XXXXXXXXXXXX" # Your Client ID - ``` - -1. Install dependencies with +1. Navigate to the repository folder and install dependencies with - ```bash - npm install - ``` + ```bash + pnpm install + ``` 1. Start the app in development mode with ```bash - npm run dev + pnpm run dev ``` ## Run Aymurai API @@ -60,36 +52,35 @@ as an `.env` file ### Development -- `dev:web`: levanta el frontend localmente para poder ser visualizado en un - browser convencional -- `dev`: levanta el frontend localmente y crea una instancia de _Electron_ para - poder visualizarlo +- `dev:web`: starts the frontend locally to be viewed in a conventional browser +- `dev`: starts the frontend locally and creates an _Electron_ instance to view it +- `start`: previews the production build with Electron +- `start:web`: previews the production web build in a browser ### Build -- `build:renderer`: genera un build de la aplicación de _Electron_ -- `build:app`: genera un build de la aplicación de _React_ -- `build`: genera un build de la aplicación de _React_ y luego un build de la - aplicación de _Electron_ +- `build:web`: builds the React Vite project +- `build`: builds both React and Electron projects (without packaging the application) ### Validation -- `lint`: corre el linter (_ESLint_) en todo el proyecto -- `lint:markdown`: corre el linter de markdown (_MarkdownLint_), pero - únicamente en los archivos de markdown -- `lint:fix`: corrige los errores de linter de formato -- `check-types:react`: corre un checko de tipado en la aplicación de _React_ -- `check-types:renderer`: corre un checko de tipado en la aplicación de - _Electron_ -- `validate`: corre el linter y luego el checkeo de tipos -- `pre-commit`: corre el _LintStaged_ +- `lint`: runs the linter (_Biome_) across the entire project +- `lint:fix`: fixes linter errors automatically +- `format`: checks code formatting with _Biome_ +- `format:fix`: fixes code formatting automatically +- `typecheck`: runs type checking on both _Node_ and _Web_ applications +- `typecheck:node`: runs type checking on the _Electron_ application +- `typecheck:web`: runs type checking on the _React_ application +- `validate`: runs linting and type checking on both React and renderer +- `pre-commit`: runs _LintStaged_ ### Deployment -- `package`: genera la aplicación empaquetada en la carpeta `/out`. El tipo de - aplicación depende del OS host -- `make`: genera un instalador de la aplicación empaquetada. También depende del - OS host +- `build:unpack`: builds and creates an unpacked distribution directory +- `build:[win|mac|linux]`: builds and packages the application for the desired target +- `package`: cleans build directory, builds, and packages the app with Electron Forge +- `make`: cleans build directory, builds, and creates distributables with Electron Forge +- `postinstall`: installs app dependencies for Electron Builder ##  Colaborators diff --git a/package.json b/package.json index 7bd7fd99..751ab20e 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,6 @@ "dev": "electron-vite dev", "start": "electron-vite preview", "start:web": "vite preview --config vite.config.ts", - "build:web": "vite build --config vite.config.ts", - "build": "npm run typecheck && electron-vite build", "lint": "biome check", "lint:fix": "biome check --write", "format": "biome format", @@ -22,6 +20,8 @@ "package": "rm -rf build && npm run build && electron-forge package", "make": "rm -rf build && npm run build && electron-forge make", "postinstall": "electron-builder install-app-deps", + "build:web": "vite build --config vite.config.ts", + "build": "npm run typecheck && electron-vite build", "build:unpack": "npm run build && electron-builder --dir", "build:win": "npm run build && electron-builder --win", "build:mac": "electron-vite build && electron-builder --mac", From c2e5eac1aa3fc69b30f1add04b5747fcda0e190f Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 2 Feb 2026 00:53:15 -0300 Subject: [PATCH 020/263] build: add support for environmental variables for both web and electron apps --- electron.vite.config.ts | 8 ++++++++ vite.config.ts | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/electron.vite.config.ts b/electron.vite.config.ts index ea0d70e6..a83d94b9 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -1,3 +1,10 @@ +/** + * Electron-vite config for building the desktop app. + * Used by the `dev`, `build`, and `build:*` scripts. + * + * Configures all three Electron processes: main, preload, and renderer. + * `envDir` is set explicitly so `.env` files are resolved from the project root. + */ import { resolve } from "node:path"; import react from "@vitejs/plugin-react"; import { defineConfig, externalizeDepsPlugin } from "electron-vite"; @@ -10,6 +17,7 @@ export default defineConfig({ plugins: [externalizeDepsPlugin()], }, renderer: { + envDir: resolve("."), server: { port: 3000, }, diff --git a/vite.config.ts b/vite.config.ts index 84782767..9375df6b 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,3 +1,10 @@ +/** + * Vite config for building the renderer as a standalone web app (no Electron). + * Used by the `dev:web` and `build:web` scripts. + * + * Since `root` is set to `src/renderer`, `envDir` points back to the project + * root so that `.env` files are resolved from there. + */ import { resolve } from "node:path"; import { tanstackRouter } from "@tanstack/router-plugin/vite"; import react from "@vitejs/plugin-react"; @@ -12,6 +19,7 @@ export default defineConfig({ react(), ], root: "src/renderer", + envDir: resolve("."), server: { port: 3000, }, From e416ace8e566990a68161e6f94a68f82565ae7b8 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 2 Feb 2026 04:00:45 -0300 Subject: [PATCH 021/263] build: install and configure pandacss --- .gitignore | 3 + package.json | 3 + panda.config.ts | 211 +++++ pnpm-lock.yaml | 1516 +++++++++++++++++++++++++++++++++++- postcss.config.cjs | 5 + src/renderer/index.html | 3 + src/renderer/src/index.css | 1 + src/renderer/src/main.tsx | 1 + tsconfig.web.json | 3 +- 9 files changed, 1723 insertions(+), 23 deletions(-) create mode 100644 panda.config.ts create mode 100644 postcss.config.cjs create mode 100644 src/renderer/src/index.css diff --git a/.gitignore b/.gitignore index d0e24cbe..a0792194 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ node_modules/* npm-debug.log* yarn-debug.log* yarn-error.log* + +# Panda CSS generated files +src/renderer/src/styled diff --git a/package.json b/package.json index 751ab20e..44ae4f0a 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,8 @@ "package": "rm -rf build && npm run build && electron-forge package", "make": "rm -rf build && npm run build && electron-forge make", "postinstall": "electron-builder install-app-deps", + "panda:codegen": "panda codegen", + "prepare": "panda codegen", "build:web": "vite build --config vite.config.ts", "build": "npm run typecheck && electron-vite build", "build:unpack": "npm run build && electron-builder --dir", @@ -40,6 +42,7 @@ "@electron-forge/maker-squirrel": "^6.0.4", "@electron-forge/maker-zip": "^6.0.4", "@electron-toolkit/tsconfig": "^1.0.1", + "@pandacss/dev": "^1.8.1", "@stitches/react": "^1.2.8", "@tanstack/react-form": "1.11.0", "@tanstack/react-query": "^5.81.1", diff --git a/panda.config.ts b/panda.config.ts new file mode 100644 index 00000000..d29cae4b --- /dev/null +++ b/panda.config.ts @@ -0,0 +1,211 @@ +import { defineConfig, defineGlobalStyles } from "@pandacss/dev"; + +const globalCss = defineGlobalStyles({ + "*": { + fontFamily: + '"Archivo", -apple-system, Helvetica Neue, Helvetica, Roboto, sans-serif', // TODO: Replace token here (was $primary) + }, + + 'html': { + color: "#110041", +}, + + "mark.predicted-word": { + backgroundColor: "#E6E8FF", // TODO: Replace token here (was $primaryAlt) + fontFamily: '"Times New Roman", Times, serif', // TODO: Replace token here (was $file) + padding: "0px 0px 0px 2px", + borderRadius: "8px", + + "& strong": { + fontSize: "12px", + padding: "0px", + margin: "0px", + }, + + "& button.remove-tag": { + visibility: "hidden", + position: "relative", + backgroundColor: "#DC582E", // TODO: Replace token here (was $errorPrimary) + color: "#FFFFFF", // TODO: Replace token here (was $white) + padding: "3px 5px", + borderRadius: "8px", + cursor: "pointer", + fontSize: "10px", + fontWeight: 800, // TODO: Replace token here (was $heavy) + textAlign: "center", + top: "-10px", + right: "-5px", + border: "none", + }, + + "&:hover": { + cursor: "pointer", + "& button.remove-tag": { + visibility: "visible", + }, + }, + }, + + "mark.searched-word": { + backgroundColor: "#E0DDE2", // TODO: Replace token here (was $bgSecondaryAlt) + fontFamily: '"Times New Roman", Times, serif', // TODO: Replace token here (was $file) + padding: "0px 2px", + borderRadius: "8px", + + "&:hover": { + cursor: "pointer", + }, + + "& button.add-tag": { + position: "relative", + backgroundColor: "#1B834E", // TODO: Replace token here (was $successPrimary) + color: "#FFFFFF", // TODO: Replace token here (was $white) + padding: "2px 5px", + borderRadius: "8px", + cursor: "pointer", + fontSize: "12px", + fontWeight: 800, // TODO: Replace token here (was $heavy) + textAlign: "center", + top: "-10px", + right: "-5px", + border: "none", + }, + }, +}); + +const text = (size: number, weight: number) => ({ + value: { + fontSize: `${size}px`, + fontWeight: weight, + }, +}); + +const color = (hex: string) => ({ value: hex }); + +export default defineConfig({ + // Use CSS reset + preflight: true, + + // Where to look for CSS declarations + include: ["./src/renderer/src/**/*.{ts,tsx}"], + + // Files to exclude + exclude: [], + + // JSX framework + jsxFramework: "react", + + // Output directory for generated styled-system + outdir: "src/renderer/src/styled", + + // Global styles (migrated from Stitches globalStyles.ts) + globalCss, + + // Other configuration + strictTokens: true, + + theme: { + textStyles: { + title: { + md: { + strong: text(32, 600), + default: text(32, 400), + }, + }, + subtitle: { + md: { + strong: text(20, 600), + default: text(20, 400), + }, + sm: { + strong: text(14, 600), + default: text(14, 400), + }, + }, + paragraph: { + md: { + strong: text(18, 600), + default: text(18, 400), + }, + sm: { + strong: text(16, 600), + default: text(16, 400), + }, + xsm: { + strong: text(10, 600), + default: text(10, 400), + }, + }, + cta: { + md: { + strong: text(16, 600), + default: text(16, 400), + }, + }, + label: { + md: { + strong: text(16, 600), + default: text(16, 400), + }, + sm: { + strong: text(12, 600), + default: text(12, 400), + }, + }, + }, + semanticTokens: { + colors: { + brand: { + primary: color("#3F479D"), + secondary: color("#C3CCD7"), + tertiary: color("#4A5568"), + }, + text: { + default: color("#110041"), + lighter: color("#625C68"), + "onbutton-default": color("#110041"), + "onbutton-alternative": color("#FFFFFF"), + // TODO: needs to be corrected in the figma file + "onbutton-disabled": color("#FF0000"), + }, + action: { + default: color("#C5CAFF"), + disabled: color("#E0DDE2"), + "alt-default": color("#3F479D"), + hover: color("#110041"), + pressed: color("#3F479D"), + focus: color("#C5CAFF"), + }, + bg: { + primary: color("#F6F5F7"), + secondary: color("#FFFFFF"), + "primary-alternative": color("#E5E8FF"), + "primary-highlight": color("#C5CAFF"), + "secondary-highlight": color("#E0DDE2"), + // gradient: '' + }, + system: { + success: color("#1B834E"), + "success-secondary": color("#E0FAED"), + error: color("#DC582E"), + "error-secondary": color("#FFECE5"), + warning: color("#F2BA2C"), + "warning-secondary": color("#FFF7DB"), + info: color("#3F479D"), + "info-secondary": color("#F6F5F7"), + }, + }, + borders: { + primary: { value: "1px solid #BCBAB8" }, + secondary: { value: "1px solid #9F99A5" }, + "primary-alt": { value: "1px solid #110041" }, + }, + gradients: { + primary: { + value: + "linear-gradient(249.5deg, #C5CAFF -33.26%, #8591E8 28.49%, #3F479D 82.99%)", + }, + }, + }, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index af8cb3a4..6bafa6f9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,6 +39,9 @@ importers: '@electron-toolkit/tsconfig': specifier: ^1.0.1 version: 1.0.1(@types/node@20.19.1) + '@pandacss/dev': + specifier: ^1.8.1 + version: 1.8.1(hono@4.11.7)(typescript@5.9.2) '@stitches/react': specifier: ^1.2.8 version: 1.2.8(react@18.3.1) @@ -53,10 +56,10 @@ importers: version: 1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tanstack/react-router-devtools': specifier: ^1.139.12 - version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(solid-js@1.9.10)(tsx@4.20.6) + version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(lightningcss@1.30.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(solid-js@1.9.10)(tsx@4.20.6) '@tanstack/router-plugin': specifier: ^1.139.12 - version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@6.3.5(@types/node@20.19.1)(tsx@4.20.6)) + version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6)) '@types/node': specifier: '20' version: 20.19.1 @@ -71,7 +74,7 @@ importers: version: 3.4.1 '@vitejs/plugin-react': specifier: ^4.5.0 - version: 4.5.0(vite@6.3.5(@types/node@20.19.1)(tsx@4.20.6)) + version: 4.5.0(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6)) axios: specifier: ^1.1.3 version: 1.9.0 @@ -95,7 +98,7 @@ importers: version: 3.2.1 electron-vite: specifier: ^3.1.0 - version: 3.1.0(vite@6.3.5(@types/node@20.19.1)(tsx@4.20.6)) + version: 3.1.0(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6)) exceljs: specifier: ^4.4.0 version: 4.4.0 @@ -131,7 +134,7 @@ importers: version: 5.9.2 vite: specifier: ^6.3.5 - version: 6.3.5(@types/node@20.19.1)(tsx@4.20.6) + version: 6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6) wait-on: specifier: ^6.0.1 version: 6.0.1 @@ -390,6 +393,24 @@ packages: cpu: [x64] os: [win32] + '@clack/core@0.5.0': + resolution: {integrity: sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==} + + '@clack/prompts@0.11.0': + resolution: {integrity: sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==} + + '@csstools/postcss-cascade-layers@5.0.2': + resolution: {integrity: sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/selector-specificity@5.0.0': + resolution: {integrity: sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==} + engines: {node: '>=18'} + peerDependencies: + postcss-selector-parser: ^7.0.0 + '@develar/schema-utils@2.6.5': resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==} engines: {node: '>= 8.9.0'} @@ -708,6 +729,12 @@ packages: '@hapi/topo@5.1.0': resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + '@hono/node-server@1.19.9': + resolution: {integrity: sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -733,6 +760,9 @@ packages: '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} @@ -751,6 +781,16 @@ packages: resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==} engines: {node: '>= 10.0.0'} + '@modelcontextprotocol/sdk@1.25.3': + resolution: {integrity: sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -772,6 +812,58 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} deprecated: This functionality has been moved to @npmcli/fs + '@pandacss/config@1.8.1': + resolution: {integrity: sha512-SvFvfDav//c2lbk9+IPRGCLGhUd1G8z/Nxs0CwZNLXpI0xTNy0ISGMV1ZKkqBFbmH95e+/5oZXnnM4rAS1LO0g==} + + '@pandacss/core@1.8.1': + resolution: {integrity: sha512-8axy9BApvc/oX5/K2/qX23HX1cHvp3MI/fm+CDx31v9zH3MIy4X49MMDeEU9o6L2Q6p6yinPgQZi7gtOqw+mfQ==} + + '@pandacss/dev@1.8.1': + resolution: {integrity: sha512-rHE7JEDNbqLVpybgT1Ff5R1loYxX3sF/a729EVvsBUtcd/xSHZyjhg8vnB5hXajaWt9Ro+u7chAB6+pdqd1Jog==} + hasBin: true + + '@pandacss/extractor@1.8.1': + resolution: {integrity: sha512-fgztRMZq1f/M8zdCku9ads+Wslje9/stypjN/qLjV436NI2LWktDmWYGTiEyHZTR5yEfI2LtJCa1b1BvZcU07g==} + + '@pandacss/generator@1.8.1': + resolution: {integrity: sha512-+20L+KeSbd2tqalH51M8pAMcJ6HM9rgnKXOyNAN/kx78WXec4jCZN9z9CSCFbrRxH/qpcIx20oAXZBbNghHSyQ==} + + '@pandacss/is-valid-prop@1.8.1': + resolution: {integrity: sha512-gf2HTBCOboc65Jlb9swAjbffXSIv+A4vzSQ9iHyTCDLMcXTHYjPOQNliI36WkuQgR0pNXggBbQXGNaT9wKcrAw==} + + '@pandacss/logger@1.8.1': + resolution: {integrity: sha512-u++vUM+roJPPle0PQ1BGl6GkxwusfzEbKtX35L/5GtF6+CQ1ZfbD07HlMjEzmyEQ+KeQ8joR1Ubh/YGrZdEWrQ==} + + '@pandacss/mcp@1.8.1': + resolution: {integrity: sha512-z3VOz9XVvpdQ0bf6a1REGZToFFcwU/0jyK699fRD3jzMg+OJ24j/T8RZvlFoDPCWcifjXI7eUCSnUJ1TVqXfcQ==} + + '@pandacss/node@1.8.1': + resolution: {integrity: sha512-59Cb55sFL+TO2Sd/s2SxSvh0nY/ouBsJQYqRvUkgLL56FDH28euCYvj8Tt6H9rISKl6xhCpixF7svA8YjTOuXg==} + + '@pandacss/parser@1.8.1': + resolution: {integrity: sha512-dyWX+P4zouBuvqbWqySKDWnrIeq/C2jdeS/GjswQny3pGQHwm1np9yqHfNEtKlaIouXYACbjP1cXl/tEgiKXHA==} + + '@pandacss/postcss@1.8.1': + resolution: {integrity: sha512-xopXqr/Bh/KTewxgsYe2muHIsuLqrZ64RH1cW4KRY5TOI+JaL7M4qAPTqa/fVMh+LV9k0woTd423g7Q3d2oivA==} + + '@pandacss/preset-base@1.8.1': + resolution: {integrity: sha512-NJtVQz4Dn3FuFLci8GvbXVGegKvAkYh7xB5TwJA5mqwRIOqWZ6+U/WoVXu9aR9wj3/EYAhqA5qUJQXrC6dUFmA==} + + '@pandacss/preset-panda@1.8.1': + resolution: {integrity: sha512-89QSWcSdhr1ViW6o0YMAQrSCxmY+xsrr0eA6GnNT6FWkjwL1QAtwjezWwODHN26BjlNTLmW8aK39Tepj6Wh2Aw==} + + '@pandacss/reporter@1.8.1': + resolution: {integrity: sha512-aTAObZ8ALxhGIXtHMEJ0KzDx3au1qlwHe60EA4BGGEPfBg25ntM8SaSbxOMhwUcbD5VffzywRoJeqWMaPmg3zw==} + + '@pandacss/shared@1.8.1': + resolution: {integrity: sha512-8U+iqqvb1hmTRHOCkO4q29OMv//szv/wJAQG6SPEuYth7QH+fEvPMl2qsZyDTe1b+pkB1bt7tpvTF4+lR1K8EA==} + + '@pandacss/token-dictionary@1.8.1': + resolution: {integrity: sha512-6uDH/QbxE/sS/QzfaSswxa+hMdDR1U3PUGVD/uCrt3tJ4zTHgR2icZ3vH9GN9k17WFutzcVQaKTKscY3PYn9TA==} + + '@pandacss/types@1.8.1': + resolution: {integrity: sha512-5hNn6PsbmSWdHmfETGTGW+gpFmzf0xdKlzbFHIIKHZK+zicCtHIg6iMahZsf9wvYiBu0LAKwgdKR+kDMya5N8w==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -1135,6 +1227,9 @@ packages: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} + '@ts-morph/common@0.28.1': + resolution: {integrity: sha512-W74iWf7ILp1ZKNYXY5qbddNaml7e9Sedv5lvU1V8lftlitkc9Pq1A+jlH23ltDgWYeZFFEqGCD1Ies9hqu3O+g==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -1177,6 +1272,9 @@ packages: '@types/node@16.18.126': resolution: {integrity: sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==} + '@types/node@17.0.45': + resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} + '@types/node@20.19.1': resolution: {integrity: sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA==} @@ -1212,6 +1310,21 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 + '@vue/compiler-core@3.5.25': + resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==} + + '@vue/compiler-dom@3.5.25': + resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==} + + '@vue/compiler-sfc@3.5.25': + resolution: {integrity: sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==} + + '@vue/compiler-ssr@3.5.25': + resolution: {integrity: sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==} + + '@vue/shared@3.5.25': + resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==} + '@xmldom/xmldom@0.8.10': resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} engines: {node: '>=10.0.0'} @@ -1219,6 +1332,10 @@ packages: abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} @@ -1240,6 +1357,14 @@ packages: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv-keywords@3.5.2: resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} peerDependencies: @@ -1248,6 +1373,13 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -1350,6 +1482,10 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + baseline-browser-mapping@2.9.19: + resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} + hasBin: true + big-integer@1.6.52: resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} engines: {node: '>=0.6'} @@ -1370,6 +1506,10 @@ packages: bluebird@3.7.2: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + boolean@3.2.0: resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. @@ -1389,6 +1529,11 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.28.0: + resolution: {integrity: sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + buffer-crc32@0.2.13: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} @@ -1417,6 +1562,13 @@ packages: builder-util@26.0.11: resolution: {integrity: sha512-xNjXfsldUEe153h1DraD0XvDOpqGR0L5eKFkdReB7eFW5HqysDZFfly4rckda6y9dF39N3pkPlOblcfHKGw+uA==} + bundle-n-require@1.1.2: + resolution: {integrity: sha512-bEk2jakVK1ytnZ9R2AAiZEeK/GxPUM8jvcRxHZXifZDMcjkI4EG/GlsJ2YGSVYT9y/p/gA9/0yDY8rCGsSU6Tg==} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -1441,9 +1593,19 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + caniuse-api@3.0.0: + resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} + caniuse-lite@1.0.30001720: resolution: {integrity: sha512-Ec/2yV2nNPwb4DnTANEV99ZWwm3ZWfdlfkQbWSDDt+PsXEVYwlhPH8tdMaPunYTKKmz7AnHi2oNEi1GcmKCD8g==} + caniuse-lite@1.0.30001766: + resolution: {integrity: sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==} + chainsaw@0.1.0: resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==} @@ -1459,6 +1621,10 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} @@ -1512,6 +1678,9 @@ packages: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} + code-block-writer@13.0.3: + resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -1562,24 +1731,47 @@ packages: engines: {node: ^12.20.0 || ^14.13.0 || >=16.0.0} hasBin: true + confbox@0.2.2: + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + config-chain@1.1.13: resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} config-file-ts@0.2.8-rc1: resolution: {integrity: sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==} + content-disposition@1.0.1: + resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} cookie-es@2.0.0: resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + core-util-is@1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + crc-32@1.2.2: resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} engines: {node: '>=0.8'} @@ -1616,6 +1808,21 @@ packages: resolution: {integrity: sha512-n63i0lZ0rvQ6FXiGQ+/JFCKAUyPFhLQYJIqKaa+tSJtfKeULF/IDNDAbdnSIxgS4NTuw2b0+lj8LzfITuq+ZxQ==} engines: {node: '>=12.10'} + crosspath@2.0.0: + resolution: {integrity: sha512-ju88BYCQ2uvjO2bR+SsgLSTwTSctU+6Vp2ePbKPgSCZyy4MWZxYsT738DlKVRE5utUjobjPRm1MkTYKJxCmpTA==} + engines: {node: '>=14.9.0'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + cssnano-utils@5.0.1: + resolution: {integrity: sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -1660,6 +1867,15 @@ packages: supports-color: optional: true + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decode-formdata@0.9.0: resolution: {integrity: sha512-q5uwOjR3Um5YD+ZWPOF/1sGHVW9A5rCrRwITQChRXlmPkxDFBqCm4jNTIVdGHNH9OnR+V9MoZVgRhsFb+ARbUw==} @@ -1697,6 +1913,10 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + detect-libc@2.0.4: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} @@ -1747,6 +1967,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + ejs@3.1.10: resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} engines: {node: '>=0.10.0'} @@ -1806,6 +2029,9 @@ packages: electron-to-chromium@1.5.161: resolution: {integrity: sha512-hwtetwfKNZo/UlwHIVBlKZVdy7o8bIZxxKs0Mv/ROPiQQQmDgdm5a+KvKtBsxM8ZjFzTaCeLoodZ8jiBE3o9rA==} + electron-to-chromium@1.5.283: + resolution: {integrity: sha512-3vifjt1HgrGW/h76UEeny+adYApveS9dH2h3p57JYzBSXJIKUJAvtmIytDKjcSCt9xHfrNCFJ7gts6vkhuq++w==} + electron-vite@3.1.0: resolution: {integrity: sha512-M7aAzaRvSl5VO+6KN4neJCYLHLpF/iWo5ztchI/+wMxIieDZQqpbCYfaEHHHPH6eupEzfvZdLYdPdmvGqoVe0Q==} engines: {node: ^18.0.0 || >=20.0.0} @@ -1836,6 +2062,10 @@ packages: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} @@ -1846,6 +2076,10 @@ packages: resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==} engines: {node: '>=0.12'} + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -1884,6 +2118,9 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} @@ -1897,9 +2134,24 @@ packages: engines: {node: '>=4'} hasBin: true + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + eventsource-parser@3.0.6: + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + exceljs@4.4.0: resolution: {integrity: sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==} engines: {node: '>=8.3.0'} @@ -1919,6 +2171,19 @@ packages: exponential-backoff@3.1.2: resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} + express-rate-limit@7.5.1: + resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + extract-zip@2.0.1: resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} engines: {node: '>= 10.17.0'} @@ -1942,6 +2207,9 @@ packages: fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} @@ -1980,6 +2248,10 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + find-up@2.1.0: resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} engines: {node: '>=4'} @@ -2013,6 +2285,14 @@ packages: resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} engines: {node: '>= 6'} + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -2024,6 +2304,10 @@ packages: resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} engines: {node: '>=14.14'} + fs-extra@11.3.2: + resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} + engines: {node: '>=14.14'} + fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -2114,6 +2398,10 @@ packages: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true @@ -2203,6 +2491,13 @@ packages: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} engines: {node: '>=0.10.0'} + hono@4.11.7: + resolution: {integrity: sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==} + engines: {node: '>=16.9.0'} + + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -2213,6 +2508,10 @@ packages: http-cache-semantics@4.2.0: resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + http-proxy-agent@5.0.0: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} @@ -2254,6 +2553,10 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -2300,6 +2603,10 @@ packages: resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} engines: {node: '>= 12'} + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} @@ -2347,6 +2654,9 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-stream@1.1.0: resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} engines: {node: '>=0.10.0'} @@ -2393,9 +2703,15 @@ packages: engines: {node: '>=10'} hasBin: true + javascript-stringify@2.1.0: + resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==} + joi@17.13.3: resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} + jose@6.1.3: + resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2420,6 +2736,12 @@ packages: json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} @@ -2456,6 +2778,10 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + lazy-val@1.0.5: resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==} @@ -2466,6 +2792,76 @@ packages: lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} + lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} engines: {node: '>=10'} @@ -2553,6 +2949,15 @@ packages: lodash.isundefined@3.0.1: resolution: {integrity: sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==} + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + lodash.union@4.6.0: resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} @@ -2574,6 +2979,9 @@ packages: resolution: {integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + look-it-up@2.1.0: + resolution: {integrity: sha512-nMoGWW2HurtuJf6XAL56FWTDCWLOTSsanrgwOyaR5Y4e3zfG5N/0cU5xWZSEU3tBxhQugRbV1xL9jb+ug7yZww==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -2603,6 +3011,9 @@ packages: magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + make-fetch-happen@10.2.1: resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -2639,10 +3050,18 @@ packages: mdurl@1.0.1: resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + mem@4.3.0: resolution: {integrity: sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==} engines: {node: '>=6'} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -2650,6 +3069,9 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + microdiff@1.5.0: + resolution: {integrity: sha512-Drq+/THMvDdzRYrK0oxJmOKiC24ayUV8ahrt8l3oRK51PWt6gdtrIGrlIH3pT/lFh1z93FbAcidtsHcWbnRz8Q==} + micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} @@ -2662,10 +3084,18 @@ packages: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + mime@2.6.0: resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} engines: {node: '>=4.0.0'} @@ -2768,6 +3198,10 @@ packages: resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} engines: {node: '>= 0.6'} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + nice-try@1.0.5: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} @@ -2781,6 +3215,10 @@ packages: node-api-version@0.2.1: resolution: {integrity: sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==} + node-eval@2.0.0: + resolution: {integrity: sha512-Ap+L9HznXAVeJj3TJ1op6M6bg5xtTq8L5CU/PJxtkhea/DrIxdTknGKIECKd/v/Lgql95iuMAYvIzBNd0pmcMg==} + engines: {node: '>= 4'} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -2793,6 +3231,9 @@ packages: node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + nodemon@2.0.22: resolution: {integrity: sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==} engines: {node: '>=8.10.0'} @@ -2830,10 +3271,26 @@ packages: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} + object-path@0.11.8: + resolution: {integrity: sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==} + engines: {node: '>= 10.12.0'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -2849,6 +3306,9 @@ packages: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} + outdent@0.8.0: + resolution: {integrity: sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==} + p-cancelable@1.1.0: resolution: {integrity: sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==} engines: {node: '>=6'} @@ -2881,6 +3341,10 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-limit@5.0.0: + resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} + engines: {node: '>=18'} + p-locate@2.0.0: resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} engines: {node: '>=4'} @@ -2908,6 +3372,9 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + package-manager-detector@1.6.0: + resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} @@ -2923,6 +3390,13 @@ packages: resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} engines: {node: '>=0.10.0'} + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} @@ -2954,6 +3428,9 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + path-to-regexp@8.3.0: + resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + path-type@2.0.0: resolution: {integrity: sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ==} engines: {node: '>=4'} @@ -2968,6 +3445,9 @@ packages: pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + phosphor-react@1.4.1: resolution: {integrity: sha512-gO5j7U0xZrdglTAYDYPACU4xDOFBTJmptrrB/GeR+tHhCZF3nUMyGmV/0hnloKjuTrOmpSFlbfOY78H39rgjUQ==} engines: {node: '>=10'} @@ -3002,14 +3482,68 @@ packages: resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} engines: {node: '>=4'} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + plist@3.1.0: resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} engines: {node: '>=10.4.0'} + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + postcss-discard-duplicates@7.0.2: + resolution: {integrity: sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-discard-empty@7.0.1: + resolution: {integrity: sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-merge-rules@7.0.7: + resolution: {integrity: sha512-njWJrd/Ms6XViwowaaCc+/vqhPG3SmXn725AGrnl+BgTuRPEacjiLEaGq16J6XirMJbtKkTwnt67SS+e2WGoew==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-minify-selectors@7.0.5: + resolution: {integrity: sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-nested@7.0.2: + resolution: {integrity: sha512-5osppouFc0VR9/VYzYxO03VaDa3e8F23Kfd6/9qcZTUI8P58GIYlArOET2Wq0ywSl2o2PjELhYOFI4W7l5QHKw==} + engines: {node: '>=18.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-normalize-whitespace@7.0.1: + resolution: {integrity: sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + postcss@8.5.4: resolution: {integrity: sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==} engines: {node: ^10 || ^12 || >=14} @@ -3032,6 +3566,11 @@ packages: engines: {node: '>=10.13.0'} hasBin: true + prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + engines: {node: '>=14'} + hasBin: true + prettier@3.7.3: resolution: {integrity: sha512-QgODejq9K3OzoBbuyobZlUhznP5SKwPqp+6Q6xw6o8gnhr4O85L2U915iM2IDcfF2NPXVaM9zlo9tdwipnYwzg==} engines: {node: '>=14'} @@ -3063,6 +3602,10 @@ packages: proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -3076,6 +3619,10 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qs@6.14.1: + resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} + engines: {node: '>=0.6'} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -3083,6 +3630,14 @@ packages: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + rcedit@3.1.0: resolution: {integrity: sha512-WRlRdY1qZbu1L11DklT07KuHfRk42l0NFFJdaExELEu4fEQ982bP5Z6OWGPj/wLLIuKRQDCxZJGAwoFsxhZhNA==} engines: {node: '>= 10.0.0'} @@ -3126,6 +3681,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + recast@0.23.11: resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} engines: {node: '>= 4'} @@ -3141,6 +3700,10 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + resedit@1.7.2: resolution: {integrity: sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==} engines: {node: '>=12', npm: '>=6'} @@ -3218,6 +3781,10 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + run-con@1.2.12: resolution: {integrity: sha512-5257ILMYIF4RztL9uoZ7V9Q97zHtNHn5bN3NobeAnzB1P3ASLgg8qocM2u+R18ttp+VEM78N2LK8XcNVtnSRrg==} hasBin: true @@ -3270,6 +3837,10 @@ packages: engines: {node: '>=10'} hasBin: true + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + serialize-error@7.0.1: resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} engines: {node: '>=10'} @@ -3294,9 +3865,16 @@ packages: resolution: {integrity: sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==} engines: {node: '>=10'} + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + shebang-command@1.2.0: resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} engines: {node: '>=0.10.0'} @@ -3317,6 +3895,22 @@ packages: resolution: {integrity: sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==} engines: {node: '>= 0.4'} + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -3332,6 +3926,9 @@ packages: resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} engines: {node: '>=10'} + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + slice-ansi@3.0.0: resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} engines: {node: '>=8'} @@ -3400,6 +3997,10 @@ packages: resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==} engines: {node: '>= 6'} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -3470,6 +4071,10 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + table@6.9.0: + resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} + engines: {node: '>=10.0.0'} + tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} @@ -3523,6 +4128,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + touch@3.1.1: resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==} hasBin: true @@ -3544,10 +4153,36 @@ packages: truncate-utf8-bytes@1.0.2: resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - tsx@4.20.6: + ts-evaluator@1.2.0: + resolution: {integrity: sha512-ncSGek1p92bj2ifB7s9UBgryHCkU9vwC5d+Lplt12gT9DH+e41X8dMoHRQjIMeAvyG7j9dEnuHmwgOtuRIQL+Q==} + engines: {node: '>=14.19.0'} + peerDependencies: + jsdom: '>=14.x || >=15.x || >=16.x || >=17.x || >=18.x || >=19.x || >=20.x || >=21.x || >=22.x' + typescript: '>=3.2.x || >= 4.x || >= 5.x' + peerDependenciesMeta: + jsdom: + optional: true + + ts-morph@27.0.2: + resolution: {integrity: sha512-fhUhgeljcrdZ+9DZND1De1029PrE+cMkIP7ooqkLRTrRLTqcki2AstsyJm0vRNbTbVCNJ0idGlbBrfqc7/nA8w==} + + ts-pattern@5.9.0: + resolution: {integrity: sha512-6s5V71mX8qBUmlgbrfL33xDUwO0fq48rxAu2LBE11WBeGdpCPOsXksQbZJHvHwhrd3QjUusd3mAOM5Gg0mFBLg==} + + tsconfck@3.1.6: + resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsx@4.20.6: resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} engines: {node: '>=18.0.0'} hasBin: true @@ -3568,11 +4203,20 @@ packages: resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} engines: {node: '>=10'} + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + typescript@5.9.2: resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} engines: {node: '>=14.17'} hasBin: true + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + uc.micro@1.0.6: resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} @@ -3598,6 +4242,10 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + unplugin@2.3.11: resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} engines: {node: '>=18.12.0'} @@ -3614,6 +4262,12 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -3648,6 +4302,10 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + verror@1.10.1: resolution: {integrity: sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==} engines: {node: '>=0.6.0'} @@ -3762,6 +4420,10 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wordwrapjs@5.1.1: + resolution: {integrity: sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==} + engines: {node: '>=12.17'} + wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -3829,10 +4491,19 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + zip-stream@4.1.1: resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} engines: {node: '>= 10'} + zod-to-json-schema@3.25.1: + resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} + peerDependencies: + zod: ^3.25 || ^4 + zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} @@ -4178,6 +4849,27 @@ snapshots: '@biomejs/cli-win32-x64@1.9.4': optional: true + '@clack/core@0.5.0': + dependencies: + picocolors: 1.1.1 + sisteransi: 1.0.5 + + '@clack/prompts@0.11.0': + dependencies: + '@clack/core': 0.5.0 + picocolors: 1.1.1 + sisteransi: 1.0.5 + + '@csstools/postcss-cascade-layers@5.0.2(postcss@8.5.6)': + dependencies: + '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + '@csstools/selector-specificity@5.0.0(postcss-selector-parser@7.1.1)': + dependencies: + postcss-selector-parser: 7.1.1 + '@develar/schema-utils@2.6.5': dependencies: ajv: 6.12.6 @@ -4682,6 +5374,10 @@ snapshots: dependencies: '@hapi/hoek': 9.3.0 + '@hono/node-server@1.19.9(hono@4.11.7)': + dependencies: + hono: 4.11.7 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -4713,6 +5409,8 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 @@ -4740,6 +5438,28 @@ snapshots: transitivePeerDependencies: - supports-color + '@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@4.0.14)': + dependencies: + '@hono/node-server': 1.19.9(hono@4.11.7) + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 7.5.1(express@5.2.1) + jose: 6.1.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.0.14 + zod-to-json-schema: 3.25.1(zod@4.0.14) + transitivePeerDependencies: + - hono + - supports-color + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4762,6 +5482,197 @@ snapshots: mkdirp: 1.0.4 rimraf: 3.0.2 + '@pandacss/config@1.8.1': + dependencies: + '@pandacss/logger': 1.8.1 + '@pandacss/preset-base': 1.8.1 + '@pandacss/preset-panda': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/types': 1.8.1 + bundle-n-require: 1.1.2 + escalade: 3.2.0 + microdiff: 1.5.0 + typescript: 5.9.3 + + '@pandacss/core@1.8.1': + dependencies: + '@csstools/postcss-cascade-layers': 5.0.2(postcss@8.5.6) + '@pandacss/is-valid-prop': 1.8.1 + '@pandacss/logger': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/token-dictionary': 1.8.1 + '@pandacss/types': 1.8.1 + browserslist: 4.28.0 + hookable: 5.5.3 + lightningcss: 1.30.2 + lodash.merge: 4.6.2 + outdent: 0.8.0 + postcss: 8.5.6 + postcss-discard-duplicates: 7.0.2(postcss@8.5.6) + postcss-discard-empty: 7.0.1(postcss@8.5.6) + postcss-merge-rules: 7.0.7(postcss@8.5.6) + postcss-minify-selectors: 7.0.5(postcss@8.5.6) + postcss-nested: 7.0.2(postcss@8.5.6) + postcss-normalize-whitespace: 7.0.1(postcss@8.5.6) + postcss-selector-parser: 7.1.1 + ts-pattern: 5.9.0 + + '@pandacss/dev@1.8.1(hono@4.11.7)(typescript@5.9.2)': + dependencies: + '@clack/prompts': 0.11.0 + '@pandacss/config': 1.8.1 + '@pandacss/logger': 1.8.1 + '@pandacss/mcp': 1.8.1(hono@4.11.7)(typescript@5.9.2) + '@pandacss/node': 1.8.1(typescript@5.9.2) + '@pandacss/postcss': 1.8.1(typescript@5.9.2) + '@pandacss/preset-base': 1.8.1 + '@pandacss/preset-panda': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/token-dictionary': 1.8.1 + '@pandacss/types': 1.8.1 + cac: 6.7.14 + transitivePeerDependencies: + - '@cfworker/json-schema' + - hono + - jsdom + - supports-color + - typescript + + '@pandacss/extractor@1.8.1(typescript@5.9.2)': + dependencies: + '@pandacss/shared': 1.8.1 + ts-evaluator: 1.2.0(typescript@5.9.2) + ts-morph: 27.0.2 + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/generator@1.8.1': + dependencies: + '@pandacss/core': 1.8.1 + '@pandacss/is-valid-prop': 1.8.1 + '@pandacss/logger': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/token-dictionary': 1.8.1 + '@pandacss/types': 1.8.1 + javascript-stringify: 2.1.0 + outdent: 0.8.0 + pluralize: 8.0.0 + postcss: 8.5.6 + ts-pattern: 5.9.0 + + '@pandacss/is-valid-prop@1.8.1': {} + + '@pandacss/logger@1.8.1': + dependencies: + '@pandacss/types': 1.8.1 + kleur: 4.1.5 + + '@pandacss/mcp@1.8.1(hono@4.11.7)(typescript@5.9.2)': + dependencies: + '@clack/prompts': 0.11.0 + '@modelcontextprotocol/sdk': 1.25.3(hono@4.11.7)(zod@4.0.14) + '@pandacss/logger': 1.8.1 + '@pandacss/node': 1.8.1(typescript@5.9.2) + '@pandacss/token-dictionary': 1.8.1 + '@pandacss/types': 1.8.1 + zod: 4.0.14 + transitivePeerDependencies: + - '@cfworker/json-schema' + - hono + - jsdom + - supports-color + - typescript + + '@pandacss/node@1.8.1(typescript@5.9.2)': + dependencies: + '@pandacss/config': 1.8.1 + '@pandacss/core': 1.8.1 + '@pandacss/generator': 1.8.1 + '@pandacss/logger': 1.8.1 + '@pandacss/parser': 1.8.1(typescript@5.9.2) + '@pandacss/reporter': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/token-dictionary': 1.8.1 + '@pandacss/types': 1.8.1 + browserslist: 4.28.0 + chokidar: 4.0.3 + fast-glob: 3.3.3 + fs-extra: 11.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + lodash.merge: 4.6.2 + look-it-up: 2.1.0 + outdent: 0.8.0 + p-limit: 5.0.0 + package-manager-detector: 1.6.0 + perfect-debounce: 1.0.0 + picomatch: 4.0.3 + pkg-types: 2.3.0 + pluralize: 8.0.0 + postcss: 8.5.6 + prettier: 3.2.5 + ts-morph: 27.0.2 + ts-pattern: 5.9.0 + tsconfck: 3.1.6(typescript@5.9.2) + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/parser@1.8.1(typescript@5.9.2)': + dependencies: + '@pandacss/config': 1.8.1 + '@pandacss/core': 1.8.1 + '@pandacss/extractor': 1.8.1(typescript@5.9.2) + '@pandacss/logger': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/types': 1.8.1 + '@vue/compiler-sfc': 3.5.25 + magic-string: 0.30.21 + ts-morph: 27.0.2 + ts-pattern: 5.9.0 + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/postcss@1.8.1(typescript@5.9.2)': + dependencies: + '@pandacss/node': 1.8.1(typescript@5.9.2) + postcss: 8.5.6 + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/preset-base@1.8.1': + dependencies: + '@pandacss/types': 1.8.1 + + '@pandacss/preset-panda@1.8.1': + dependencies: + '@pandacss/types': 1.8.1 + + '@pandacss/reporter@1.8.1': + dependencies: + '@pandacss/core': 1.8.1 + '@pandacss/generator': 1.8.1 + '@pandacss/logger': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/types': 1.8.1 + table: 6.9.0 + wordwrapjs: 5.1.1 + + '@pandacss/shared@1.8.1': {} + + '@pandacss/token-dictionary@1.8.1': + dependencies: + '@pandacss/logger': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/types': 1.8.1 + picomatch: 4.0.3 + ts-pattern: 5.9.0 + + '@pandacss/types@1.8.1': {} + '@pkgjs/parseargs@0.11.0': optional: true @@ -4940,13 +5851,13 @@ snapshots: '@tanstack/query-core': 5.81.1 react: 18.3.1 - '@tanstack/react-router-devtools@1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(solid-js@1.9.10)(tsx@4.20.6)': + '@tanstack/react-router-devtools@1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(lightningcss@1.30.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(solid-js@1.9.10)(tsx@4.20.6)': dependencies: '@tanstack/react-router': 1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@tanstack/router-devtools-core': 1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(solid-js@1.9.10)(tsx@4.20.6) + '@tanstack/router-devtools-core': 1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(lightningcss@1.30.2)(solid-js@1.9.10)(tsx@4.20.6) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - vite: 7.2.4(@types/node@20.19.1)(tsx@4.20.6) + vite: 7.2.4(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6) optionalDependencies: '@tanstack/router-core': 1.139.12 transitivePeerDependencies: @@ -4999,14 +5910,14 @@ snapshots: tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - '@tanstack/router-devtools-core@1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(solid-js@1.9.10)(tsx@4.20.6)': + '@tanstack/router-devtools-core@1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(lightningcss@1.30.2)(solid-js@1.9.10)(tsx@4.20.6)': dependencies: '@tanstack/router-core': 1.139.12 clsx: 2.1.1 goober: 2.1.18(csstype@3.1.3) solid-js: 1.9.10 tiny-invariant: 1.3.3 - vite: 7.2.4(@types/node@20.19.1)(tsx@4.20.6) + vite: 7.2.4(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6) optionalDependencies: csstype: 3.1.3 transitivePeerDependencies: @@ -5035,7 +5946,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@6.3.5(@types/node@20.19.1)(tsx@4.20.6))': + '@tanstack/router-plugin@1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) @@ -5053,7 +5964,7 @@ snapshots: zod: 3.25.76 optionalDependencies: '@tanstack/react-router': 1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - vite: 6.3.5(@types/node@20.19.1)(tsx@4.20.6) + vite: 6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6) transitivePeerDependencies: - supports-color @@ -5078,6 +5989,12 @@ snapshots: '@tootallnate/once@2.0.0': {} + '@ts-morph/common@0.28.1': + dependencies: + minimatch: 10.0.1 + path-browserify: 1.0.1 + tinyglobby: 0.2.15 + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.27.4 @@ -5130,6 +6047,8 @@ snapshots: '@types/node@16.18.126': {} + '@types/node@17.0.45': {} + '@types/node@20.19.1': dependencies: undici-types: 6.21.0 @@ -5165,7 +6084,7 @@ snapshots: '@types/node': 16.18.126 optional: true - '@vitejs/plugin-react@4.5.0(vite@6.3.5(@types/node@20.19.1)(tsx@4.20.6))': + '@vitejs/plugin-react@4.5.0(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6))': dependencies: '@babel/core': 7.27.4 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.27.4) @@ -5173,14 +6092,51 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.9 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.3.5(@types/node@20.19.1)(tsx@4.20.6) + vite: 6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6) transitivePeerDependencies: - supports-color + '@vue/compiler-core@3.5.25': + dependencies: + '@babel/parser': 7.28.5 + '@vue/shared': 3.5.25 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.25': + dependencies: + '@vue/compiler-core': 3.5.25 + '@vue/shared': 3.5.25 + + '@vue/compiler-sfc@3.5.25': + dependencies: + '@babel/parser': 7.28.5 + '@vue/compiler-core': 3.5.25 + '@vue/compiler-dom': 3.5.25 + '@vue/compiler-ssr': 3.5.25 + '@vue/shared': 3.5.25 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.6 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.25': + dependencies: + '@vue/compiler-dom': 3.5.25 + '@vue/shared': 3.5.25 + + '@vue/shared@3.5.25': {} + '@xmldom/xmldom@0.8.10': {} abbrev@1.1.1: {} + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + acorn@8.15.0: {} agent-base@6.0.2: @@ -5200,6 +6156,10 @@ snapshots: clean-stack: 2.2.0 indent-string: 4.0.0 + ajv-formats@3.0.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + ajv-keywords@3.5.2(ajv@6.12.6): dependencies: ajv: 6.12.6 @@ -5211,6 +6171,15 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-colors@4.1.3: {} + ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 @@ -5363,6 +6332,8 @@ snapshots: base64-js@1.5.1: {} + baseline-browser-mapping@2.9.19: {} + big-integer@1.6.52: {} binary-extensions@2.3.0: {} @@ -5382,6 +6353,20 @@ snapshots: bluebird@3.7.2: {} + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.14.1 + raw-body: 3.0.2 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + boolean@3.2.0: optional: true @@ -5405,6 +6390,14 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.25.0) + browserslist@4.28.0: + dependencies: + baseline-browser-mapping: 2.9.19 + caniuse-lite: 1.0.30001766 + electron-to-chromium: 1.5.283 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.0) + buffer-crc32@0.2.13: {} buffer-equal@1.0.1: {} @@ -5449,6 +6442,13 @@ snapshots: transitivePeerDependencies: - supports-color + bundle-n-require@1.1.2: + dependencies: + esbuild: 0.25.5 + node-eval: 2.0.0 + + bytes@3.1.2: {} + cac@6.7.14: {} cacache@16.1.3: @@ -5501,8 +6501,22 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + caniuse-api@3.0.0: + dependencies: + browserslist: 4.28.0 + caniuse-lite: 1.0.30001720 + lodash.memoize: 4.1.2 + lodash.uniq: 4.5.0 + caniuse-lite@1.0.30001720: {} + caniuse-lite@1.0.30001766: {} + chainsaw@0.1.0: dependencies: traverse: 0.3.9 @@ -5526,6 +6540,10 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + chownr@2.0.0: {} chromium-pickle-js@0.2.0: {} @@ -5575,6 +6593,8 @@ snapshots: clsx@2.1.1: {} + code-block-writer@13.0.3: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -5621,6 +6641,8 @@ snapshots: tree-kill: 1.2.2 yargs: 17.7.2 + confbox@0.2.2: {} + config-chain@1.1.13: dependencies: ini: 1.3.8 @@ -5632,15 +6654,28 @@ snapshots: glob: 10.4.5 typescript: 5.9.2 + content-disposition@1.0.1: {} + + content-type@1.0.5: {} + convert-source-map@2.0.0: {} cookie-es@2.0.0: {} + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + core-util-is@1.0.2: optional: true core-util-is@1.0.3: {} + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + crc-32@1.2.2: {} crc32-stream@4.0.3: @@ -5682,6 +6717,16 @@ snapshots: cross-zip@4.0.1: {} + crosspath@2.0.0: + dependencies: + '@types/node': 17.0.45 + + cssesc@3.0.0: {} + + cssnano-utils@5.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + csstype@3.1.3: {} date-fns@2.30.0: @@ -5708,6 +6753,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.3: + dependencies: + ms: 2.1.3 + decode-formdata@0.9.0: {} decompress-response@3.3.0: @@ -5744,6 +6793,8 @@ snapshots: delayed-stream@1.0.0: {} + depd@2.0.0: {} + detect-libc@2.0.4: {} detect-node@2.1.0: @@ -5810,6 +6861,8 @@ snapshots: eastasianwidth@0.2.0: {} + ee-first@1.1.1: {} + ejs@3.1.10: dependencies: jake: 10.9.2 @@ -5957,7 +7010,9 @@ snapshots: electron-to-chromium@1.5.161: {} - electron-vite@3.1.0(vite@6.3.5(@types/node@20.19.1)(tsx@4.20.6)): + electron-to-chromium@1.5.283: {} + + electron-vite@3.1.0(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6)): dependencies: '@babel/core': 7.27.4 '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.27.4) @@ -5965,7 +7020,7 @@ snapshots: esbuild: 0.25.5 magic-string: 0.30.17 picocolors: 1.1.1 - vite: 6.3.5(@types/node@20.19.1)(tsx@4.20.6) + vite: 6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6) transitivePeerDependencies: - supports-color @@ -5996,6 +7051,8 @@ snapshots: encodeurl@1.0.2: optional: true + encodeurl@2.0.0: {} + encoding@0.1.13: dependencies: iconv-lite: 0.6.3 @@ -6007,6 +7064,8 @@ snapshots: entities@3.0.1: {} + entities@4.5.0: {} + env-paths@2.2.1: {} err-code@2.0.3: {} @@ -6063,6 +7122,8 @@ snapshots: escalade@3.2.0: {} + escape-html@1.0.3: {} + escape-string-regexp@1.0.5: {} escape-string-regexp@4.0.0: @@ -6070,8 +7131,18 @@ snapshots: esprima@4.0.1: {} + estree-walker@2.0.2: {} + + etag@1.8.1: {} + eventemitter3@5.0.1: {} + eventsource-parser@3.0.6: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + exceljs@4.4.0: dependencies: archiver: 5.3.2 @@ -6112,6 +7183,45 @@ snapshots: exponential-backoff@3.1.2: {} + express-rate-limit@7.5.1(express@5.2.1): + dependencies: + express: 5.2.1 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.0.1 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.1 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.14.1 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + exsolve@1.0.8: {} + extract-zip@2.0.1: dependencies: debug: 4.4.1 @@ -6142,6 +7252,8 @@ snapshots: fast-json-stable-stringify@2.1.0: {} + fast-uri@3.1.0: {} + fastq@1.19.1: dependencies: reusify: 1.1.0 @@ -6174,6 +7286,17 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@2.1.1: + dependencies: + debug: 4.4.1 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + find-up@2.1.0: dependencies: locate-path: 2.0.0 @@ -6209,6 +7332,10 @@ snapshots: es-set-tostringtag: 2.1.0 mime-types: 2.1.35 + forwarded@0.2.0: {} + + fresh@2.0.0: {} + fs-constants@1.0.0: {} fs-extra@10.1.0: @@ -6223,6 +7350,12 @@ snapshots: jsonfile: 6.1.0 universalify: 2.0.1 + fs-extra@11.3.2: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + fs-extra@7.0.1: dependencies: graceful-fs: 4.2.11 @@ -6332,6 +7465,10 @@ snapshots: dependencies: is-glob: 4.0.3 + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + glob@10.4.5: dependencies: foreground-child: 3.3.1 @@ -6467,6 +7604,10 @@ snapshots: dependencies: parse-passwd: 1.0.0 + hono@4.11.7: {} + + hookable@5.5.3: {} + hosted-git-info@2.8.9: {} hosted-git-info@4.1.0: @@ -6475,6 +7616,14 @@ snapshots: http-cache-semantics@4.2.0: {} + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + http-proxy-agent@5.0.0: dependencies: '@tootallnate/once': 2.0.0 @@ -6527,6 +7676,10 @@ snapshots: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: {} ignore-by-default@1.0.1: {} @@ -6559,6 +7712,8 @@ snapshots: jsbn: 1.1.0 sprintf-js: 1.1.3 + ipaddr.js@1.9.1: {} + is-arrayish@0.2.1: {} is-binary-path@2.1.0: @@ -6591,6 +7746,8 @@ snapshots: is-number@7.0.0: {} + is-promise@4.0.0: {} + is-stream@1.1.0: {} is-stream@3.0.0: {} @@ -6626,6 +7783,8 @@ snapshots: filelist: 1.0.4 minimatch: 3.1.2 + javascript-stringify@2.1.0: {} + joi@17.13.3: dependencies: '@hapi/hoek': 9.3.0 @@ -6634,6 +7793,8 @@ snapshots: '@sideway/formula': 3.0.1 '@sideway/pinpoint': 2.0.0 + jose@6.1.3: {} + js-tokens@4.0.0: {} js-yaml@4.1.0: @@ -6650,6 +7811,10 @@ snapshots: json-schema-traverse@0.4.1: {} + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + json-stringify-safe@5.0.1: optional: true @@ -6688,6 +7853,8 @@ snapshots: dependencies: json-buffer: 3.0.1 + kleur@4.1.5: {} + lazy-val@1.0.5: {} lazystream@1.0.1: @@ -6698,6 +7865,55 @@ snapshots: dependencies: immediate: 3.0.6 + lightningcss-android-arm64@1.30.2: + optional: true + + lightningcss-darwin-arm64@1.30.2: + optional: true + + lightningcss-darwin-x64@1.30.2: + optional: true + + lightningcss-freebsd-x64@1.30.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.2: + optional: true + + lightningcss-linux-arm64-gnu@1.30.2: + optional: true + + lightningcss-linux-arm64-musl@1.30.2: + optional: true + + lightningcss-linux-x64-gnu@1.30.2: + optional: true + + lightningcss-linux-x64-musl@1.30.2: + optional: true + + lightningcss-win32-arm64-msvc@1.30.2: + optional: true + + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: + dependencies: + detect-libc: 2.0.4 + optionalDependencies: + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 + lilconfig@2.1.0: {} linkify-it@4.0.1: @@ -6786,6 +8002,12 @@ snapshots: lodash.isundefined@3.0.1: {} + lodash.memoize@4.1.2: {} + + lodash.merge@4.6.2: {} + + lodash.truncate@4.4.2: {} + lodash.union@4.6.0: {} lodash.uniq@4.5.0: {} @@ -6812,6 +8034,8 @@ snapshots: strip-ansi: 7.1.0 wrap-ansi: 8.1.0 + look-it-up@2.1.0: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -6836,6 +8060,10 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + make-fetch-happen@10.2.1: dependencies: agentkeepalive: 4.6.0 @@ -6898,16 +8126,22 @@ snapshots: mdurl@1.0.1: {} + media-typer@1.1.0: {} + mem@4.3.0: dependencies: map-age-cleaner: 0.1.3 mimic-fn: 2.1.0 p-is-promise: 2.1.0 + merge-descriptors@2.0.0: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} + microdiff@1.5.0: {} + micromatch@4.0.5: dependencies: braces: 3.0.3 @@ -6920,10 +8154,16 @@ snapshots: mime-db@1.52.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + mime@2.6.0: {} mimic-fn@2.1.0: {} @@ -7005,6 +8245,8 @@ snapshots: negotiator@0.6.4: {} + negotiator@1.0.0: {} + nice-try@1.0.5: {} node-abi@3.75.0: @@ -7018,6 +8260,10 @@ snapshots: dependencies: semver: 7.7.2 + node-eval@2.0.0: + dependencies: + path-is-absolute: 1.0.1 + node-fetch@2.7.0(encoding@0.1.13): dependencies: whatwg-url: 5.0.0 @@ -7026,6 +8272,8 @@ snapshots: node-releases@2.0.19: {} + node-releases@2.0.27: {} + nodemon@2.0.22: dependencies: chokidar: 3.6.0 @@ -7070,9 +8318,19 @@ snapshots: dependencies: path-key: 4.0.0 + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + object-keys@1.1.1: optional: true + object-path@0.11.8: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -7097,6 +8355,8 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 + outdent@0.8.0: {} + p-cancelable@1.1.0: {} p-cancelable@2.1.1: {} @@ -7119,6 +8379,10 @@ snapshots: dependencies: yocto-queue: 0.1.0 + p-limit@5.0.0: + dependencies: + yocto-queue: 1.2.2 + p-locate@2.0.0: dependencies: p-limit: 1.3.0 @@ -7141,6 +8405,8 @@ snapshots: package-json-from-dist@1.0.1: {} + package-manager-detector@1.6.0: {} + pako@1.0.11: {} parse-author@2.0.0: @@ -7153,6 +8419,10 @@ snapshots: parse-passwd@1.0.0: {} + parseurl@1.3.3: {} + + path-browserify@1.0.1: {} + path-exists@3.0.0: {} path-exists@4.0.0: {} @@ -7172,6 +8442,8 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 + path-to-regexp@8.3.0: {} + path-type@2.0.0: dependencies: pify: 2.3.0 @@ -7182,6 +8454,8 @@ snapshots: pend@1.2.0: {} + perfect-debounce@1.0.0: {} + phosphor-react@1.4.1(react@18.3.1): dependencies: react: 18.3.1 @@ -7201,16 +8475,65 @@ snapshots: pify@3.0.0: optional: true + pkce-challenge@5.0.1: {} + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 + pkg-types@2.3.0: + dependencies: + confbox: 0.2.2 + exsolve: 1.0.8 + pathe: 2.0.3 + plist@3.1.0: dependencies: '@xmldom/xmldom': 0.8.10 base64-js: 1.5.1 xmlbuilder: 15.1.1 + pluralize@8.0.0: {} + + postcss-discard-duplicates@7.0.2(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-discard-empty@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-merge-rules@7.0.7(postcss@8.5.6): + dependencies: + browserslist: 4.28.0 + caniuse-api: 3.0.0 + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-minify-selectors@7.0.5(postcss@8.5.6): + dependencies: + cssesc: 3.0.0 + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-nested@7.0.2(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-normalize-whitespace@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + postcss@8.5.4: dependencies: nanoid: 3.3.11 @@ -7232,6 +8555,8 @@ snapshots: prettier@2.8.8: {} + prettier@3.2.5: {} + prettier@3.7.3: {} proc-log@2.0.1: {} @@ -7250,6 +8575,11 @@ snapshots: proto-list@1.2.4: optional: true + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + proxy-from-env@1.1.0: {} pstree.remy@1.1.8: {} @@ -7261,10 +8591,23 @@ snapshots: punycode@2.3.1: {} + qs@6.14.1: + dependencies: + side-channel: 1.1.0 + queue-microtask@1.2.3: {} quick-lru@5.1.1: {} + range-parser@1.2.1: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + rcedit@3.1.0: dependencies: cross-spawn-windows-exe: 1.2.0 @@ -7322,6 +8665,8 @@ snapshots: dependencies: picomatch: 2.3.1 + readdirp@4.1.2: {} + recast@0.23.11: dependencies: ast-types: 0.16.1 @@ -7338,6 +8683,8 @@ snapshots: require-directory@2.1.1: {} + require-from-string@2.0.2: {} + resedit@1.7.2: dependencies: pe-library: 0.4.1 @@ -7461,6 +8808,16 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.53.3 fsevents: 2.3.3 + router@2.2.0: + dependencies: + debug: 4.4.1 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.3.0 + transitivePeerDependencies: + - supports-color + run-con@1.2.12: dependencies: deep-extend: 0.6.0 @@ -7507,6 +8864,22 @@ snapshots: semver@7.7.2: {} + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + serialize-error@7.0.1: dependencies: type-fest: 0.13.1 @@ -7524,8 +8897,19 @@ snapshots: seroval@1.4.0: {} + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + setimmediate@1.0.5: {} + setprototypeof@1.2.0: {} + shebang-command@1.2.0: dependencies: shebang-regex: 1.0.0 @@ -7540,6 +8924,34 @@ snapshots: shell-quote@1.8.2: {} + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + signal-exit@3.0.7: {} signal-exit@4.1.0: {} @@ -7552,6 +8964,8 @@ snapshots: dependencies: semver: 7.7.2 + sisteransi@1.0.5: {} + slice-ansi@3.0.0: dependencies: ansi-styles: 4.3.0 @@ -7625,6 +9039,8 @@ snapshots: stat-mode@1.0.0: {} + statuses@2.0.2: {} + string-argv@0.3.2: {} string-width@4.2.3: @@ -7689,6 +9105,14 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + table@6.9.0: + dependencies: + ajv: 8.17.1 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + tar-stream@2.2.0: dependencies: bl: 4.1.0 @@ -7751,6 +9175,8 @@ snapshots: dependencies: is-number: 7.0.0 + toidentifier@1.0.1: {} + touch@3.1.1: {} tr46@0.0.3: {} @@ -7767,6 +9193,24 @@ snapshots: dependencies: utf8-byte-length: 1.0.5 + ts-evaluator@1.2.0(typescript@5.9.2): + dependencies: + ansi-colors: 4.1.3 + crosspath: 2.0.0 + object-path: 0.11.8 + typescript: 5.9.2 + + ts-morph@27.0.2: + dependencies: + '@ts-morph/common': 0.28.1 + code-block-writer: 13.0.3 + + ts-pattern@5.9.0: {} + + tsconfck@3.1.6(typescript@5.9.2): + optionalDependencies: + typescript: 5.9.2 + tslib@2.8.1: {} tsx@4.20.6: @@ -7786,8 +9230,16 @@ snapshots: type-fest@1.4.0: {} + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 + typescript@5.9.2: {} + typescript@5.9.3: {} + uc.micro@1.0.6: {} undefsafe@2.0.5: {} @@ -7806,6 +9258,8 @@ snapshots: universalify@2.0.1: {} + unpipe@1.0.0: {} + unplugin@2.3.11: dependencies: '@jridgewell/remapping': 2.3.5 @@ -7838,6 +9292,12 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + update-browserslist-db@1.2.3(browserslist@4.28.0): + dependencies: + browserslist: 4.28.0 + escalade: 3.2.0 + picocolors: 1.1.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -7870,6 +9330,8 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 + vary@1.1.2: {} + verror@1.10.1: dependencies: assert-plus: 1.0.0 @@ -7877,7 +9339,7 @@ snapshots: extsprintf: 1.4.1 optional: true - vite@6.3.5(@types/node@20.19.1)(tsx@4.20.6): + vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6): dependencies: esbuild: 0.25.5 fdir: 6.4.5(picomatch@4.0.2) @@ -7888,9 +9350,10 @@ snapshots: optionalDependencies: '@types/node': 20.19.1 fsevents: 2.3.3 + lightningcss: 1.30.2 tsx: 4.20.6 - vite@7.2.4(@types/node@20.19.1)(tsx@4.20.6): + vite@7.2.4(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6): dependencies: esbuild: 0.25.5 fdir: 6.5.0(picomatch@4.0.3) @@ -7901,6 +9364,7 @@ snapshots: optionalDependencies: '@types/node': 20.19.1 fsevents: 2.3.3 + lightningcss: 1.30.2 tsx: 4.20.6 wait-on@6.0.1: @@ -7937,6 +9401,8 @@ snapshots: word-wrap@1.2.5: optional: true + wordwrapjs@5.1.1: {} + wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 @@ -8009,12 +9475,18 @@ snapshots: yocto-queue@0.1.0: {} + yocto-queue@1.2.2: {} + zip-stream@4.1.1: dependencies: archiver-utils: 3.0.4 compress-commons: 4.1.2 readable-stream: 3.6.2 + zod-to-json-schema@3.25.1(zod@4.0.14): + dependencies: + zod: 4.0.14 + zod@3.25.76: {} zod@4.0.14: {} diff --git a/postcss.config.cjs b/postcss.config.cjs new file mode 100644 index 00000000..1bfc8f1d --- /dev/null +++ b/postcss.config.cjs @@ -0,0 +1,5 @@ +module.exports = { + plugins: { + "@pandacss/dev/postcss": {}, + }, +}; diff --git a/src/renderer/index.html b/src/renderer/index.html index 4cf464d1..93cd96fa 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -13,6 +13,9 @@ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ --> + + + AymurAI diff --git a/src/renderer/src/index.css b/src/renderer/src/index.css new file mode 100644 index 00000000..e27a23b7 --- /dev/null +++ b/src/renderer/src/index.css @@ -0,0 +1 @@ +@layer reset, base, tokens, recipes, utilities; diff --git a/src/renderer/src/main.tsx b/src/renderer/src/main.tsx index e6a927b3..c1a50bac 100644 --- a/src/renderer/src/main.tsx +++ b/src/renderer/src/main.tsx @@ -1,6 +1,7 @@ import React from "react"; import ReactDOM from "react-dom/client"; +import "./index.css"; import App from "./app"; ReactDOM.createRoot(document.getElementById("root")!).render( diff --git a/tsconfig.web.json b/tsconfig.web.json index 955f7a75..4a1a9b0a 100644 --- a/tsconfig.web.json +++ b/tsconfig.web.json @@ -15,6 +15,7 @@ "src/renderer/src/env.d.ts", "src/renderer/src/**/*", "src/renderer/src/**/*.tsx", - "src/preload/*.d.ts" + "src/preload/*.d.ts", + "src/renderer/src/styled/**/*" ] } From 67603f66fc086b40d3280092af8e9490ddc8640f Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 2 Feb 2026 04:01:06 -0300 Subject: [PATCH 022/263] chore: flag stitches as deprecated --- src/renderer/src/styles/globalStyles.ts | 1 + src/renderer/src/styles/index.ts | 2 ++ src/renderer/src/styles/stitches.config.ts | 3 +++ 3 files changed, 6 insertions(+) diff --git a/src/renderer/src/styles/globalStyles.ts b/src/renderer/src/styles/globalStyles.ts index 69d711ef..653b594b 100644 --- a/src/renderer/src/styles/globalStyles.ts +++ b/src/renderer/src/styles/globalStyles.ts @@ -1,5 +1,6 @@ import { globalCss } from "./stitches.config"; +/** @deprecated Global styles have been migrated to Panda CSS in `panda.config.ts`. */ export const globalStyles = globalCss({ "@import": 'url("https://fonts.googleapis.com/css2?family=Archivo:wght@400;600;800&display=swap")', diff --git a/src/renderer/src/styles/index.ts b/src/renderer/src/styles/index.ts index a8d51685..91fd335d 100644 --- a/src/renderer/src/styles/index.ts +++ b/src/renderer/src/styles/index.ts @@ -1,2 +1,4 @@ +/** @deprecated Use Panda CSS instead. Import from `@/styled/css` or `@/styled/jsx`. */ export * from "./stitches.config"; +/** @deprecated Global styles have been migrated to Panda CSS in `panda.config.ts`. */ export * from "./globalStyles"; diff --git a/src/renderer/src/styles/stitches.config.ts b/src/renderer/src/styles/stitches.config.ts index 73ae4fd4..c4f34ce7 100644 --- a/src/renderer/src/styles/stitches.config.ts +++ b/src/renderer/src/styles/stitches.config.ts @@ -2,6 +2,7 @@ import { type CSS as CSSProp, createStitches } from "@stitches/react"; import * as tokens from "./tokens"; +/** @deprecated Use Panda CSS instead. Import from `@/styled/css` or `@/styled/jsx`. */ export const defaultTheme = createStitches({ theme: { colors: { @@ -115,7 +116,9 @@ export const defaultTheme = createStitches({ }, }); +/** @deprecated Use Panda CSS instead. Import from `@/styled/css` or `@/styled/jsx`. */ export type CSS = CSSProp; +/** @deprecated Use `styled` from `@/styled/jsx`. */ export const { styled, globalCss, createTheme, theme, keyframes } = defaultTheme; From ebcf3a66f161e7032b45ecd64b879e00427b2465 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 2 Feb 2026 04:02:32 -0300 Subject: [PATCH 023/263] feat: add loading page and updated branding images --- .../public/brand/aymurai-vert-darkpurple.png | Bin 0 -> 48200 bytes ...murai-vert.png => aymurai-vert-purple.png} | Bin src/renderer/public/brand/data-genero.png | Bin 4153 -> 0 bytes src/renderer/public/brand/datagenero.svg | 15 +++++++++ src/renderer/public/brand/iso-white.png | Bin 0 -> 38733 bytes src/renderer/src/layout/loading.tsx | 31 ++++++++++++++++++ 6 files changed, 46 insertions(+) create mode 100644 src/renderer/public/brand/aymurai-vert-darkpurple.png rename src/renderer/public/brand/{aymurai-vert.png => aymurai-vert-purple.png} (100%) delete mode 100644 src/renderer/public/brand/data-genero.png create mode 100644 src/renderer/public/brand/datagenero.svg create mode 100644 src/renderer/public/brand/iso-white.png create mode 100644 src/renderer/src/layout/loading.tsx diff --git a/src/renderer/public/brand/aymurai-vert-darkpurple.png b/src/renderer/public/brand/aymurai-vert-darkpurple.png new file mode 100644 index 0000000000000000000000000000000000000000..e043f5276712a253970f14d2efc8c0be5e982050 GIT binary patch literal 48200 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

5SAH0eBg(dX|Ui;>wMnOc-^?Yw+e*la{I)D`t#j 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 O13)5-;Eh_2G5-M%v)!)% diff --git a/src/renderer/public/brand/datagenero.svg b/src/renderer/public/brand/datagenero.svg new file mode 100644 index 00000000..a07225aa --- /dev/null +++ b/src/renderer/public/brand/datagenero.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/renderer/public/brand/iso-white.png b/src/renderer/public/brand/iso-white.png new file mode 100644 index 0000000000000000000000000000000000000000..5c1359f1015afb3847eeb63a95debf848cbaaf82 GIT binary patch literal 38733 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 I&Fbv`1A798J^%m! literal 0 HcmV?d00001 diff --git a/src/renderer/src/layout/loading.tsx b/src/renderer/src/layout/loading.tsx new file mode 100644 index 00000000..566422be --- /dev/null +++ b/src/renderer/src/layout/loading.tsx @@ -0,0 +1,31 @@ +import { css } from "@/styled/css"; +import { stack } from "@/styled/patterns"; + +const background = css( + stack.raw({ + align: "center", + justify: "center", + }), + { + width: "screen", + height: "screen", + + bgGradient: "primary", + }, +); +const image = css({ + animation: "pulse", +}); + +export default function Loading() { + return ( +

+ AymurAI iso white +
+ ); +} From 60cf7fdee3d1c63bc51c5728f243b47f16208256 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 2 Feb 2026 04:02:48 -0300 Subject: [PATCH 024/263] chore: configure view transition for all pages --- src/renderer/src/app.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/renderer/src/app.tsx b/src/renderer/src/app.tsx index 5d088bad..a1695e2e 100644 --- a/src/renderer/src/app.tsx +++ b/src/renderer/src/app.tsx @@ -14,12 +14,13 @@ const TanStackQueryProviderContext = TanstackReactQuery.getContext(); // Create a new router instance const memoryHistory = createMemoryHistory({ - initialEntries: ["/home/host"], // Pass your initial url + initialEntries: ["/"], // Pass your initial url }); const router = createRouter({ routeTree, history: memoryHistory, context: { ...TanStackQueryProviderContext }, + defaultViewTransition: true, }); declare module "@tanstack/react-router" { From 51fe0990982f99404f1cae6f5b87d9bafb3232d1 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 2 Feb 2026 04:03:08 -0300 Subject: [PATCH 025/263] feat: add loading screen on boot, timer of 1.5s --- src/renderer/src/routes/index.tsx | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/routes/index.tsx b/src/renderer/src/routes/index.tsx index c762a8f9..bfcfef2c 100644 --- a/src/renderer/src/routes/index.tsx +++ b/src/renderer/src/routes/index.tsx @@ -1,9 +1,22 @@ -import { Navigate, createFileRoute } from "@tanstack/react-router"; +import Loading from "@/layout/loading"; +import { createFileRoute, useNavigate } from "@tanstack/react-router"; +import { useEffect } from "react"; export const Route = createFileRoute("/")({ component: RouteComponent, }); +const TIMING = 2000; function RouteComponent() { - return ; + const navigate = useNavigate(); + + useEffect(() => { + const timer = setTimeout(() => { + navigate({ to: "/home" }); + }, TIMING); + + return () => clearTimeout(timer); + }, [navigate]); + + return ; } From 64048ac70042698b4bb47a2503748c678eaf9787 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 2 Feb 2026 19:41:54 -0300 Subject: [PATCH 026/263] chore: re-implement button and partially input --- src/renderer/src/components/button.tsx | 137 +++++++++++++ src/renderer/src/components/button/index.tsx | 147 -------------- src/renderer/src/components/index.ts | 2 +- src/renderer/src/components/input.tsx | 191 ++++++++++++++++++ .../UncontrolledInput.styles.ts} | 0 .../{input => uncontrolled-input}/index.tsx | 4 +- 6 files changed, 331 insertions(+), 150 deletions(-) create mode 100644 src/renderer/src/components/button.tsx delete mode 100644 src/renderer/src/components/button/index.tsx create mode 100644 src/renderer/src/components/input.tsx rename src/renderer/src/components/{input/Input.styles.ts => uncontrolled-input/UncontrolledInput.styles.ts} (100%) rename src/renderer/src/components/{input => uncontrolled-input}/index.tsx (96%) diff --git a/src/renderer/src/components/button.tsx b/src/renderer/src/components/button.tsx new file mode 100644 index 00000000..e10020c5 --- /dev/null +++ b/src/renderer/src/components/button.tsx @@ -0,0 +1,137 @@ +import { type RecipeVariantProps, css, cva } from "@/styled/css"; +import { CircleNotch } from "phosphor-react"; +import type { ButtonHTMLAttributes } from "react"; + +const button = cva({ + base: { + display: "flex", + flexDir: "row", + gap: "1", // 4px + justifyContent: "center", + alignSelf: "stretch", + alignItems: "center", + + transitionProperty: "[background-color, color, box-shadow]", + transitionDuration: "slow", // 300ms + transitionTimingFunction: "default", + + rounded: "sm", // 4px + border: "none", + + textStyle: "cta.md.strong", + + cursor: "pointer", + + "&:disabled": { + cursor: "not-allowed", + }, + }, + variants: { + variant: { + primary: { + bg: "action.default", + color: "text.onbutton-default", + + "&:hover:enabled": { + bg: "action.hover", + color: "text.onbutton-alternative", + }, + + "&:active:enabled": { + bg: "action.pressed", + color: "text.onbutton-alternative", + }, + + "&:focus:enabled": { + bg: "action.focus", + outline: "primary-alt", + outlineWidth: "[2px]", + boxShadow: "[0px 0px 10px rgba(17, 0, 65, 0.2)]", + }, + + "&:disabled": { + bg: "action.disabled", + color: "text.onbutton-default", + }, + }, + secondary: { + color: "text.onbutton-default", + bg: "bg.secondary", + + borderWidth: "[2px]", + borderStyle: "solid", + borderColor: "action.alt-default", + + "&:hover:enabled": { + color: "text.onbutton-default", + bg: "bg.secondary", + borderColor: "action.hover", + }, + + "&:active:enabled": { + color: "text.onbutton-alternative", + bg: "action.pressed", + borderColor: "action.pressed", + }, + + "&:focus:enabled": { + boxShadow: "[0px 0px 10px rgba(17, 0, 65, 0.2)]", + outline: "primary-alt", + outlineWidth: "[2px]", + bg: "bg.secondary", + }, + + "&:disabled": { + color: "text.onbutton-disabled", + bg: "bg.secondary", + borderColor: "action.disabled", + }, + }, + tertiary: { + // TODO: not implemented + }, + }, + size: { + md: { padding: "4" }, + sm: { py: "2", px: "4" }, + }, + }, + defaultVariants: { + size: "md", + variant: "primary", + }, +}); + +type ButtonProps = RecipeVariantProps & + ButtonHTMLAttributes & { + isLoading?: boolean; + }; + +function Button({ + size, + variant, + isLoading, + disabled, + children, + ...props +}: ButtonProps) { + return ( + + ); +} + +export default Button; diff --git a/src/renderer/src/components/button/index.tsx b/src/renderer/src/components/button/index.tsx deleted file mode 100644 index 8b762123..00000000 --- a/src/renderer/src/components/button/index.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import { keyframes, styled } from "@/styles"; -import { CircleNotch } from "phosphor-react"; - -const StyledButton = styled("button", { - display: "flex", - flexDirection: "row", - gap: "$xxs", - justifyContent: "center", - alignSelf: "stretch", - alignItems: "center", - - transitionProperty: "background-color, color, box-shadow", - transitionDuration: "0.3s", - transitionTimingFunction: "ease", - - borderRadius: "$xs", - b: "none", - - fontWeight: 600, - fontSize: "$ctaMd", - lineHeight: "$ctaMd", - - cursor: "pointer", - "&:disabled": { - cursor: "not-allowed", - }, - - variants: { - variant: { - primary: { - color: "$textOnButtonDefault", - bg: "$actionDefault", - - "&:hover": { - color: "$textOnButtonAlternative", - bg: "$actionHover", - }, - - "&:active": { - color: "$textOnButtonAlternative", - bg: "$actionPressed", - }, - - "&:focus": { - boxShadow: "0px 0px 10px rgba(17, 0, 65, 0.2)", - outline: "2px solid $borderPrimaryAlt", - }, - - "&:disabled": { - color: "$textOnButtonDefault", - bg: "$actionDisabled", - }, - }, - secondary: { - color: "$textOnButtonDefault", - bg: "$bgSecondary", - - borderWidth: "$sizes$xxs", - borderStyle: "solid", - borderColor: "$actionDefaultAlt", - - "&:hover": { - color: "$textOnButtonDefault", - bg: "$white", - borderColor: "$actionHover", - }, - - "&:active": { - color: "$textOnButtonAlternative", - bg: "$actionPressed", - borderColor: "$actionPressed", - }, - - "&:focus": { - boxShadow: "0px 0px 10px rgba(17, 0, 65, 0.2)", - outline: "2px solid $borderPrimaryAlt", - bg: "$bgSecondary", - }, - - "&:disabled": { - color: "$textOnButtonDisabled", - bg: "$bgSecondary", - borderColor: "$actionDisabled", - }, - }, - tertiary: { - color: "$textOnButtonDefault", - bg: "$white", - - // Doesnt have a :hover state - - "&:active": { - color: "$actionPressed", - }, - - "&:focus": { - outline: "2px solid $primaryAlt", - }, - - // Doesnt have a :disabled state - }, - none: { - p: 0, - bg: "inherit", - }, - }, - size: { - s: { p: "$s $m" }, - m: { p: "$m" }, - l: { py: "$m", width: 300 }, - }, - checked: { - true: { - bg: "$actionPressed", - color: "$textOnButtonAlternative", - }, - false: {}, - }, - }, - defaultVariants: { - size: "m", - variant: "primary", - checked: false, - }, -}); - -const spin = keyframes({ - "0%": { transform: "rotate(0deg)" }, - "100%": { transform: "rotate(360deg)" }, -}); -const Spinner = styled(CircleNotch, { - animation: `${spin} 1s linear infinite`, -}); - -interface Props extends React.ComponentProps { - isLoading?: boolean; -} - -function Button({ children, isLoading, disabled, ...props }: Props) { - return ( - - {isLoading ? : children} - - ); -} - -export default Button; diff --git a/src/renderer/src/components/index.ts b/src/renderer/src/components/index.ts index 0eb80d4a..440965de 100644 --- a/src/renderer/src/components/index.ts +++ b/src/renderer/src/components/index.ts @@ -12,7 +12,6 @@ export { FinishAnonymizer } from "./finish-anonymizer"; export { FinishDataset } from "./finish-dataset"; export { default as Grid } from "./grid"; export { default as HiddenInput } from "./hidden-input"; -export { default as Input } from "./input"; export { default as Label } from "./label"; export { OnboardingCard } from "./onboarding-card"; export { OnboardingGrid } from "./onboarding-grid"; @@ -31,5 +30,6 @@ export { default as ThemeProvider } from "./theme-provider"; export { default as Title } from "./title"; export { default as Toast } from "./toast"; export { default as Tooltip } from "./tooltip"; +export { default as Input } from "./uncontrolled-input"; export { ValidateDataset } from "./validate-dataset"; export { default as ValidationForm } from "./validation-form"; diff --git a/src/renderer/src/components/input.tsx b/src/renderer/src/components/input.tsx new file mode 100644 index 00000000..4eecdc3f --- /dev/null +++ b/src/renderer/src/components/input.tsx @@ -0,0 +1,191 @@ +import { useId } from "react"; + +import { cva, sva } from "@/styled/css"; +import { hstack, stack } from "@/styled/patterns"; +import { WarningCircle } from "phosphor-react"; + +const input = sva({ + slots: ["container", "inputBox", "input", "label", "errorMessage", "helper"], + base: { + container: stack.raw({ gap: "1", width: "full" }), + inputBox: { + ...hstack.raw({ alignItems: "center", gap: "1" }), + + rounded: "sm", + border: "primary", + + "&:focus-within": { + outline: "none", + boxShadow: "[0px 2px 2px rgba(0, 0, 0, 0.16)]", + }, + }, + input: { + textStyle: "label.md.default", + border: "none", + outline: "none", + flex: "[1]", + + p: "3", + + "&::placeholder": { + color: "text.lighter", + }, + }, + label: { textStyle: "label.sm.default" }, + errorMessage: { + ...hstack.raw({ gap: "1" }), + textStyle: "label.sm.default", + color: "system.error", + }, + helper: { + textStyle: "label.sm.default", + color: "text.lighter", + }, + }, + variants: { + disabled: { + true: { + inputBox: { + bg: "bg.primary", + border: "primary", + color: "text.lighter", + cursor: "not-allowed", + }, + input: { + cursor: "not-allowed", + }, + }, + false: { + inputBox: { + bg: "white", + }, + }, + }, + error: { + true: { + container: { + color: "system.error", + }, + inputBox: { + border: "error", + }, + input: { + // "&::placeholder": { + // color: "system.error-secondary", + // }, + }, + label: { color: "system.error" }, + }, + false: {}, + }, + }, + defaultVariants: { + error: false, + disabled: false, + }, +}); + +const affix = cva({ + base: { + ...hstack.raw({ alignItems: "center", gap: "1" }), + userSelect: "none", + textStyle: "label.md.default", + // py: "3", + }, + variants: { + position: { + prefix: { pl: "3", mr: "-3" }, + suffix: { pr: "3", ml: "-3" }, + }, + }, +}); + +interface InputProps { + // Rendering + label?: string; + placeholder?: string; + prefix?: string; + suffix?: string; + suggestion?: string; + helper?: string; + // Control + id?: string; + value: string; + onChange?: React.ChangeEventHandler; + disabled?: boolean; + error?: string | null; + type?: "text" | "number"; +} +export default function Input({ + // Rendering + label, + placeholder, + prefix, + suffix, + suggestion, + helper, + // Control + id, + value, + onChange, + disabled = false, + error, + type, +}: InputProps) { + const randomId = useId(); + const inputId = id ?? randomId; + const errorMessageId = `${inputId}-error`; + + const classes = input({ disabled, error: !!error }); + + return ( +
+ {label && ( + + )} + +
+ {prefix && ( +
+ {prefix} + {/* In the designs this vertical bar is defined as a Text, but it's + not. Use a Label instead */} + | +
+ )} + + + + {suffix && ( +
+ {/* In the designs this vertical bar is defined as a Text, but it's + not. Use a Label instead */} + | + {suffix} +
+ )} +
+ + {helper && !error &&

{helper}

} + {error && ( + + )} +
+ ); +} diff --git a/src/renderer/src/components/input/Input.styles.ts b/src/renderer/src/components/uncontrolled-input/UncontrolledInput.styles.ts similarity index 100% rename from src/renderer/src/components/input/Input.styles.ts rename to src/renderer/src/components/uncontrolled-input/UncontrolledInput.styles.ts diff --git a/src/renderer/src/components/input/index.tsx b/src/renderer/src/components/uncontrolled-input/index.tsx similarity index 96% rename from src/renderer/src/components/input/index.tsx rename to src/renderer/src/components/uncontrolled-input/index.tsx index 8b43b2bc..d48966ef 100644 --- a/src/renderer/src/components/input/index.tsx +++ b/src/renderer/src/components/uncontrolled-input/index.tsx @@ -14,7 +14,7 @@ import { Container, InputContainer, Input as StyledInput, -} from "./Input.styles"; +} from "./UncontrolledInput.styles"; export type InputRefValue = { value: string }; interface Props @@ -30,7 +30,7 @@ interface Props css?: CSS; specialCharacters?: string; } -export default forwardRef<{ value: string }, Props>(function Input( +export default forwardRef<{ value: string }, Props>(function UncontrolledInput( { label, helper, From 2393d18e035bd267901fce24ff1081fea92e894b Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 2 Feb 2026 19:45:45 -0300 Subject: [PATCH 027/263] chore: fix some tokens in panda and move stitches global styles --- panda.config.ts | 15 +++++++-------- src/renderer/src/components/label/index.ts | 3 +++ src/renderer/src/components/stack/index.ts | 3 +++ src/renderer/src/components/subtitle/index.ts | 3 +++ .../src/components/theme-provider/index.tsx | 4 +--- src/renderer/src/services/utils.ts | 2 ++ 6 files changed, 19 insertions(+), 11 deletions(-) diff --git a/panda.config.ts b/panda.config.ts index d29cae4b..3cea4cca 100644 --- a/panda.config.ts +++ b/panda.config.ts @@ -3,12 +3,12 @@ import { defineConfig, defineGlobalStyles } from "@pandacss/dev"; const globalCss = defineGlobalStyles({ "*": { fontFamily: - '"Archivo", -apple-system, Helvetica Neue, Helvetica, Roboto, sans-serif', // TODO: Replace token here (was $primary) + '"Archivo", -apple-system, Helvetica Neue, Helvetica, Roboto, sans-serif', // TODO: Replace token here (was $primary) }, - - 'html': { + + html: { color: "#110041", -}, + }, "mark.predicted-word": { backgroundColor: "#E6E8FF", // TODO: Replace token here (was $primaryAlt) @@ -165,8 +165,7 @@ export default defineConfig({ lighter: color("#625C68"), "onbutton-default": color("#110041"), "onbutton-alternative": color("#FFFFFF"), - // TODO: needs to be corrected in the figma file - "onbutton-disabled": color("#FF0000"), + "onbutton-disabled": color("#2D3748"), }, action: { default: color("#C5CAFF"), @@ -182,7 +181,6 @@ export default defineConfig({ "primary-alternative": color("#E5E8FF"), "primary-highlight": color("#C5CAFF"), "secondary-highlight": color("#E0DDE2"), - // gradient: '' }, system: { success: color("#1B834E"), @@ -197,8 +195,9 @@ export default defineConfig({ }, borders: { primary: { value: "1px solid #BCBAB8" }, - secondary: { value: "1px solid #9F99A5" }, + secondary: { value: "1px solid #EDF2F7" }, "primary-alt": { value: "1px solid #110041" }, + error: { value: "1px solid {colors.system.error}" }, }, gradients: { primary: { diff --git a/src/renderer/src/components/label/index.ts b/src/renderer/src/components/label/index.ts index a01556af..08531a91 100644 --- a/src/renderer/src/components/label/index.ts +++ b/src/renderer/src/components/label/index.ts @@ -1,5 +1,8 @@ import { styled } from "@/styles"; +/** + * @deprecated use `textStyles` from PandaCSS instead. + */ const Label = styled("label", { variants: { size: { diff --git a/src/renderer/src/components/stack/index.ts b/src/renderer/src/components/stack/index.ts index aae6c732..d6fae295 100644 --- a/src/renderer/src/components/stack/index.ts +++ b/src/renderer/src/components/stack/index.ts @@ -1,5 +1,8 @@ import { styled } from "@/styles"; +/** + * @deprecated Use `Stack` from `@/styled/jsx` instead. + */ const Stack = styled("div", { display: "flex", diff --git a/src/renderer/src/components/subtitle/index.ts b/src/renderer/src/components/subtitle/index.ts index 2bc6572a..acdf6e5e 100644 --- a/src/renderer/src/components/subtitle/index.ts +++ b/src/renderer/src/components/subtitle/index.ts @@ -1,5 +1,8 @@ import { styled } from "@/styles"; +/** + * @deprecated Use `textStyle` from PandaCSS instead. + */ const Subtitle = styled("p", { variants: { size: { diff --git a/src/renderer/src/components/theme-provider/index.tsx b/src/renderer/src/components/theme-provider/index.tsx index f9ed65c6..50b30fb2 100644 --- a/src/renderer/src/components/theme-provider/index.tsx +++ b/src/renderer/src/components/theme-provider/index.tsx @@ -1,8 +1,6 @@ -import { globalStyles } from "@/styles"; - import type { Props } from "./ThemeProvider.types"; export default function ThemeProvider({ children }: Props) { - globalStyles(); + // globalStyles(); return
{children}
; } diff --git a/src/renderer/src/services/utils.ts b/src/renderer/src/services/utils.ts index 85de4e09..1d57c23e 100644 --- a/src/renderer/src/services/utils.ts +++ b/src/renderer/src/services/utils.ts @@ -102,6 +102,8 @@ interface SchemedMutationArgs< * mutationFn: (userData) => createUser(userData), * }); * ``` + * + * @deprecated Deprecated in favor of using regular `useMutation` with zod parsing inside */ export const useSchemedMutation = < TSchema extends z.ZodTypeAny, From 3a289e1e6d2091beeb1dbb4d1395cf9c3361090d Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 2 Feb 2026 19:46:01 -0300 Subject: [PATCH 028/263] chore: add changes to router file --- src/renderer/src/routeTree.gen.ts | 170 ++++++++++-------------------- 1 file changed, 57 insertions(+), 113 deletions(-) diff --git a/src/renderer/src/routeTree.gen.ts b/src/renderer/src/routeTree.gen.ts index ceb86f2b..79eccbda 100644 --- a/src/renderer/src/routeTree.gen.ts +++ b/src/renderer/src/routeTree.gen.ts @@ -8,63 +8,49 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. -import { createFileRoute } from '@tanstack/react-router' - import { Route as rootRouteImport } from './routes/__root' import { Route as IndexRouteImport } from './routes/index' -import { Route as HomeLayoutRouteRouteImport } from './routes/home._layout/route' +import { Route as HomeIndexRouteImport } from './routes/home/index' +import { Route as HomeHostRouteImport } from './routes/home/host' +import { Route as HomeFeaturesRouteImport } from './routes/home/features' import { Route as AppFeatureRouteRouteImport } from './routes/app.$feature/route' -import { Route as HomeLayoutIndexRouteImport } from './routes/home._layout/index' import { Route as AppFeatureIndexRouteImport } from './routes/app.$feature/index' -import { Route as HomeLayoutHostRouteImport } from './routes/home._layout/host' -import { Route as HomeLayoutFeaturesRouteImport } from './routes/home._layout/features' import { Route as AppFeatureValidationRouteImport } from './routes/app.$feature/validation' import { Route as AppFeatureProcessRouteImport } from './routes/app.$feature/process' import { Route as AppFeaturePreviewRouteImport } from './routes/app.$feature/preview' import { Route as AppFeatureOnboardingRouteImport } from './routes/app.$feature/onboarding' import { Route as AppFeatureFinishRouteImport } from './routes/app.$feature/finish' -const HomeRouteImport = createFileRoute('/home')() - -const HomeRoute = HomeRouteImport.update({ - id: '/home', - path: '/home', - getParentRoute: () => rootRouteImport, -} as any) const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRouteImport, } as any) -const HomeLayoutRouteRoute = HomeLayoutRouteRouteImport.update({ - id: '/_layout', - getParentRoute: () => HomeRoute, +const HomeIndexRoute = HomeIndexRouteImport.update({ + id: '/home/', + path: '/home/', + getParentRoute: () => rootRouteImport, +} as any) +const HomeHostRoute = HomeHostRouteImport.update({ + id: '/home/host', + path: '/home/host', + getParentRoute: () => rootRouteImport, +} as any) +const HomeFeaturesRoute = HomeFeaturesRouteImport.update({ + id: '/home/features', + path: '/home/features', + getParentRoute: () => rootRouteImport, } as any) const AppFeatureRouteRoute = AppFeatureRouteRouteImport.update({ id: '/app/$feature', path: '/app/$feature', getParentRoute: () => rootRouteImport, } as any) -const HomeLayoutIndexRoute = HomeLayoutIndexRouteImport.update({ - id: '/', - path: '/', - getParentRoute: () => HomeLayoutRouteRoute, -} as any) const AppFeatureIndexRoute = AppFeatureIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => AppFeatureRouteRoute, } as any) -const HomeLayoutHostRoute = HomeLayoutHostRouteImport.update({ - id: '/host', - path: '/host', - getParentRoute: () => HomeLayoutRouteRoute, -} as any) -const HomeLayoutFeaturesRoute = HomeLayoutFeaturesRouteImport.update({ - id: '/features', - path: '/features', - getParentRoute: () => HomeLayoutRouteRoute, -} as any) const AppFeatureValidationRoute = AppFeatureValidationRouteImport.update({ id: '/validation', path: '/validation', @@ -94,104 +80,93 @@ const AppFeatureFinishRoute = AppFeatureFinishRouteImport.update({ export interface FileRoutesByFullPath { '/': typeof IndexRoute '/app/$feature': typeof AppFeatureRouteRouteWithChildren - '/home': typeof HomeLayoutRouteRouteWithChildren + '/home/features': typeof HomeFeaturesRoute + '/home/host': typeof HomeHostRoute + '/home': typeof HomeIndexRoute '/app/$feature/finish': typeof AppFeatureFinishRoute '/app/$feature/onboarding': typeof AppFeatureOnboardingRoute '/app/$feature/preview': typeof AppFeaturePreviewRoute '/app/$feature/process': typeof AppFeatureProcessRoute '/app/$feature/validation': typeof AppFeatureValidationRoute - '/home/features': typeof HomeLayoutFeaturesRoute - '/home/host': typeof HomeLayoutHostRoute '/app/$feature/': typeof AppFeatureIndexRoute - '/home/': typeof HomeLayoutIndexRoute } export interface FileRoutesByTo { '/': typeof IndexRoute - '/home': typeof HomeLayoutIndexRoute + '/home/features': typeof HomeFeaturesRoute + '/home/host': typeof HomeHostRoute + '/home': typeof HomeIndexRoute '/app/$feature/finish': typeof AppFeatureFinishRoute '/app/$feature/onboarding': typeof AppFeatureOnboardingRoute '/app/$feature/preview': typeof AppFeaturePreviewRoute '/app/$feature/process': typeof AppFeatureProcessRoute '/app/$feature/validation': typeof AppFeatureValidationRoute - '/home/features': typeof HomeLayoutFeaturesRoute - '/home/host': typeof HomeLayoutHostRoute '/app/$feature': typeof AppFeatureIndexRoute } export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute '/app/$feature': typeof AppFeatureRouteRouteWithChildren - '/home': typeof HomeRouteWithChildren - '/home/_layout': typeof HomeLayoutRouteRouteWithChildren + '/home/features': typeof HomeFeaturesRoute + '/home/host': typeof HomeHostRoute + '/home/': typeof HomeIndexRoute '/app/$feature/finish': typeof AppFeatureFinishRoute '/app/$feature/onboarding': typeof AppFeatureOnboardingRoute '/app/$feature/preview': typeof AppFeaturePreviewRoute '/app/$feature/process': typeof AppFeatureProcessRoute '/app/$feature/validation': typeof AppFeatureValidationRoute - '/home/_layout/features': typeof HomeLayoutFeaturesRoute - '/home/_layout/host': typeof HomeLayoutHostRoute '/app/$feature/': typeof AppFeatureIndexRoute - '/home/_layout/': typeof HomeLayoutIndexRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath fullPaths: | '/' | '/app/$feature' + | '/home/features' + | '/home/host' | '/home' | '/app/$feature/finish' | '/app/$feature/onboarding' | '/app/$feature/preview' | '/app/$feature/process' | '/app/$feature/validation' - | '/home/features' - | '/home/host' | '/app/$feature/' - | '/home/' fileRoutesByTo: FileRoutesByTo to: | '/' + | '/home/features' + | '/home/host' | '/home' | '/app/$feature/finish' | '/app/$feature/onboarding' | '/app/$feature/preview' | '/app/$feature/process' | '/app/$feature/validation' - | '/home/features' - | '/home/host' | '/app/$feature' id: | '__root__' | '/' | '/app/$feature' - | '/home' - | '/home/_layout' + | '/home/features' + | '/home/host' + | '/home/' | '/app/$feature/finish' | '/app/$feature/onboarding' | '/app/$feature/preview' | '/app/$feature/process' | '/app/$feature/validation' - | '/home/_layout/features' - | '/home/_layout/host' | '/app/$feature/' - | '/home/_layout/' fileRoutesById: FileRoutesById } export interface RootRouteChildren { IndexRoute: typeof IndexRoute AppFeatureRouteRoute: typeof AppFeatureRouteRouteWithChildren - HomeRoute: typeof HomeRouteWithChildren + HomeFeaturesRoute: typeof HomeFeaturesRoute + HomeHostRoute: typeof HomeHostRoute + HomeIndexRoute: typeof HomeIndexRoute } declare module '@tanstack/react-router' { interface FileRoutesByPath { - '/home': { - id: '/home' - path: '/home' - fullPath: '/home' - preLoaderRoute: typeof HomeRouteImport - parentRoute: typeof rootRouteImport - } '/': { id: '/' path: '/' @@ -199,12 +174,26 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRouteImport } - '/home/_layout': { - id: '/home/_layout' + '/home/': { + id: '/home/' path: '/home' fullPath: '/home' - preLoaderRoute: typeof HomeLayoutRouteRouteImport - parentRoute: typeof HomeRoute + preLoaderRoute: typeof HomeIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/home/host': { + id: '/home/host' + path: '/home/host' + fullPath: '/home/host' + preLoaderRoute: typeof HomeHostRouteImport + parentRoute: typeof rootRouteImport + } + '/home/features': { + id: '/home/features' + path: '/home/features' + fullPath: '/home/features' + preLoaderRoute: typeof HomeFeaturesRouteImport + parentRoute: typeof rootRouteImport } '/app/$feature': { id: '/app/$feature' @@ -213,13 +202,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AppFeatureRouteRouteImport parentRoute: typeof rootRouteImport } - '/home/_layout/': { - id: '/home/_layout/' - path: '/' - fullPath: '/home/' - preLoaderRoute: typeof HomeLayoutIndexRouteImport - parentRoute: typeof HomeLayoutRouteRoute - } '/app/$feature/': { id: '/app/$feature/' path: '/' @@ -227,20 +209,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AppFeatureIndexRouteImport parentRoute: typeof AppFeatureRouteRoute } - '/home/_layout/host': { - id: '/home/_layout/host' - path: '/host' - fullPath: '/home/host' - preLoaderRoute: typeof HomeLayoutHostRouteImport - parentRoute: typeof HomeLayoutRouteRoute - } - '/home/_layout/features': { - id: '/home/_layout/features' - path: '/features' - fullPath: '/home/features' - preLoaderRoute: typeof HomeLayoutFeaturesRouteImport - parentRoute: typeof HomeLayoutRouteRoute - } '/app/$feature/validation': { id: '/app/$feature/validation' path: '/validation' @@ -301,36 +269,12 @@ const AppFeatureRouteRouteWithChildren = AppFeatureRouteRoute._addFileChildren( AppFeatureRouteRouteChildren, ) -interface HomeLayoutRouteRouteChildren { - HomeLayoutFeaturesRoute: typeof HomeLayoutFeaturesRoute - HomeLayoutHostRoute: typeof HomeLayoutHostRoute - HomeLayoutIndexRoute: typeof HomeLayoutIndexRoute -} - -const HomeLayoutRouteRouteChildren: HomeLayoutRouteRouteChildren = { - HomeLayoutFeaturesRoute: HomeLayoutFeaturesRoute, - HomeLayoutHostRoute: HomeLayoutHostRoute, - HomeLayoutIndexRoute: HomeLayoutIndexRoute, -} - -const HomeLayoutRouteRouteWithChildren = HomeLayoutRouteRoute._addFileChildren( - HomeLayoutRouteRouteChildren, -) - -interface HomeRouteChildren { - HomeLayoutRouteRoute: typeof HomeLayoutRouteRouteWithChildren -} - -const HomeRouteChildren: HomeRouteChildren = { - HomeLayoutRouteRoute: HomeLayoutRouteRouteWithChildren, -} - -const HomeRouteWithChildren = HomeRoute._addFileChildren(HomeRouteChildren) - const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, AppFeatureRouteRoute: AppFeatureRouteRouteWithChildren, - HomeRoute: HomeRouteWithChildren, + HomeFeaturesRoute: HomeFeaturesRoute, + HomeHostRoute: HomeHostRoute, + HomeIndexRoute: HomeIndexRoute, } export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) From 59363cd78ac93d41a68f5e4e57659b5ddb3dc8be Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 2 Feb 2026 19:46:30 -0300 Subject: [PATCH 029/263] chore: change to named export on local store --- src/renderer/src/store/useLocal.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/renderer/src/store/useLocal.ts b/src/renderer/src/store/useLocal.ts index 95deec71..87f72711 100644 --- a/src/renderer/src/store/useLocal.ts +++ b/src/renderer/src/store/useLocal.ts @@ -22,8 +22,8 @@ const useLocalStore = create()( ), ); -const useServerHost = () => useLocalStore((state) => state.serverHost); -const useServerHostActions = () => { +export const useServerHost = () => useLocalStore((state) => state.serverHost); +export const useServerHostActions = () => { const setServerHost = useLocalStore((state) => state.setServerHost); const clearServerHost = useLocalStore((state) => state.clearServerHost); @@ -32,8 +32,3 @@ const useServerHostActions = () => { clearServerHost, }; }; - -export const localStore = { - useServerHost, - useServerHostActions, -}; From 047b115a20ad87d125113343eea7e13518260e60 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 2 Feb 2026 19:46:45 -0300 Subject: [PATCH 030/263] chore: replace custom use mutation hook with base on connect to host hook --- .../src/services/aymurai/useConnectToHost.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/renderer/src/services/aymurai/useConnectToHost.ts b/src/renderer/src/services/aymurai/useConnectToHost.ts index 8855e71b..e0645f19 100644 --- a/src/renderer/src/services/aymurai/useConnectToHost.ts +++ b/src/renderer/src/services/aymurai/useConnectToHost.ts @@ -1,18 +1,20 @@ import api from "@/services/api"; import z from "zod"; -import { useSchemedMutation } from "../utils"; + +import { useMutation } from "@tanstack/react-query"; export const useConnectToHost = () => { - return useSchemedMutation({ + return useMutation({ mutationKey: ["healthcheck"], - mutationFn: (host: string) => { + mutationFn: async (host: string) => { const url = new URL(host).toString().replace(/\/$/, ""); - return api.get(`${url}/server/healthcheck`).then((r) => r.data); + const response = await api + .get(`${url}/server/healthcheck`) + .then((r) => r.data); + + return z.object({ status: z.string() }).parse(response); }, - schema: z.object({ - status: z.string(), - }), onSuccess: (_data, host) => { api.defaults.baseURL = host; }, From ab0a4e20738ba0e18afe2bf6982eaeee8cc837f7 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Thu, 5 Feb 2026 22:47:52 -0300 Subject: [PATCH 031/263] fix: add lineheight to text styles and adjust font weight --- panda.config.ts | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/panda.config.ts b/panda.config.ts index 3cea4cca..82d1085f 100644 --- a/panda.config.ts +++ b/panda.config.ts @@ -73,10 +73,11 @@ const globalCss = defineGlobalStyles({ }, }); -const text = (size: number, weight: number) => ({ +const text = (size: number, weight: number, lineHeight: string) => ({ value: { fontSize: `${size}px`, fontWeight: weight, + lineHeight, }, }); @@ -108,48 +109,52 @@ export default defineConfig({ textStyles: { title: { md: { - strong: text(32, 600), - default: text(32, 400), + strong: text(32, 700, "120%"), + default: text(32, 400, "120%"), }, }, subtitle: { md: { - strong: text(20, 600), - default: text(20, 400), + strong: text(20, 600, "120%"), + default: text(20, 400, "120%"), }, sm: { - strong: text(14, 600), - default: text(14, 400), + strong: text(14, 600, "120%"), + default: text(14, 400, "120%"), }, }, paragraph: { md: { - strong: text(18, 600), - default: text(18, 400), + strong: text(18, 600, "150%"), + default: text(18, 400, "150%"), }, sm: { - strong: text(16, 600), - default: text(16, 400), + strong: text(16, 600, "140%"), + default: text(16, 400, "140%"), }, xsm: { - strong: text(10, 600), - default: text(10, 400), + strong: text(10, 600, "140%"), + default: text(10, 400, "140%"), }, }, cta: { md: { - strong: text(16, 600), - default: text(16, 400), + strong: text(16, 600, "100%"), + default: text(16, 400, "100%"), + }, + sm: { + strong: text(16, 600, "115%"), + default: text(16, 400, "115%"), }, }, label: { md: { - strong: text(16, 600), - default: text(16, 400), + strong: text(16, 600, "120%"), + default: text(16, 400, "120%"), }, sm: { - strong: text(12, 600), - default: text(12, 400), + strong: text(12, 600, "120%"), + default: text(12, 400, "120%"), }, }, }, From a6198d991249a3480bc0af634357258633504499 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Thu, 5 Feb 2026 22:50:10 -0300 Subject: [PATCH 032/263] fix: add fixed height to button and auto adjust icon size --- src/renderer/src/components/button.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/renderer/src/components/button.tsx b/src/renderer/src/components/button.tsx index e10020c5..6ed89d71 100644 --- a/src/renderer/src/components/button.tsx +++ b/src/renderer/src/components/button.tsx @@ -92,8 +92,8 @@ const button = cva({ }, }, size: { - md: { padding: "4" }, - sm: { py: "2", px: "4" }, + md: { height: "12", padding: "4" }, + sm: { height: "8", py: "2", px: "4" }, }, }, defaultVariants: { @@ -122,11 +122,7 @@ function Button({ disabled={disabled || isLoading} > {isLoading ? ( - + ) : ( children )} From 0833a9871d31766af45b1d8179cd244ac34a20e9 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Fri, 6 Feb 2026 01:39:53 -0300 Subject: [PATCH 033/263] feat: create components to render in home screen --- .../src/components/home/choose-host.tsx | 95 ++++++++++++++++++ .../src/components/home/connect-to-host.tsx | 98 +++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 src/renderer/src/components/home/choose-host.tsx create mode 100644 src/renderer/src/components/home/connect-to-host.tsx diff --git a/src/renderer/src/components/home/choose-host.tsx b/src/renderer/src/components/home/choose-host.tsx new file mode 100644 index 00000000..5ac21e30 --- /dev/null +++ b/src/renderer/src/components/home/choose-host.tsx @@ -0,0 +1,95 @@ +import { Button } from "@/components"; +import { useRunLocalServer } from "@/services/aymurai"; +import { css } from "@/styled/css"; +import { stack } from "@/styled/patterns"; +import { useNavigate } from "@tanstack/react-router"; +import { HardDrives, Monitor } from "phosphor-react"; + +interface ChooseHostProps { + onRemoteClick: () => void; +} +export default function ChooseHost({ onRemoteClick }: ChooseHostProps) { + const navigate = useNavigate(); + const { run: runLocalServer, isRunning } = useRunLocalServer({ + onSuccess: () => + navigate({ + to: "/home/features", + }), + }); + + return ( +
+ Logotipo AymurAI +
+

+ ¿Como deseas conectarte a Aymurai? +

+
+ +

+ o +

+ +
+
+
+ ); + // return ( + // + // Logotipo AymurAI + // + // + // ¿Como deseas conectarte a Aymurai? + // + // + // + // + // o + // + // + // + // + // + // ) +} diff --git a/src/renderer/src/components/home/connect-to-host.tsx b/src/renderer/src/components/home/connect-to-host.tsx new file mode 100644 index 00000000..a524e8d7 --- /dev/null +++ b/src/renderer/src/components/home/connect-to-host.tsx @@ -0,0 +1,98 @@ +import { useConnectToHost } from "@/services/aymurai"; +import * as localStore from "@/store/useLocal"; +import { css } from "@/styled/css"; +import { Stack } from "@/styled/jsx"; +import { useNavigate } from "@tanstack/react-router"; +import { AxiosError } from "axios"; +import { ArrowLeft } from "phosphor-react"; +import { type ChangeEventHandler, useState } from "react"; +import { ZodError } from "zod"; +import Button from "../button"; +import Input from "../input"; + +const BackButton = ({ onClick }: { onClick: () => void }) => ( + +); + +interface ConnectToHostProps { + onBackClick: () => void; +} +export default function ConnectToHost({ onBackClick }: ConnectToHostProps) { + const navigate = useNavigate(); + const remoteHost = localStore.useServerHost() ?? ""; + const { setServerHost } = localStore.useServerHostActions(); + + const [host, setHost] = useState(remoteHost); + + const { mutate: connectToHost, isPending, error, reset } = useConnectToHost(); + + const handleChange: ChangeEventHandler = (e) => { + setHost(e.target.value); + reset(); + }; + + const tryConnection = () => { + connectToHost(host, { + onSuccess: () => { + setServerHost(host); + navigate({ + to: "/home/features", + }); + }, + }); + }; + + return ( + <> + + +

+ Ingresa la dirección del servidor al que deseas conectarte +

+ + + + + + +
+ + ); +} + +function errorMessage(err: Error | null): string { + console.error(err); + if (err instanceof AxiosError) { + if (err.code === "ERR_NETWORK") return "No se pudo conectar al servidor"; + return "Error de conexión"; + } + + if (err instanceof ZodError) { + return "El servidor no respondió correctamente"; + } + + if (err instanceof TypeError) { + return "El formato de la URL es incorrecto."; + } + + return "Error desconocido"; +} From 0947627c4dc27c48833c7bc17e430cc5cc6e513f Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Fri, 6 Feb 2026 01:40:08 -0300 Subject: [PATCH 034/263] feat: create link card tool for features --- .../src/components/home/card-tool.tsx | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/renderer/src/components/home/card-tool.tsx diff --git a/src/renderer/src/components/home/card-tool.tsx b/src/renderer/src/components/home/card-tool.tsx new file mode 100644 index 00000000..fe39adb8 --- /dev/null +++ b/src/renderer/src/components/home/card-tool.tsx @@ -0,0 +1,92 @@ +import { cx, sva } from "@/styled/css"; +import { Stack, styled } from "@/styled/jsx"; +import { stack } from "@/styled/patterns"; +import { Link, type LinkComponentProps } from "@tanstack/react-router"; +import type { Icon } from "phosphor-react"; + +const card = sva({ + className: "card-tool", + slots: ["container", "icon"], + base: { + container: { + ...stack.raw({ gap: "4", align: "start" }), + padding: "8", + rounded: "sm", + + transitionProperty: "[border, box-shadow]", + transitionTimingFunction: "default", + transitionDuration: "normal", + }, + icon: { + p: "4", + borderRadius: "[14px]", + }, + }, + variants: { + disabled: { + true: { + container: { + border: "primary", + bg: "bg.primary", + cursor: "not-allowed", + color: "text.lighter", + }, + icon: { + bg: "bg.secondary", + }, + }, + false: { + container: { + border: "primary", + bg: "bg.secondary", + cursor: "pointer", + + "&:hover": { + border: "primary-alt", + boxShadow: "[0px 0px 15px 0px #3F479D66]", + }, + }, + icon: { + bg: "bg.primary-alternative", + }, + }, + }, + }, + defaultVariants: { + disabled: false, + }, +}); + +interface CardToolProps extends LinkComponentProps { + title: string; + subtitle: string; + icon: Icon; + disabled?: boolean; +} +export default function CardTool({ + title, + subtitle, + icon: Icon, + disabled = false, + className, + ...props +}: CardToolProps) { + const classes = card({ disabled }); + return ( + +
+ +
+ + {title} + + {subtitle} + + + + ); +} From 5e41df1aeec169d285d03ae8a369e5099e775958 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Fri, 6 Feb 2026 01:41:18 -0300 Subject: [PATCH 035/263] feat: redesign home --- src/renderer/src/layout/home/Home.styles.ts | 81 ++++++++++ src/renderer/src/layout/home/index.tsx | 60 +++++++ src/renderer/src/layout/login/Login.styles.ts | 42 ----- src/renderer/src/layout/login/index.tsx | 50 ------ .../src/routes/home._layout/features.tsx | 51 ------ src/renderer/src/routes/home._layout/host.tsx | 150 ------------------ .../src/routes/home._layout/route.tsx | 11 -- src/renderer/src/routes/home/features.tsx | 66 ++++++++ src/renderer/src/routes/home/host.tsx | 24 +++ .../routes/{home._layout => home}/index.tsx | 2 +- 10 files changed, 232 insertions(+), 305 deletions(-) create mode 100644 src/renderer/src/layout/home/Home.styles.ts create mode 100644 src/renderer/src/layout/home/index.tsx delete mode 100644 src/renderer/src/layout/login/Login.styles.ts delete mode 100644 src/renderer/src/layout/login/index.tsx delete mode 100644 src/renderer/src/routes/home._layout/features.tsx delete mode 100644 src/renderer/src/routes/home._layout/host.tsx delete mode 100644 src/renderer/src/routes/home._layout/route.tsx create mode 100644 src/renderer/src/routes/home/features.tsx create mode 100644 src/renderer/src/routes/home/host.tsx rename src/renderer/src/routes/{home._layout => home}/index.tsx (72%) diff --git a/src/renderer/src/layout/home/Home.styles.ts b/src/renderer/src/layout/home/Home.styles.ts new file mode 100644 index 00000000..9f1861aa --- /dev/null +++ b/src/renderer/src/layout/home/Home.styles.ts @@ -0,0 +1,81 @@ +import { styled } from "@/styles"; +import { Link } from "@tanstack/react-router"; + +export const Background = styled("main", { + bg: "$secondary", + + display: "flex", + + height: "100vh", + width: "100vw", + + p: 32, +}); + +export const InnerBackground = styled("div", { + display: "flex", + flexDirection: "column", + justifyContent: "center", + alignItems: "center", + gap: 48, + + position: "relative", + + bg: "$white", + b: "1px solid $borderPrimary", + + width: "100%", + height: "100%", +}); + +export const BackButton = styled(Link, { + position: "absolute", + + top: "$m", + left: "$m", +}); + +export const BuiltBy = styled("div", { + position: "absolute", + bottom: "$xxl", +}); + +// /** +// * Adds the `$secondary` colors +// */ +// export const Background = styled("main", { +// bg: "$secondary", + +// display: "flex", + +// height: "100vh", +// }); + +// /** +// * Contains the Login elements and adds the margin +// */ +// export const Container = styled("div", { +// bg: "$white", + +// display: "flex", +// flexDirection: "column", +// justifyContent: "space-between", +// alignItems: "center", +// flex: 1, +// gap: "$l", + +// padding: "$l", +// margin: "$xl", + +// b: "1px solid $borderPrimary", +// }); + +// export const MainContent = styled(Stack, { +// flex: 1, +// }); + +// export const Logo = styled("img", { +// width: 250, +// mt: -32, +// mb: -16, +// }); diff --git a/src/renderer/src/layout/home/index.tsx b/src/renderer/src/layout/home/index.tsx new file mode 100644 index 00000000..cc97bf82 --- /dev/null +++ b/src/renderer/src/layout/home/index.tsx @@ -0,0 +1,60 @@ +import { css } from "@/styled/css"; +import { stack } from "@/styled/patterns"; + +const background = css({ + display: "flex", + + bg: "bg.primary-highlight", + height: "screen", + width: "screen", + + p: "8", +}); +const inner = css( + stack.raw({ justify: "center", align: "center", gap: "12" }), + { + pos: "relative", + + bg: "bg.secondary", + border: "primary", + + width: "full", + height: "full", + }, +); + +const builtBy = css({ + pos: "absolute", + bottom: "16", // 64px +}); + +interface LoginLayoutProps { + children?: React.ReactNode; +} +export default function LoginLayout({ children }: LoginLayoutProps) { + return ( +
+
+ {children} + {/* Floating content below */}k +
+
+

+ Plataforma hecha por +

+ DataGenero isologo +
+
+
+
+ ); +} diff --git a/src/renderer/src/layout/login/Login.styles.ts b/src/renderer/src/layout/login/Login.styles.ts deleted file mode 100644 index 1dffc0d0..00000000 --- a/src/renderer/src/layout/login/Login.styles.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Stack } from "@/components"; -import { styled } from "@/styles"; - -/** - * Adds the `$secondary` colors - */ -export const Background = styled("main", { - bg: "$secondary", - - display: "flex", - - height: "100vh", -}); - -/** - * Contains the Login elements and adds the margin - */ -export const Container = styled("div", { - bg: "$white", - - display: "flex", - flexDirection: "column", - justifyContent: "space-between", - alignItems: "center", - flex: 1, - gap: "$l", - - padding: "$l", - margin: "$xl", - - b: "1px solid $borderPrimary", -}); - -export const MainContent = styled(Stack, { - flex: 1, -}); - -export const Logo = styled("img", { - width: 250, - mt: -32, - mb: -16, -}); diff --git a/src/renderer/src/layout/login/index.tsx b/src/renderer/src/layout/login/index.tsx deleted file mode 100644 index a84d5c34..00000000 --- a/src/renderer/src/layout/login/index.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Button, Label, Stack, Subtitle } from "@/components"; -import { Outlet, useNavigate } from "@tanstack/react-router"; -import { ArrowBendUpLeft } from "phosphor-react"; -import * as S from "./Login.styles"; - -interface LoginLayoutProps { - canGoBack?: boolean; -} -export default function LoginLayout({ canGoBack = false }: LoginLayoutProps) { - const navigate = useNavigate(); - - const handleGoBack = () => { - navigate({ to: "/home" }); - }; - return ( - - - - {/* Title */} - - Te damos la bienvenida a - - - - {/* Outlet: buttons and actions to proceed to the platform */} - - - {canGoBack && ( - - )} - - - {/* DataGenero info */} - - - - DataGenero - - - - - ); -} diff --git a/src/renderer/src/routes/home._layout/features.tsx b/src/renderer/src/routes/home._layout/features.tsx deleted file mode 100644 index 3878344a..00000000 --- a/src/renderer/src/routes/home._layout/features.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { Button, Stack, Subtitle } from "@/components"; -import { Feature } from "@/types/features"; -import { createFileRoute, useNavigate } from "@tanstack/react-router"; -import { ArrowBendUpLeft, Database, Detective } from "phosphor-react"; - -export const Route = createFileRoute("/home/_layout/features")({ - component: RouteComponent, -}); - -function RouteComponent() { - const navigate = useNavigate(); - - const handleBack = () => { - navigate({ to: "/home" }); - }; - - const handleSelectFeature = (feature: Feature) => () => { - navigate({ - to: "/app/$feature/onboarding", - params: { feature }, - }); - }; - - return ( - - - ¿Cual función vas a utilizar? - - - - o - - - - - ); -} diff --git a/src/renderer/src/routes/home._layout/host.tsx b/src/renderer/src/routes/home._layout/host.tsx deleted file mode 100644 index 5918fbbb..00000000 --- a/src/renderer/src/routes/home._layout/host.tsx +++ /dev/null @@ -1,150 +0,0 @@ -import { Button, Input, Label, Stack, Subtitle } from "@/components"; -import { useConnectToHost, useRunLocalServer } from "@/services/aymurai"; -import { localStore } from "@/store/useLocal"; -import { createFileRoute, useNavigate } from "@tanstack/react-router"; -import { AxiosError } from "axios"; -import { ArrowBendUpLeft, HardDrives, Monitor } from "phosphor-react"; -import { useState } from "react"; -import { ZodError } from "zod"; - -function errorMessage(err: Error): string { - if (err instanceof AxiosError) { - if (err.code === "ERR_NETWORK") return "No se pudo conectar al servidor"; - return "Error de conexión"; - } - - if (err instanceof ZodError) { - return "Formato de respuesta inválido."; - } - - return "Error desconocido"; -} - -export const Route = createFileRoute("/home/_layout/host")({ - component: RouteComponent, -}); - -function RouteComponent() { - const navigate = useNavigate(); - - const [isLocal, setIsLocal] = useState(null); - - const remoteHost = localStore.useServerHost() ?? ""; - const { setServerHost } = localStore.useServerHostActions(); - const { mutate: connectToHost, isPending, error, reset } = useConnectToHost(); - const { run: runLocalServer, isRunning } = useRunLocalServer({ - onSuccess: () => - navigate({ - to: "/home/features", - }), - }); - - const handleBack = () => { - setIsLocal(null); - }; - - const handleUseLocal = async () => { - await runLocalServer(); - }; - - const handleUseRemote = () => { - setIsLocal(false); - }; - - const tryConnection = () => { - connectToHost(remoteHost, { - onSuccess: () => - navigate({ - to: "/home/features", - }), - }); - }; - - const handleHostChange = (value: string) => { - setServerHost(value); - reset(); - }; - - return ( - - {/* Not yet selected */} - {isLocal === null && ( - <> - - ¿Cómo prefieres conectarte a AymurAI? - - {/* Buttons */} - - - o - - - - )} - - {/* Remote host option selected */} - {isLocal === false && ( - - - Ingresa la dirección del servidor al que deseas conectarte - - - - {error && ( -
- -
- )} -
- - -
- )} -
- ); -} diff --git a/src/renderer/src/routes/home._layout/route.tsx b/src/renderer/src/routes/home._layout/route.tsx deleted file mode 100644 index f28124e6..00000000 --- a/src/renderer/src/routes/home._layout/route.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import LoginLayout from "@/layout/login"; -import { createFileRoute } from "@tanstack/react-router"; - -export const Route = createFileRoute("/home/_layout")({ - component: RouteComponent, - onEnter: ({ context }) => context.queryClient.removeQueries(), -}); - -function RouteComponent() { - return ; -} diff --git a/src/renderer/src/routes/home/features.tsx b/src/renderer/src/routes/home/features.tsx new file mode 100644 index 00000000..f770235f --- /dev/null +++ b/src/renderer/src/routes/home/features.tsx @@ -0,0 +1,66 @@ +import CardTool from "@/components/home/card-tool"; +import { css } from "@/styled/css"; +import { Grid, Stack, styled } from "@/styled/jsx"; +import { Feature } from "@/types/features"; +import { createFileRoute } from "@tanstack/react-router"; +import { Database, Detective } from "phosphor-react"; + +export const Route = createFileRoute("/home/features")({ + component: RouteComponent, +}); + +const header = css({ + width: "full", + py: "6", + px: "8", + bg: "bg.secondary", + borderBottom: "[1px solid #BCBAB8]", +}); +const content = css({ + display: "flex", + justifyContent: "center", + flex: "1", + + width: "full", + height: "full", + pt: "28", + + bg: "bg.primary", +}); + +function RouteComponent() { + return ( + +
+ AymurAI logo +
+
+ + + ¡Hola! Selecciona la herramienta a utilizar + + + + + + +
+
+ ); +} diff --git a/src/renderer/src/routes/home/host.tsx b/src/renderer/src/routes/home/host.tsx new file mode 100644 index 00000000..42ebba5d --- /dev/null +++ b/src/renderer/src/routes/home/host.tsx @@ -0,0 +1,24 @@ +import ChooseHost from "@/components/home/choose-host"; +import ConnectToHost from "@/components/home/connect-to-host"; +import LoginLayout from "@/layout/home"; +import { createFileRoute } from "@tanstack/react-router"; +import { useState } from "react"; + +export const Route = createFileRoute("/home/host")({ + component: RouteComponent, +}); + +function RouteComponent() { + const [isLocal, setIsLocal] = useState(null); + + return ( + + {isLocal === null && ( + setIsLocal(false)} /> + )} + {isLocal === false && ( + setIsLocal(null)} /> + )} + + ); +} diff --git a/src/renderer/src/routes/home._layout/index.tsx b/src/renderer/src/routes/home/index.tsx similarity index 72% rename from src/renderer/src/routes/home._layout/index.tsx rename to src/renderer/src/routes/home/index.tsx index 14db4ead..cb8400d0 100644 --- a/src/renderer/src/routes/home._layout/index.tsx +++ b/src/renderer/src/routes/home/index.tsx @@ -1,6 +1,6 @@ import { Navigate, createFileRoute } from "@tanstack/react-router"; -export const Route = createFileRoute("/home/_layout/")({ +export const Route = createFileRoute("/home/")({ component: Index, }); From ce991130369560dd6ec042d4c0789ca2fe624fed Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Fri, 6 Feb 2026 01:58:28 -0300 Subject: [PATCH 036/263] fix: extra character in home layout and rename the component --- src/renderer/src/layout/home/index.tsx | 7 ++++--- src/renderer/src/routes/home/host.tsx | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/renderer/src/layout/home/index.tsx b/src/renderer/src/layout/home/index.tsx index cc97bf82..8ecaaffd 100644 --- a/src/renderer/src/layout/home/index.tsx +++ b/src/renderer/src/layout/home/index.tsx @@ -28,15 +28,16 @@ const builtBy = css({ bottom: "16", // 64px }); -interface LoginLayoutProps { +interface HomeLayoutProps { children?: React.ReactNode; } -export default function LoginLayout({ children }: LoginLayoutProps) { +export default function HomeLayout({ children }: HomeLayoutProps) { return (
{children} - {/* Floating content below */}k + + {/* Floating content below */}

(null); return ( - + {isLocal === null && ( setIsLocal(false)} /> )} {isLocal === false && ( setIsLocal(null)} /> )} - + ); } From 9cd982f83279bfdfc76f25f626cca819ad7ba602 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 7 Feb 2026 23:14:52 -0300 Subject: [PATCH 037/263] chore(styles): add animation semantic tokens --- panda.config.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/panda.config.ts b/panda.config.ts index 82d1085f..437d9784 100644 --- a/panda.config.ts +++ b/panda.config.ts @@ -106,6 +106,24 @@ export default defineConfig({ strictTokens: true, theme: { + extend: { + keyframes: { + fadeIn: { + from: { opacity: "0", transform: "scale(0.96)" }, + to: { opacity: "1", transform: "scale(1)" }, + }, + fadeOut: { + from: { opacity: "1", transform: "scale(1)" }, + to: { opacity: "0", transform: "scale(0.96)" }, + }, + }, + tokens: { + animations: { + fadeIn: { value: "fadeIn 0.15s ease-out" }, + fadeOut: { value: "fadeOut 0.1s ease-in" }, + }, + }, + }, textStyles: { title: { md: { From 5475a617f590685371b85d06e474d891acf8659b Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 7 Feb 2026 23:15:46 -0300 Subject: [PATCH 038/263] feat: add more brand images --- .../public/brand/aymurai-hor-darkpurple.svg | 39 ++++++++++++++++++ .../public/brand/aymurai-iso-darkpurple.svg | 40 +++++++++++++++++++ .../public/brand/aymurai-iso-purple.svg | 35 ++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 src/renderer/public/brand/aymurai-hor-darkpurple.svg create mode 100644 src/renderer/public/brand/aymurai-iso-darkpurple.svg create mode 100644 src/renderer/public/brand/aymurai-iso-purple.svg diff --git a/src/renderer/public/brand/aymurai-hor-darkpurple.svg b/src/renderer/public/brand/aymurai-hor-darkpurple.svg new file mode 100644 index 00000000..d8f0fd19 --- /dev/null +++ b/src/renderer/public/brand/aymurai-hor-darkpurple.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/renderer/public/brand/aymurai-iso-darkpurple.svg b/src/renderer/public/brand/aymurai-iso-darkpurple.svg new file mode 100644 index 00000000..0e29278f --- /dev/null +++ b/src/renderer/public/brand/aymurai-iso-darkpurple.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/renderer/public/brand/aymurai-iso-purple.svg b/src/renderer/public/brand/aymurai-iso-purple.svg new file mode 100644 index 00000000..35114f7c --- /dev/null +++ b/src/renderer/public/brand/aymurai-iso-purple.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From edce72959c1f980fc3c846874ba76542bfb19c73 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 8 Feb 2026 00:00:16 -0300 Subject: [PATCH 039/263] feat(components): create brand, layout and ui components --- src/renderer/src/components/layout/footer.tsx | 27 +++ src/renderer/src/components/layout/header.tsx | 91 +++++++++ .../src/components/layout/main-content.tsx | 46 +++++ src/renderer/src/components/ui/button.tsx | 139 +++++++++++++ src/renderer/src/components/ui/card.tsx | 53 +++++ src/renderer/src/components/ui/input.tsx | 191 ++++++++++++++++++ src/renderer/src/components/ui/popover.tsx | 53 +++++ 7 files changed, 600 insertions(+) create mode 100644 src/renderer/src/components/layout/footer.tsx create mode 100644 src/renderer/src/components/layout/header.tsx create mode 100644 src/renderer/src/components/layout/main-content.tsx create mode 100644 src/renderer/src/components/ui/button.tsx create mode 100644 src/renderer/src/components/ui/card.tsx create mode 100644 src/renderer/src/components/ui/input.tsx create mode 100644 src/renderer/src/components/ui/popover.tsx diff --git a/src/renderer/src/components/layout/footer.tsx b/src/renderer/src/components/layout/footer.tsx new file mode 100644 index 00000000..28ab5f6c --- /dev/null +++ b/src/renderer/src/components/layout/footer.tsx @@ -0,0 +1,27 @@ +import { css } from "@/styled/css"; +import BuiltBy from "../brand/built-by"; + +const content = css({ + display: "flex", + flexDirection: "row", + + borderTop: "primary", + px: "12", + py: "6", +}); +const childrenContainer = css({ + flex: "1", +}); + +interface FooterProps { + withBuiltBy?: boolean; + children?: React.ReactNode; +} +export default function Footer({ withBuiltBy, children }: FooterProps) { + return ( +

+ {withBuiltBy && } +
{children}
+
+ ); +} diff --git a/src/renderer/src/components/layout/header.tsx b/src/renderer/src/components/layout/header.tsx new file mode 100644 index 00000000..4dadef3a --- /dev/null +++ b/src/renderer/src/components/layout/header.tsx @@ -0,0 +1,91 @@ +import { FEATURES } from "@/constants"; +import { css } from "@/styled/css"; +import { Divider, Grid, Stack, styled } from "@/styled/jsx"; +import type { FeatureFlowEnum } from "@/types/features"; +import { Link } from "@tanstack/react-router"; +import { DotsNine } from "phosphor-react"; +import FeatureIcon from "../feature-icon"; +import Button from "../ui/button"; +import Card from "../ui/card"; +import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"; + +function Menu() { + const features = Object.entries(FEATURES); + return ( + + + + + + + {features.map(([value, feature]) => ( + + + + + + {feature.title} + + + + + ))} + + + + ); +} + +const header = css({ + width: "full", + py: "6", + px: "8", + bg: "bg.secondary", + borderBottom: "[1px solid #BCBAB8]", +}); + +interface HeaderProps { + title?: string; + children?: React.ReactNode; + withFeaturesMenu?: boolean; +} +export default function Header({ + title, + withFeaturesMenu, + children, +}: HeaderProps) { + const img = title + ? "brand/aymurai-iso-darkpurple.svg" + : "brand/aymurai-hor-darkpurple.svg"; + + return ( +
+ + + AymurAI logo + {title && ( + <> + + {title} + + )} + + + {children} + {withFeaturesMenu && } + + +
+ ); +} diff --git a/src/renderer/src/components/layout/main-content.tsx b/src/renderer/src/components/layout/main-content.tsx new file mode 100644 index 00000000..097353ae --- /dev/null +++ b/src/renderer/src/components/layout/main-content.tsx @@ -0,0 +1,46 @@ +import { cva } from "@/styled/css"; + +const content = cva({ + base: { + flex: "1", + + width: "full", + height: "full", + + bg: "bg.primary", + }, + variants: { + full: { + true: {}, + false: { + display: "flex", + flexDir: "column", + alignItems: "center", + pt: "28", + + "& > div.spacing": { + width: "5xl", + mx: "8", + }, + }, + }, + }, + defaultVariants: { + full: false, + }, +}); + +interface MainContentProps { + children: React.ReactNode; + full?: boolean; +} +export default function MainContent({ + children, + full = false, +}: MainContentProps) { + return ( +
+
{children}
+
+ ); +} diff --git a/src/renderer/src/components/ui/button.tsx b/src/renderer/src/components/ui/button.tsx new file mode 100644 index 00000000..b1ebf72b --- /dev/null +++ b/src/renderer/src/components/ui/button.tsx @@ -0,0 +1,139 @@ +import { type RecipeVariantProps, css, cva } from "@/styled/css"; +import { CircleNotch } from "phosphor-react"; +import type { ButtonHTMLAttributes } from "react"; + +const button = cva({ + base: { + display: "flex", + flexDir: "row", + gap: "1", // 4px + justifyContent: "center", + alignSelf: "stretch", + alignItems: "center", + + transitionProperty: "[background-color, color, box-shadow]", + transitionDuration: "slow", // 300ms + transitionTimingFunction: "default", + + border: "none", + + textStyle: "cta.md.strong", + + cursor: "pointer", + + "&:disabled": { + cursor: "not-allowed", + }, + }, + variants: { + variant: { + primary: { + bg: "action.default", + color: "text.onbutton-default", + + "&:hover:enabled": { + bg: "action.hover", + color: "text.onbutton-alternative", + }, + + "&:active:enabled": { + bg: "action.pressed", + color: "text.onbutton-alternative", + }, + + "&:focus:enabled": { + bg: "action.focus", + outline: "primary-alt", + outlineWidth: "[2px]", + boxShadow: "[0px 0px 10px rgba(17, 0, 65, 0.2)]", + }, + + "&:disabled": { + bg: "action.disabled", + color: "text.onbutton-default", + }, + }, + secondary: { + color: "text.onbutton-default", + bg: "bg.secondary", + + borderWidth: "[2px]", + borderStyle: "solid", + borderColor: "action.alt-default", + + "&:hover:enabled": { + color: "text.onbutton-default", + bg: "bg.secondary", + borderColor: "action.hover", + }, + + "&:active:enabled": { + color: "text.onbutton-alternative", + bg: "action.pressed", + borderColor: "action.pressed", + }, + + "&:focus:enabled": { + boxShadow: "[0px 0px 10px rgba(17, 0, 65, 0.2)]", + outline: "primary-alt", + outlineWidth: "[2px]", + bg: "bg.secondary", + }, + + "&:disabled": { + color: "text.onbutton-disabled", + bg: "bg.secondary", + borderColor: "action.disabled", + }, + }, + tertiary: { + // TODO: not implemented + }, + }, + size: { + md: { height: "12", padding: "4", rounded: "sm" }, + sm: { height: "9", py: "2", px: "4", rounded: "sm" }, + "icon-md": { + height: "12", + width: "12", + padding: "3", + rounded: "md", + }, + "icon-sm": { height: "9", width: "9", padding: "2", rounded: "md" }, + }, + }, + defaultVariants: { + size: "md", + variant: "primary", + }, +}); + +type ButtonProps = RecipeVariantProps & + ButtonHTMLAttributes & { + isLoading?: boolean; + }; + +function Button({ + size, + variant, + isLoading, + disabled, + children, + ...props +}: ButtonProps) { + return ( + + ); +} + +export default Button; diff --git a/src/renderer/src/components/ui/card.tsx b/src/renderer/src/components/ui/card.tsx new file mode 100644 index 00000000..53247b9b --- /dev/null +++ b/src/renderer/src/components/ui/card.tsx @@ -0,0 +1,53 @@ +import { cva } from "@/styled/css"; + +const styles = cva({ + base: { + transitionProperty: "[border, box-shadow]", + transitionTimingFunction: "default", + transitionDuration: "normal", + }, + variants: { + size: { + lg: { + p: "8", + rounded: "sm", + }, + sm: { + rounded: "lg", + p: "4", + }, + }, + disabled: { + true: { + border: "primary", + bg: "bg.primary", + cursor: "not-allowed", + color: "text.lighter", + }, + false: { + border: "primary", + bg: "bg.secondary", + cursor: "pointer", + + "&:hover": { + border: "primary-alt", + boxShadow: "[0px 0px 15px 0px #3F479D66]", + }, + }, + }, + }, +}); + +interface CardProps { + children?: React.ReactNode; + disabled?: boolean; + size?: "lg" | "sm"; +} +export default function Card({ + disabled = false, + size = "lg", + children, +}: CardProps) { + const classes = styles({ size, disabled }); + return
{children}
; +} diff --git a/src/renderer/src/components/ui/input.tsx b/src/renderer/src/components/ui/input.tsx new file mode 100644 index 00000000..4eecdc3f --- /dev/null +++ b/src/renderer/src/components/ui/input.tsx @@ -0,0 +1,191 @@ +import { useId } from "react"; + +import { cva, sva } from "@/styled/css"; +import { hstack, stack } from "@/styled/patterns"; +import { WarningCircle } from "phosphor-react"; + +const input = sva({ + slots: ["container", "inputBox", "input", "label", "errorMessage", "helper"], + base: { + container: stack.raw({ gap: "1", width: "full" }), + inputBox: { + ...hstack.raw({ alignItems: "center", gap: "1" }), + + rounded: "sm", + border: "primary", + + "&:focus-within": { + outline: "none", + boxShadow: "[0px 2px 2px rgba(0, 0, 0, 0.16)]", + }, + }, + input: { + textStyle: "label.md.default", + border: "none", + outline: "none", + flex: "[1]", + + p: "3", + + "&::placeholder": { + color: "text.lighter", + }, + }, + label: { textStyle: "label.sm.default" }, + errorMessage: { + ...hstack.raw({ gap: "1" }), + textStyle: "label.sm.default", + color: "system.error", + }, + helper: { + textStyle: "label.sm.default", + color: "text.lighter", + }, + }, + variants: { + disabled: { + true: { + inputBox: { + bg: "bg.primary", + border: "primary", + color: "text.lighter", + cursor: "not-allowed", + }, + input: { + cursor: "not-allowed", + }, + }, + false: { + inputBox: { + bg: "white", + }, + }, + }, + error: { + true: { + container: { + color: "system.error", + }, + inputBox: { + border: "error", + }, + input: { + // "&::placeholder": { + // color: "system.error-secondary", + // }, + }, + label: { color: "system.error" }, + }, + false: {}, + }, + }, + defaultVariants: { + error: false, + disabled: false, + }, +}); + +const affix = cva({ + base: { + ...hstack.raw({ alignItems: "center", gap: "1" }), + userSelect: "none", + textStyle: "label.md.default", + // py: "3", + }, + variants: { + position: { + prefix: { pl: "3", mr: "-3" }, + suffix: { pr: "3", ml: "-3" }, + }, + }, +}); + +interface InputProps { + // Rendering + label?: string; + placeholder?: string; + prefix?: string; + suffix?: string; + suggestion?: string; + helper?: string; + // Control + id?: string; + value: string; + onChange?: React.ChangeEventHandler; + disabled?: boolean; + error?: string | null; + type?: "text" | "number"; +} +export default function Input({ + // Rendering + label, + placeholder, + prefix, + suffix, + suggestion, + helper, + // Control + id, + value, + onChange, + disabled = false, + error, + type, +}: InputProps) { + const randomId = useId(); + const inputId = id ?? randomId; + const errorMessageId = `${inputId}-error`; + + const classes = input({ disabled, error: !!error }); + + return ( +
+ {label && ( + + )} + +
+ {prefix && ( +
+ {prefix} + {/* In the designs this vertical bar is defined as a Text, but it's + not. Use a Label instead */} + | +
+ )} + + + + {suffix && ( +
+ {/* In the designs this vertical bar is defined as a Text, but it's + not. Use a Label instead */} + | + {suffix} +
+ )} +
+ + {helper && !error &&

{helper}

} + {error && ( + + )} +
+ ); +} diff --git a/src/renderer/src/components/ui/popover.tsx b/src/renderer/src/components/ui/popover.tsx new file mode 100644 index 00000000..8be12b91 --- /dev/null +++ b/src/renderer/src/components/ui/popover.tsx @@ -0,0 +1,53 @@ +import { css, cx } from "@/styled/css"; +import * as PopoverPrimitive from "@radix-ui/react-popover"; +import type { ComponentPropsWithoutRef } from "react"; + +const Popover = PopoverPrimitive.Root; +const PopoverTrigger = PopoverPrimitive.Trigger; +const PopoverAnchor = PopoverPrimitive.Anchor; +const PopoverClose = PopoverPrimitive.Close; + +const contentStyles = css({ + zIndex: 50, + bg: "bg.primary", + rounded: "lg", + boxShadow: "[0px 0px 15px 0px #00000026]", + + "&[data-state='open']": { + animation: "fadeIn", + }, + "&[data-state='closed']": { + animation: "fadeOut", + }, +}); + +const arrowStyles = css({ + fill: "bg.secondary", +}); + +function PopoverContent({ + className, + sideOffset = 8, + showArrow = false, + container, + children, + ...props +}: ComponentPropsWithoutRef & { + showArrow?: boolean; + container?: HTMLElement; +}) { + return ( + + + {children} + {showArrow && } + + + ); +} + +export { Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger }; From a2c2040ae0979800c5b7ccf80b43cf80710273ae Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 21 Feb 2026 12:53:09 -0300 Subject: [PATCH 040/263] fix: replace brand images with correct ones and set proper heights --- .../public/brand/aymurai-hor-darkpurple.svg | 64 +++++++----------- .../public/brand/aymurai-iso-darkpurple.svg | 58 +++++----------- .../public/brand/aymurai-vert-darkpurple.png | Bin 48200 -> 0 bytes .../public/brand/aymurai-vert-darkpurple.svg | 25 +++++++ .../src/components/home/choose-host.tsx | 41 +---------- src/renderer/src/components/layout/header.tsx | 59 ++-------------- 6 files changed, 74 insertions(+), 173 deletions(-) delete mode 100644 src/renderer/public/brand/aymurai-vert-darkpurple.png create mode 100644 src/renderer/public/brand/aymurai-vert-darkpurple.svg diff --git a/src/renderer/public/brand/aymurai-hor-darkpurple.svg b/src/renderer/public/brand/aymurai-hor-darkpurple.svg index d8f0fd19..efde8df1 100644 --- a/src/renderer/public/brand/aymurai-hor-darkpurple.svg +++ b/src/renderer/public/brand/aymurai-hor-darkpurple.svg @@ -1,39 +1,25 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/renderer/public/brand/aymurai-iso-darkpurple.svg b/src/renderer/public/brand/aymurai-iso-darkpurple.svg index 0e29278f..9fa89d34 100644 --- a/src/renderer/public/brand/aymurai-iso-darkpurple.svg +++ b/src/renderer/public/brand/aymurai-iso-darkpurple.svg @@ -1,40 +1,18 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + diff --git a/src/renderer/public/brand/aymurai-vert-darkpurple.png b/src/renderer/public/brand/aymurai-vert-darkpurple.png deleted file mode 100644 index e043f5276712a253970f14d2efc8c0be5e982050..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48200 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

5SAH0eBg(dX|Ui;>wMnOc-^?Yw+e*la{I)D`t#j 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 + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/renderer/src/components/home/choose-host.tsx b/src/renderer/src/components/home/choose-host.tsx index 5ac21e30..cc8a36a7 100644 --- a/src/renderer/src/components/home/choose-host.tsx +++ b/src/renderer/src/components/home/choose-host.tsx @@ -20,11 +20,9 @@ export default function ChooseHost({ onRemoteClick }: ChooseHostProps) { return (

Logotipo AymurAI

); - // return ( - // - // Logotipo AymurAI - // - // - // ¿Como deseas conectarte a Aymurai? - // - // - // - // - // o - // - // - // - // - // - // ) } diff --git a/src/renderer/src/components/layout/header.tsx b/src/renderer/src/components/layout/header.tsx index 4dadef3a..8eb5831c 100644 --- a/src/renderer/src/components/layout/header.tsx +++ b/src/renderer/src/components/layout/header.tsx @@ -1,46 +1,5 @@ -import { FEATURES } from "@/constants"; import { css } from "@/styled/css"; import { Divider, Grid, Stack, styled } from "@/styled/jsx"; -import type { FeatureFlowEnum } from "@/types/features"; -import { Link } from "@tanstack/react-router"; -import { DotsNine } from "phosphor-react"; -import FeatureIcon from "../feature-icon"; -import Button from "../ui/button"; -import Card from "../ui/card"; -import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"; - -function Menu() { - const features = Object.entries(FEATURES); - return ( - - - - - - - {features.map(([value, feature]) => ( - - - - - - {feature.title} - - - - - ))} - - - - ); -} const header = css({ width: "full", @@ -53,22 +12,17 @@ const header = css({ interface HeaderProps { title?: string; children?: React.ReactNode; - withFeaturesMenu?: boolean; } -export default function Header({ - title, - withFeaturesMenu, - children, -}: HeaderProps) { +export default function Header({ title, children }: HeaderProps) { const img = title - ? "brand/aymurai-iso-darkpurple.svg" - : "brand/aymurai-hor-darkpurple.svg"; + ? "/brand/aymurai-iso-darkpurple.svg" + : "/brand/aymurai-hor-darkpurple.svg"; return (
- AymurAI logo + AymurAI logo {title && ( <> )} - - {children} - {withFeaturesMenu && } - + {children}
); From edb8521130acd64e2c278aacb881a0a1558aaf77 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 21 Feb 2026 13:10:35 -0300 Subject: [PATCH 041/263] feat: create modern tooltip component --- .../{tooltip => tooltip-old}/Arrow.tsx | 0 .../Tooltip.styles.ts | 0 .../{tooltip => tooltip-old}/index.tsx | 0 src/renderer/src/components/ui/tooltip.tsx | 50 +++++++++++++++++++ 4 files changed, 50 insertions(+) rename src/renderer/src/components/{tooltip => tooltip-old}/Arrow.tsx (100%) rename src/renderer/src/components/{tooltip => tooltip-old}/Tooltip.styles.ts (100%) rename src/renderer/src/components/{tooltip => tooltip-old}/index.tsx (100%) create mode 100644 src/renderer/src/components/ui/tooltip.tsx diff --git a/src/renderer/src/components/tooltip/Arrow.tsx b/src/renderer/src/components/tooltip-old/Arrow.tsx similarity index 100% rename from src/renderer/src/components/tooltip/Arrow.tsx rename to src/renderer/src/components/tooltip-old/Arrow.tsx diff --git a/src/renderer/src/components/tooltip/Tooltip.styles.ts b/src/renderer/src/components/tooltip-old/Tooltip.styles.ts similarity index 100% rename from src/renderer/src/components/tooltip/Tooltip.styles.ts rename to src/renderer/src/components/tooltip-old/Tooltip.styles.ts diff --git a/src/renderer/src/components/tooltip/index.tsx b/src/renderer/src/components/tooltip-old/index.tsx similarity index 100% rename from src/renderer/src/components/tooltip/index.tsx rename to src/renderer/src/components/tooltip-old/index.tsx diff --git a/src/renderer/src/components/ui/tooltip.tsx b/src/renderer/src/components/ui/tooltip.tsx new file mode 100644 index 00000000..537cf185 --- /dev/null +++ b/src/renderer/src/components/ui/tooltip.tsx @@ -0,0 +1,50 @@ +import { css, cx } from "@/styled/css"; +import * as TooltipPrimitive from "@radix-ui/react-tooltip"; +import type { ComponentPropsWithoutRef } from "react"; + +const TooltipProvider = TooltipPrimitive.Provider; +const Tooltip = TooltipPrimitive.Root; +const TooltipTrigger = TooltipPrimitive.Trigger; + +const contentStyles = css({ + zIndex: 50, + bg: "bg.primary", + rounded: "md", + boxShadow: "[0px 0px 15px 0px #00000026]", + + "&[data-state='delayed-open']": { + animation: "fadeIn", + }, + "&[data-state='closed']": { + animation: "fadeOut", + }, +}); + +const arrowStyles = css({ + fill: "bg.primary", +}); + +function TooltipContent({ + className, + sideOffset = 6, + showArrow = true, + children, + ...props +}: ComponentPropsWithoutRef & { + showArrow?: boolean; +}) { + return ( + + + {children} + {showArrow && } + + + ); +} + +export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }; From 5a02a5dfc57c9c81c5b50c0e3cec625c70bdfae4 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 21 Feb 2026 13:11:22 -0300 Subject: [PATCH 042/263] chore: flag card as deprecated --- src/renderer/src/components/{card => card-old}/index.tsx | 3 +++ 1 file changed, 3 insertions(+) rename src/renderer/src/components/{card => card-old}/index.tsx (93%) diff --git a/src/renderer/src/components/card/index.tsx b/src/renderer/src/components/card-old/index.tsx similarity index 93% rename from src/renderer/src/components/card/index.tsx rename to src/renderer/src/components/card-old/index.tsx index 721a1d96..87a81176 100644 --- a/src/renderer/src/components/card/index.tsx +++ b/src/renderer/src/components/card-old/index.tsx @@ -1,5 +1,8 @@ import { styled } from "@/styles"; +/** + * @deprecated + */ const Card = styled("div", { display: "flex", flexDirection: "column", From 41a158c3788cb7a8153a41f4f3a480512f8b67cc Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 21 Feb 2026 13:21:58 -0300 Subject: [PATCH 043/263] chore: create modern ui components --- .../src/components/brand/built-by.tsx | 23 +++ src/renderer/src/components/button.tsx | 133 ------------ src/renderer/src/components/dialog/index.tsx | 2 +- src/renderer/src/components/drop-area.tsx | 148 ++++++++++++++ src/renderer/src/components/feature-icon.tsx | 65 ++++++ src/renderer/src/components/features-menu.tsx | 42 ++++ .../src/components/home/card-tool.tsx | 92 --------- .../src/components/home/connect-to-host.tsx | 7 +- src/renderer/src/components/home/stepper.tsx | 90 +++++++++ .../src/components/how-it-works-modal.tsx | 72 +++++++ src/renderer/src/components/how-it-works.tsx | 109 ++++++++++ src/renderer/src/components/index.ts | 6 +- src/renderer/src/components/input.tsx | 191 ------------------ src/renderer/src/components/layout/footer.tsx | 3 + .../src/components/layout/main-content.tsx | 14 +- .../src/components/section-title/index.tsx | 3 + src/renderer/src/components/ui/dialog.tsx | 88 ++++++++ 17 files changed, 659 insertions(+), 429 deletions(-) create mode 100644 src/renderer/src/components/brand/built-by.tsx delete mode 100644 src/renderer/src/components/button.tsx create mode 100644 src/renderer/src/components/drop-area.tsx create mode 100644 src/renderer/src/components/feature-icon.tsx create mode 100644 src/renderer/src/components/features-menu.tsx delete mode 100644 src/renderer/src/components/home/card-tool.tsx create mode 100644 src/renderer/src/components/home/stepper.tsx create mode 100644 src/renderer/src/components/how-it-works-modal.tsx create mode 100644 src/renderer/src/components/how-it-works.tsx delete mode 100644 src/renderer/src/components/input.tsx create mode 100644 src/renderer/src/components/ui/dialog.tsx diff --git a/src/renderer/src/components/brand/built-by.tsx b/src/renderer/src/components/brand/built-by.tsx new file mode 100644 index 00000000..b9717ff2 --- /dev/null +++ b/src/renderer/src/components/brand/built-by.tsx @@ -0,0 +1,23 @@ +import { DATAGENERO_URL } from "@/constants"; +import { styled } from "@/styled/jsx"; +import { type StackStyles, stack } from "@/styled/patterns"; + +interface BuiltByProps { + size?: number; + gap?: StackStyles["gap"]; +} +export default function BuiltBy({ size = 150, gap = "2" }: BuiltByProps) { + return ( + + + Plataforma hecha por + + DataGenero isologo + + ); +} diff --git a/src/renderer/src/components/button.tsx b/src/renderer/src/components/button.tsx deleted file mode 100644 index 6ed89d71..00000000 --- a/src/renderer/src/components/button.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import { type RecipeVariantProps, css, cva } from "@/styled/css"; -import { CircleNotch } from "phosphor-react"; -import type { ButtonHTMLAttributes } from "react"; - -const button = cva({ - base: { - display: "flex", - flexDir: "row", - gap: "1", // 4px - justifyContent: "center", - alignSelf: "stretch", - alignItems: "center", - - transitionProperty: "[background-color, color, box-shadow]", - transitionDuration: "slow", // 300ms - transitionTimingFunction: "default", - - rounded: "sm", // 4px - border: "none", - - textStyle: "cta.md.strong", - - cursor: "pointer", - - "&:disabled": { - cursor: "not-allowed", - }, - }, - variants: { - variant: { - primary: { - bg: "action.default", - color: "text.onbutton-default", - - "&:hover:enabled": { - bg: "action.hover", - color: "text.onbutton-alternative", - }, - - "&:active:enabled": { - bg: "action.pressed", - color: "text.onbutton-alternative", - }, - - "&:focus:enabled": { - bg: "action.focus", - outline: "primary-alt", - outlineWidth: "[2px]", - boxShadow: "[0px 0px 10px rgba(17, 0, 65, 0.2)]", - }, - - "&:disabled": { - bg: "action.disabled", - color: "text.onbutton-default", - }, - }, - secondary: { - color: "text.onbutton-default", - bg: "bg.secondary", - - borderWidth: "[2px]", - borderStyle: "solid", - borderColor: "action.alt-default", - - "&:hover:enabled": { - color: "text.onbutton-default", - bg: "bg.secondary", - borderColor: "action.hover", - }, - - "&:active:enabled": { - color: "text.onbutton-alternative", - bg: "action.pressed", - borderColor: "action.pressed", - }, - - "&:focus:enabled": { - boxShadow: "[0px 0px 10px rgba(17, 0, 65, 0.2)]", - outline: "primary-alt", - outlineWidth: "[2px]", - bg: "bg.secondary", - }, - - "&:disabled": { - color: "text.onbutton-disabled", - bg: "bg.secondary", - borderColor: "action.disabled", - }, - }, - tertiary: { - // TODO: not implemented - }, - }, - size: { - md: { height: "12", padding: "4" }, - sm: { height: "8", py: "2", px: "4" }, - }, - }, - defaultVariants: { - size: "md", - variant: "primary", - }, -}); - -type ButtonProps = RecipeVariantProps & - ButtonHTMLAttributes & { - isLoading?: boolean; - }; - -function Button({ - size, - variant, - isLoading, - disabled, - children, - ...props -}: ButtonProps) { - return ( - - ); -} - -export default Button; diff --git a/src/renderer/src/components/dialog/index.tsx b/src/renderer/src/components/dialog/index.tsx index 3d2f2bcc..16c2539c 100644 --- a/src/renderer/src/components/dialog/index.tsx +++ b/src/renderer/src/components/dialog/index.tsx @@ -1,7 +1,7 @@ import { styled } from "@/styles"; import { X } from "phosphor-react"; import type { FC, ReactNode } from "react"; -import Button from "../button"; +import Button from "../ui/button"; export interface DialogOption { id: string; diff --git a/src/renderer/src/components/drop-area.tsx b/src/renderer/src/components/drop-area.tsx new file mode 100644 index 00000000..02eae626 --- /dev/null +++ b/src/renderer/src/components/drop-area.tsx @@ -0,0 +1,148 @@ +import { WHITELISTED_EXTENSIONS } from "@/constants"; +import { css, cva } from "@/styled/css"; +import { Stack, styled } from "@/styled/jsx"; +import { File } from "phosphor-react"; +import { useCallback, useRef, useState } from "react"; + +function FileIcon() { + return ( + + + + ); +} + +const styles = cva({ + base: { + display: "flex", + flexDirection: "column", + alignItems: "center", + justifyContent: "center", + gap: "8", + + w: "full", + h: "[335px]", + p: "8", + + rounded: "sm", + border: "primary", + + bg: "[#F3F4FF]", + cursor: "pointer", + + transitionProperty: "[border-color, background-color, box-shadow]", + transitionTimingFunction: "default", + transitionDuration: "normal", + }, + variants: { + dragging: { + true: { + borderColor: "brand.primary", + bg: "bg.primary-alternative", + boxShadow: "[0px 0px 15px 0px #3F479D66]", + }, + }, + }, +}); + +interface DropAreaProps { + onDropFiles: (files: File[]) => void; + multiple?: boolean; +} + +export default function DropArea({ + onDropFiles, + multiple = true, +}: DropAreaProps) { + const [dragging, setDragging] = useState(false); + const inputRef = useRef(null); + const dragCounter = useRef(0); + + const accept = WHITELISTED_EXTENSIONS.map((ext) => `.${ext}`).join(","); + + const handleFiles = useCallback( + (fileList: FileList) => { + const files = Array.from(fileList).filter((file) => { + const ext = file.name.split(".").pop()?.toLowerCase(); + return ext && WHITELISTED_EXTENSIONS.includes(ext); + }); + if (files.length > 0) onDropFiles(files); + }, + [onDropFiles], + ); + + const handleDragEnter = useCallback((e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + dragCounter.current++; + setDragging(true); + }, []); + + const handleDragLeave = useCallback((e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + dragCounter.current--; + if (dragCounter.current === 0) setDragging(false); + }, []); + + const handleDragOver = useCallback((e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + }, []); + + const handleDrop = useCallback( + (e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + dragCounter.current = 0; + setDragging(false); + if (e.dataTransfer.files.length > 0) { + handleFiles(e.dataTransfer.files); + } + }, + [handleFiles], + ); + + const handleClick = () => inputRef.current?.click(); + + const handleChange: React.ChangeEventHandler = (e) => { + if (e.target.files) handleFiles(e.target.files); + }; + + return ( +
+ + + + Selecciona el archivo para +
+ agregar a la base de datos +
+ + Formatos válidos:{" "} + {WHITELISTED_EXTENSIONS.map((e) => `.${e}`).join(", ")} + +
+ +
+ ); +} diff --git a/src/renderer/src/components/feature-icon.tsx b/src/renderer/src/components/feature-icon.tsx new file mode 100644 index 00000000..5546851f --- /dev/null +++ b/src/renderer/src/components/feature-icon.tsx @@ -0,0 +1,65 @@ +import { FEATURES } from "@/constants"; +import { cva } from "@/styled/css"; +import { stack } from "@/styled/patterns"; +import type { FeatureFlowEnum } from "@/types/features"; +import type { Icon } from "phosphor-react"; + +const styles = cva({ + base: { + ...stack.raw({ align: "center", justify: "center" }), + p: "4", + borderRadius: "[14px]", + }, + variants: { + disabled: { + true: { + bg: "bg.secondary", + color: "text.lighter", + }, + false: { + color: "text.default", + bg: "bg.primary-alternative", + }, + }, + size: { + lg: { + width: "[70px]", + height: "[70px]", + p: "[14px]", + rounded: "[14px]", + }, + sm: { + width: "10", + height: "10", + p: "2", + rounded: "lg", + }, + }, + }, + defaultVariants: { + disabled: false, + size: "lg", + }, +}); + +type FeatureIconProps = { + size: "lg" | "sm"; + disabled?: boolean; +} & ( + | { feature: FeatureFlowEnum; icon?: never } + | { feature?: never; icon: Icon } +); + +export default function FeatureIcon({ + feature, + size, + icon: OverrideIcon, + disabled = false, +}: FeatureIconProps) { + const Icon = OverrideIcon ?? FEATURES[feature].icon; + return ( +
+ +
+ ); +} diff --git a/src/renderer/src/components/features-menu.tsx b/src/renderer/src/components/features-menu.tsx new file mode 100644 index 00000000..e10d479d --- /dev/null +++ b/src/renderer/src/components/features-menu.tsx @@ -0,0 +1,42 @@ +import { FEATURES } from "@/constants"; +import { Grid, Stack, styled } from "@/styled/jsx"; +import type { FeatureFlowEnum } from "@/types/features"; +import { Link } from "@tanstack/react-router"; +import { DotsNine } from "phosphor-react"; +import FeatureIcon from "./feature-icon"; +import Button from "./ui/button"; +import Card from "./ui/card"; +import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover"; + +export default function FeaturesMenu() { + const features = Object.entries(FEATURES); + return ( + + + + + + + {features.map(([value, feature]) => ( + + + + + + {feature.title} + + + + + ))} + + + + ); +} diff --git a/src/renderer/src/components/home/card-tool.tsx b/src/renderer/src/components/home/card-tool.tsx deleted file mode 100644 index fe39adb8..00000000 --- a/src/renderer/src/components/home/card-tool.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { cx, sva } from "@/styled/css"; -import { Stack, styled } from "@/styled/jsx"; -import { stack } from "@/styled/patterns"; -import { Link, type LinkComponentProps } from "@tanstack/react-router"; -import type { Icon } from "phosphor-react"; - -const card = sva({ - className: "card-tool", - slots: ["container", "icon"], - base: { - container: { - ...stack.raw({ gap: "4", align: "start" }), - padding: "8", - rounded: "sm", - - transitionProperty: "[border, box-shadow]", - transitionTimingFunction: "default", - transitionDuration: "normal", - }, - icon: { - p: "4", - borderRadius: "[14px]", - }, - }, - variants: { - disabled: { - true: { - container: { - border: "primary", - bg: "bg.primary", - cursor: "not-allowed", - color: "text.lighter", - }, - icon: { - bg: "bg.secondary", - }, - }, - false: { - container: { - border: "primary", - bg: "bg.secondary", - cursor: "pointer", - - "&:hover": { - border: "primary-alt", - boxShadow: "[0px 0px 15px 0px #3F479D66]", - }, - }, - icon: { - bg: "bg.primary-alternative", - }, - }, - }, - }, - defaultVariants: { - disabled: false, - }, -}); - -interface CardToolProps extends LinkComponentProps { - title: string; - subtitle: string; - icon: Icon; - disabled?: boolean; -} -export default function CardTool({ - title, - subtitle, - icon: Icon, - disabled = false, - className, - ...props -}: CardToolProps) { - const classes = card({ disabled }); - return ( - -
- -
- - {title} - - {subtitle} - - - - ); -} diff --git a/src/renderer/src/components/home/connect-to-host.tsx b/src/renderer/src/components/home/connect-to-host.tsx index a524e8d7..b1bdb444 100644 --- a/src/renderer/src/components/home/connect-to-host.tsx +++ b/src/renderer/src/components/home/connect-to-host.tsx @@ -7,8 +7,8 @@ import { AxiosError } from "axios"; import { ArrowLeft } from "phosphor-react"; import { type ChangeEventHandler, useState } from "react"; import { ZodError } from "zod"; -import Button from "../button"; -import Input from "../input"; +import Button from "../ui/button"; +import Input from "../ui/input"; const BackButton = ({ onClick }: { onClick: () => void }) => ( + + + ¿Cómo funciona? + + + + + ¿Cómo funciona? + + + + + } + feature={feature} + /> + + + + ); +} diff --git a/src/renderer/src/components/how-it-works.tsx b/src/renderer/src/components/how-it-works.tsx new file mode 100644 index 00000000..9e619fe4 --- /dev/null +++ b/src/renderer/src/components/how-it-works.tsx @@ -0,0 +1,109 @@ +import { SectionTitle } from "@/layout/section-title"; +import { css } from "@/styled/css"; +import { Grid, Stack, styled } from "@/styled/jsx"; +import { hstack, stack } from "@/styled/patterns"; +import { FeatureFlowEnum } from "@/types/features"; + +const card = css({ + ...hstack.raw({ gap: "4", alignItems: "center" }), + + bg: "bg.secondary", + border: "primary", + rounded: "sm", + + px: "4", + py: "6", +}); + +const stepStyle = css({ + ...stack.raw({ align: "center", justify: "center" }), + + bg: "action.alt-default", + color: "text.onbutton-alternative", + rounded: "full", + textStyle: "cta.md.strong", + + width: "9", + height: "9", +}); + +interface CardProps { + img: string; + imgAlt: string; + step: number; + title: string; + subtitle: string; +} +function Card({ img, imgAlt, step, title, subtitle }: CardProps) { + return ( +
+ {imgAlt} + +

{step}

+ + {title} + {subtitle} + +
+
+ ); +} + +interface HowItWorksProps { + title?: React.ReactNode; + feature: FeatureFlowEnum; +} +export default function HowItWorks({ + title = "¿Cómo funciona?", + feature, +}: HowItWorksProps) { + const renderTitle = + typeof title === "string" ? {title} : title; + + return ( + + {renderTitle} + + + + + {/* Last step depends on the feature we're seeing */} + {feature === FeatureFlowEnum.Dataset ? ( + + ) : ( + + )} + + + ); +} diff --git a/src/renderer/src/components/index.ts b/src/renderer/src/components/index.ts index 440965de..3622ebad 100644 --- a/src/renderer/src/components/index.ts +++ b/src/renderer/src/components/index.ts @@ -1,6 +1,5 @@ export { default as Arrow } from "./arrow"; -export { default as Button } from "./button"; -export { default as Card } from "./card"; +export { default as Card } from "./card-old"; export { Checkbox, CheckboxGroup } from "./checkbox"; export { default as DecisionTabs } from "./decision-tabs"; export { default as FileAnnotator } from "./file-annotator"; @@ -29,7 +28,8 @@ export { default as Text } from "./text"; export { default as ThemeProvider } from "./theme-provider"; export { default as Title } from "./title"; export { default as Toast } from "./toast"; -export { default as Tooltip } from "./tooltip"; +export { default as Tooltip } from "./tooltip-old"; +export { default as Button } from "./ui/button"; export { default as Input } from "./uncontrolled-input"; export { ValidateDataset } from "./validate-dataset"; export { default as ValidationForm } from "./validation-form"; diff --git a/src/renderer/src/components/input.tsx b/src/renderer/src/components/input.tsx deleted file mode 100644 index 4eecdc3f..00000000 --- a/src/renderer/src/components/input.tsx +++ /dev/null @@ -1,191 +0,0 @@ -import { useId } from "react"; - -import { cva, sva } from "@/styled/css"; -import { hstack, stack } from "@/styled/patterns"; -import { WarningCircle } from "phosphor-react"; - -const input = sva({ - slots: ["container", "inputBox", "input", "label", "errorMessage", "helper"], - base: { - container: stack.raw({ gap: "1", width: "full" }), - inputBox: { - ...hstack.raw({ alignItems: "center", gap: "1" }), - - rounded: "sm", - border: "primary", - - "&:focus-within": { - outline: "none", - boxShadow: "[0px 2px 2px rgba(0, 0, 0, 0.16)]", - }, - }, - input: { - textStyle: "label.md.default", - border: "none", - outline: "none", - flex: "[1]", - - p: "3", - - "&::placeholder": { - color: "text.lighter", - }, - }, - label: { textStyle: "label.sm.default" }, - errorMessage: { - ...hstack.raw({ gap: "1" }), - textStyle: "label.sm.default", - color: "system.error", - }, - helper: { - textStyle: "label.sm.default", - color: "text.lighter", - }, - }, - variants: { - disabled: { - true: { - inputBox: { - bg: "bg.primary", - border: "primary", - color: "text.lighter", - cursor: "not-allowed", - }, - input: { - cursor: "not-allowed", - }, - }, - false: { - inputBox: { - bg: "white", - }, - }, - }, - error: { - true: { - container: { - color: "system.error", - }, - inputBox: { - border: "error", - }, - input: { - // "&::placeholder": { - // color: "system.error-secondary", - // }, - }, - label: { color: "system.error" }, - }, - false: {}, - }, - }, - defaultVariants: { - error: false, - disabled: false, - }, -}); - -const affix = cva({ - base: { - ...hstack.raw({ alignItems: "center", gap: "1" }), - userSelect: "none", - textStyle: "label.md.default", - // py: "3", - }, - variants: { - position: { - prefix: { pl: "3", mr: "-3" }, - suffix: { pr: "3", ml: "-3" }, - }, - }, -}); - -interface InputProps { - // Rendering - label?: string; - placeholder?: string; - prefix?: string; - suffix?: string; - suggestion?: string; - helper?: string; - // Control - id?: string; - value: string; - onChange?: React.ChangeEventHandler; - disabled?: boolean; - error?: string | null; - type?: "text" | "number"; -} -export default function Input({ - // Rendering - label, - placeholder, - prefix, - suffix, - suggestion, - helper, - // Control - id, - value, - onChange, - disabled = false, - error, - type, -}: InputProps) { - const randomId = useId(); - const inputId = id ?? randomId; - const errorMessageId = `${inputId}-error`; - - const classes = input({ disabled, error: !!error }); - - return ( -
- {label && ( - - )} - -
- {prefix && ( -
- {prefix} - {/* In the designs this vertical bar is defined as a Text, but it's - not. Use a Label instead */} - | -
- )} - - - - {suffix && ( -
- {/* In the designs this vertical bar is defined as a Text, but it's - not. Use a Label instead */} - | - {suffix} -
- )} -
- - {helper && !error &&

{helper}

} - {error && ( - - )} -
- ); -} diff --git a/src/renderer/src/components/layout/footer.tsx b/src/renderer/src/components/layout/footer.tsx index 28ab5f6c..a25d9170 100644 --- a/src/renderer/src/components/layout/footer.tsx +++ b/src/renderer/src/components/layout/footer.tsx @@ -4,6 +4,7 @@ import BuiltBy from "../brand/built-by"; const content = css({ display: "flex", flexDirection: "row", + alignItems: "center", borderTop: "primary", px: "12", @@ -11,6 +12,8 @@ const content = css({ }); const childrenContainer = css({ flex: "1", + display: "flex", + justifyContent: "flex-end", }); interface FooterProps { diff --git a/src/renderer/src/components/layout/main-content.tsx b/src/renderer/src/components/layout/main-content.tsx index 097353ae..8d3d6b3f 100644 --- a/src/renderer/src/components/layout/main-content.tsx +++ b/src/renderer/src/components/layout/main-content.tsx @@ -1,11 +1,11 @@ import { cva } from "@/styled/css"; +import { stack } from "@/styled/patterns"; const content = cva({ base: { flex: "1", width: "full", - height: "full", bg: "bg.primary", }, @@ -13,14 +13,14 @@ const content = cva({ full: { true: {}, false: { - display: "flex", - flexDir: "column", - alignItems: "center", - pt: "28", + ...stack.raw({ align: "center", gap: "0" }), + + pt: "16", + px: "8", "& > div.spacing": { - width: "5xl", - mx: "8", + width: "full", + maxWidth: "5xl", }, }, }, diff --git a/src/renderer/src/components/section-title/index.tsx b/src/renderer/src/components/section-title/index.tsx index 7d849a04..0f4eb4ad 100644 --- a/src/renderer/src/components/section-title/index.tsx +++ b/src/renderer/src/components/section-title/index.tsx @@ -6,6 +6,9 @@ interface Props { children: ReactNode; onClick?: MouseEventHandler; } +/** + * @deprecated in favor of `@/components/layout/section-title` + */ export default function SectionTitle({ children, onClick }: Props) { return ( diff --git a/src/renderer/src/components/ui/dialog.tsx b/src/renderer/src/components/ui/dialog.tsx new file mode 100644 index 00000000..5449a6b1 --- /dev/null +++ b/src/renderer/src/components/ui/dialog.tsx @@ -0,0 +1,88 @@ +import { css, cx } from "@/styled/css"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; +import type { ComponentPropsWithoutRef } from "react"; + +const Dialog = DialogPrimitive.Root; +const DialogTrigger = DialogPrimitive.Trigger; +const DialogClose = DialogPrimitive.Close; +const DialogTitle = DialogPrimitive.Title; +const DialogDescription = DialogPrimitive.Description; + +const overlayStyles = css({ + position: "fixed", + inset: "[0]", + zIndex: 50, + bg: "[rgba(0, 0, 0, 0.5)]", + + "&[data-state='open']": { + animation: "fadeIn", + }, + "&[data-state='closed']": { + animation: "fadeOut", + }, +}); + +const contentStyles = css({ + position: "fixed", + inset: "[0]", + margin: "auto", + zIndex: 50, + + bg: "bg.secondary", + rounded: "lg", + p: "6", + boxShadow: "[0px 0px 15px 0px #00000026]", + + width: "[90vw]", + h: "[fit-content]", + + "&[data-state='open']": { + animation: "fadeIn", + }, + "&[data-state='closed']": { + animation: "fadeOut", + }, +}); + +function DialogOverlay({ + className, + ...props +}: ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>) { + return ( + <DialogPrimitive.Overlay + className={cx(overlayStyles, className)} + {...props} + /> + ); +} + +function DialogContent({ + className, + container, + children, + ...props +}: ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & { + container?: HTMLElement; +}) { + return ( + <DialogPrimitive.Portal container={container}> + <DialogOverlay /> + <DialogPrimitive.Content + className={cx(contentStyles, className)} + {...props} + > + {children} + </DialogPrimitive.Content> + </DialogPrimitive.Portal> + ); +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogOverlay, + DialogTitle, + DialogTrigger, +}; From f6f7fac8970d4fd7659b2d731569f460d044843a Mon Sep 17 00:00:00 2001 From: AymurAI Frontend <front-end@datagenero.org> Date: Sat, 21 Feb 2026 13:31:10 -0300 Subject: [PATCH 044/263] fix: remove fadeIn scaling animation --- panda.config.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/panda.config.ts b/panda.config.ts index 437d9784..72f545b2 100644 --- a/panda.config.ts +++ b/panda.config.ts @@ -109,12 +109,12 @@ export default defineConfig({ extend: { keyframes: { fadeIn: { - from: { opacity: "0", transform: "scale(0.96)" }, - to: { opacity: "1", transform: "scale(1)" }, + from: { opacity: "0" }, + to: { opacity: "1" }, }, fadeOut: { - from: { opacity: "1", transform: "scale(1)" }, - to: { opacity: "0", transform: "scale(0.96)" }, + from: { opacity: "1" }, + to: { opacity: "0" }, }, }, tokens: { From 3b79f3915def83e5b08643f0c253f3b3f07b260d Mon Sep 17 00:00:00 2001 From: AymurAI Frontend <front-end@datagenero.org> Date: Sat, 21 Feb 2026 13:32:11 -0300 Subject: [PATCH 045/263] build: update react and add radix dependencies --- package.json | 15 +- pnpm-lock.yaml | 1082 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 770 insertions(+), 327 deletions(-) diff --git a/package.json b/package.json index 44ae4f0a..aec1fb56 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,9 @@ "@electron-forge/maker-zip": "^6.0.4", "@electron-toolkit/tsconfig": "^1.0.1", "@pandacss/dev": "^1.8.1", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-tooltip": "^1.2.8", "@stitches/react": "^1.2.8", "@tanstack/react-form": "1.11.0", "@tanstack/react-query": "^5.81.1", @@ -50,14 +53,14 @@ "@tanstack/react-router-devtools": "^1.139.12", "@tanstack/router-plugin": "^1.139.12", "@types/node": "20", - "@types/react": "18", - "@types/react-dom": "18", + "@types/react": "19", + "@types/react-dom": "19", "@types/regex-escape": "^3.4.1", "@vitejs/plugin-react": "^4.5.0", - "axios": "^1.1.3", + "axios": "^1.12.0", "concurrently": "^7.5.0", "cross-env": "^7.0.3", - "electron": "^21.2.0", + "electron": "^22.3.25", "electron-builder": "^26.0.12", "electron-debug": "^3.2.0", "electron-devtools-installer": "^3.2.1", @@ -69,8 +72,8 @@ "nodemon": "^2.0.20", "phosphor-react": "^1.4.1", "prettier": "^2.7.1", - "react": "18", - "react-dom": "18", + "react": "19", + "react-dom": "19", "regex-escape": "^3.4.10", "typescript": "^5.9.2", "vite": "^6.3.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6bafa6f9..d5c8f984 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,10 +10,10 @@ importers: dependencies: '@electron-toolkit/preload': specifier: ^3.0.2 - version: 3.0.2(electron@21.4.4) + version: 3.0.2(electron@22.3.27) '@electron-toolkit/utils': specifier: ^4.0.0 - version: 4.0.0(electron@21.4.4) + version: 4.0.0(electron@22.3.27) electron-squirrel-startup: specifier: ^1.0.0 version: 1.0.1 @@ -42,33 +42,42 @@ importers: '@pandacss/dev': specifier: ^1.8.1 version: 1.8.1(hono@4.11.7)(typescript@5.9.2) + '@radix-ui/react-dialog': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-popover': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-tooltip': + specifier: ^1.2.8 + version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@stitches/react': specifier: ^1.2.8 - version: 1.2.8(react@18.3.1) + version: 1.2.8(react@19.2.4) '@tanstack/react-form': specifier: 1.11.0 - version: 1.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.11.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-query': specifier: ^5.81.1 - version: 5.81.1(react@18.3.1) + version: 5.81.1(react@19.2.4) '@tanstack/react-router': specifier: ^1.139.12 - version: 1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-router-devtools': specifier: ^1.139.12 - version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(lightningcss@1.30.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(solid-js@1.9.10)(tsx@4.20.6) + version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(lightningcss@1.30.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(tsx@4.20.6) '@tanstack/router-plugin': specifier: ^1.139.12 - version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6)) + version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6)) '@types/node': specifier: '20' version: 20.19.1 '@types/react': - specifier: '18' - version: 18.3.22 + specifier: '19' + version: 19.2.13 '@types/react-dom': - specifier: '18' - version: 18.3.7(@types/react@18.3.22) + specifier: '19' + version: 19.2.3(@types/react@19.2.13) '@types/regex-escape': specifier: ^3.4.1 version: 3.4.1 @@ -76,8 +85,8 @@ importers: specifier: ^4.5.0 version: 4.5.0(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6)) axios: - specifier: ^1.1.3 - version: 1.9.0 + specifier: ^1.12.0 + version: 1.13.4 concurrently: specifier: ^7.5.0 version: 7.6.0 @@ -85,8 +94,8 @@ importers: specifier: ^7.0.3 version: 7.0.3 electron: - specifier: ^21.2.0 - version: 21.4.4 + specifier: ^22.3.25 + version: 22.3.27 electron-builder: specifier: ^26.0.12 version: 26.0.12(electron-builder-squirrel-windows@26.0.12) @@ -116,16 +125,16 @@ importers: version: 2.0.22 phosphor-react: specifier: ^1.4.1 - version: 1.4.1(react@18.3.1) + version: 1.4.1(react@19.2.4) prettier: specifier: ^2.7.1 version: 2.8.8 react: - specifier: '18' - version: 18.3.1 + specifier: '19' + version: 19.2.4 react-dom: - specifier: '18' - version: 18.3.1(react@18.3.1) + specifier: '19' + version: 19.2.4(react@19.2.4) regex-escape: specifier: ^3.4.10 version: 3.4.11 @@ -143,7 +152,7 @@ importers: version: 4.0.14 zustand: specifier: ^5.0.7 - version: 5.0.7(@types/react@18.3.22)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + version: 5.0.7(@types/react@19.2.13)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)) packages: @@ -509,10 +518,6 @@ packages: resolution: {integrity: sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==} hasBin: true - '@electron/get@1.14.1': - resolution: {integrity: sha512-BrZYyL/6m0ZXz/lDxy/nlVhQz+WF+iPS6qXolEU8atw7h6v1aYkjwJZ63m+bJMBTxDE66X+r2tPS4a/8C82sZw==} - engines: {node: '>=8.6'} - '@electron/get@2.0.3': resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==} engines: {node: '>=12'} @@ -720,6 +725,21 @@ packages: '@fast-csv/parse@4.3.6': resolution: {integrity: sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==} + '@floating-ui/core@1.7.4': + resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==} + + '@floating-ui/dom@1.7.5': + resolution: {integrity: sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==} + + '@floating-ui/react-dom@2.1.7': + resolution: {integrity: sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@gar/promisify@1.1.3': resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} @@ -868,6 +888,263 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.15': + resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.11': + resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.3': + resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.7': + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-popover@1.1.15': + resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.2.8': + resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-tooltip@1.2.8': + resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.2.3': + resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@rolldown/pluginutils@1.0.0-beta.9': resolution: {integrity: sha512-e9MeMtVWo186sgvFFJOPGy7/d2j2mZhLJIdVW0C/xDluuOvymEATqz6zKsP0ZmXGzQtqlyjz5sC1sYQUoJG98w==} @@ -1090,10 +1367,6 @@ packages: '@sideway/pinpoint@2.0.0': resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} - '@sindresorhus/is@0.14.0': - resolution: {integrity: sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==} - engines: {node: '>=6'} - '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} @@ -1103,10 +1376,6 @@ packages: peerDependencies: react: '>= 16.3.0' - '@szmarczak/http-timer@1.1.2': - resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==} - engines: {node: '>=6'} - '@szmarczak/http-timer@4.0.6': resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} @@ -1281,16 +1550,13 @@ packages: '@types/plist@3.0.5': resolution: {integrity: sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==} - '@types/prop-types@15.7.14': - resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==} - - '@types/react-dom@18.3.7': - resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: - '@types/react': ^18.0.0 + '@types/react': ^19.2.0 - '@types/react@18.3.22': - resolution: {integrity: sha512-vUhG0YmQZ7kL/tmKLrD3g5zXbXXreZXB3pmROW8bg3CnLnpjkRVwUlLne7Ufa2r9yJ8+/6B73RzhAek5TBKh2Q==} + '@types/react@19.2.13': + resolution: {integrity: sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==} '@types/regex-escape@3.4.1': resolution: {integrity: sha512-aQihdLwAzyST0/LTidv76ZKtltWbea61FprvpMHbqUToUpdZrSYUqPb3ToojMW2a29JfoJXBxtO6K5py4o8uwA==} @@ -1437,6 +1703,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + assert-plus@1.0.0: resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} engines: {node: '>=0.8'} @@ -1470,8 +1740,8 @@ packages: axios@0.25.0: resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==} - axios@1.9.0: - resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==} + axios@1.13.4: + resolution: {integrity: sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==} babel-dead-code-elimination@1.0.10: resolution: {integrity: sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA==} @@ -1581,10 +1851,6 @@ packages: resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} engines: {node: '>=10.6.0'} - cacheable-request@6.1.0: - resolution: {integrity: sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==} - engines: {node: '>=8'} - cacheable-request@7.0.4: resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} engines: {node: '>=8'} @@ -1734,9 +2000,6 @@ packages: confbox@0.2.2: resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} - config-chain@1.1.13: - resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} - config-file-ts@0.2.8-rc1: resolution: {integrity: sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==} @@ -1823,8 +2086,8 @@ packages: peerDependencies: postcss: ^8.4.32 - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} date-fns@2.30.0: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} @@ -1879,10 +2142,6 @@ packages: decode-formdata@0.9.0: resolution: {integrity: sha512-q5uwOjR3Um5YD+ZWPOF/1sGHVW9A5rCrRwITQChRXlmPkxDFBqCm4jNTIVdGHNH9OnR+V9MoZVgRhsFb+ARbUw==} - decompress-response@3.3.0: - resolution: {integrity: sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==} - engines: {node: '>=4'} - decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} @@ -1894,9 +2153,6 @@ packages: defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} - defer-to-connect@1.1.3: - resolution: {integrity: sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==} - defer-to-connect@2.0.1: resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} engines: {node: '>=10'} @@ -1921,6 +2177,9 @@ packages: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} @@ -1961,9 +2220,6 @@ packages: duplexer2@0.1.4: resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} - duplexer3@0.1.5: - resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==} - eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -2047,9 +2303,9 @@ packages: resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==} engines: {node: '>=8.0.0'} - electron@21.4.4: - resolution: {integrity: sha512-N5O7y7Gtt7mDgkJLkW49ETiT8M3myZ9tNIEvGTKhpBduX4WdgMj6c3hYeYBD6XW7SvbRkWEQaTl25RNday8Xpw==} - engines: {node: '>= 10.17.0'} + electron@22.3.27: + resolution: {integrity: sha512-7Rht21vHqj4ZFRnKuZdFqZFsvMBCmDqmjetiMqPtF+TmTBiGne1mnstVXOA/SRGhN2Qy5gY5bznJKpiqogjM8A==} + engines: {node: '>= 12.20.55'} hasBin: true emoji-regex@8.0.0: @@ -2058,10 +2314,6 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} @@ -2285,6 +2537,10 @@ packages: resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} engines: {node: '>= 6'} + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -2367,6 +2623,10 @@ packages: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + get-package-info@1.0.0: resolution: {integrity: sha512-SCbprXGAPdIhKAXiG+Mk6yeoFH61JlYunqdFQFHDtLjJlDjFf6x07dsS8acO+xWt52jpdVo49AlVDnUVK1sDNw==} engines: {node: '>= 4.0'} @@ -2418,7 +2678,7 @@ packages: glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me global-agent@3.0.0: resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} @@ -2432,10 +2692,6 @@ packages: resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} engines: {node: '>=0.10.0'} - global-tunnel-ng@2.7.1: - resolution: {integrity: sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==} - engines: {node: '>=0.10'} - globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -2457,10 +2713,6 @@ packages: resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} engines: {node: '>=10.19.0'} - got@9.6.0: - resolution: {integrity: sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==} - engines: {node: '>=8.6'} - graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -2727,9 +2979,6 @@ packages: engines: {node: '>=6'} hasBin: true - json-buffer@3.0.0: - resolution: {integrity: sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==} - json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -2772,9 +3021,6 @@ packages: keyboardevents-areequal@0.2.2: resolution: {integrity: sha512-Nv+Kr33T0mEjxR500q+I6IWisOQ0lK1GGOncV0kWE6n4KFmpcu7RUX5/2B0EUtX51Cb0HjZ9VJsSY3u4cBa0kw==} - keyv@3.1.0: - resolution: {integrity: sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==} - keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -2982,14 +3228,6 @@ packages: look-it-up@2.1.0: resolution: {integrity: sha512-nMoGWW2HurtuJf6XAL56FWTDCWLOTSsanrgwOyaR5Y4e3zfG5N/0cU5xWZSEU3tBxhQugRbV1xL9jb+ug7yZww==} - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - - lowercase-keys@1.0.1: - resolution: {integrity: sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==} - engines: {node: '>=0.10.0'} - lowercase-keys@2.0.0: resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} engines: {node: '>=8'} @@ -3251,18 +3489,10 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - normalize-url@4.5.1: - resolution: {integrity: sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==} - engines: {node: '>=8'} - normalize-url@6.1.0: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} engines: {node: '>=10'} - npm-conf@1.1.3: - resolution: {integrity: sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==} - engines: {node: '>=4'} - npm-run-path@2.0.2: resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} engines: {node: '>=4'} @@ -3309,10 +3539,6 @@ packages: outdent@0.8.0: resolution: {integrity: sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==} - p-cancelable@1.1.0: - resolution: {integrity: sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==} - engines: {node: '>=6'} - p-cancelable@2.1.1: resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} engines: {node: '>=8'} @@ -3478,10 +3704,6 @@ packages: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - pify@3.0.0: - resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} - engines: {node: '>=4'} - pkce-challenge@5.0.1: resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} engines: {node: '>=16.20.0'} @@ -3557,10 +3779,6 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - prepend-http@2.0.0: - resolution: {integrity: sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==} - engines: {node: '>=4'} - prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} @@ -3599,9 +3817,6 @@ packages: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} engines: {node: '>=10'} - proto-list@1.2.4: - resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} - proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -3642,17 +3857,47 @@ packages: resolution: {integrity: sha512-WRlRdY1qZbu1L11DklT07KuHfRk42l0NFFJdaExELEu4fEQ982bP5Z6OWGPj/wLLIuKRQDCxZJGAwoFsxhZhNA==} engines: {node: '>= 10.0.0'} - react-dom@18.3.1: - resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} peerDependencies: - react: ^18.3.1 + react: ^19.2.4 react-refresh@0.17.0: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} - react@18.3.1: - resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.2: + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} read-binary-file-arch@1.0.6: @@ -3727,9 +3972,6 @@ packages: engines: {node: '>= 0.4'} hasBin: true - responselike@1.0.2: - resolution: {integrity: sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==} - responselike@2.0.1: resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} @@ -3814,8 +4056,8 @@ packages: resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} engines: {node: '>=10'} - scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} semver-compare@1.0.0: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} @@ -4120,10 +4362,6 @@ packages: resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} engines: {node: '>=14.14'} - to-readable-stream@1.0.0: - resolution: {integrity: sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==} - engines: {node: '>=6'} - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -4187,10 +4425,6 @@ packages: engines: {node: '>=18.0.0'} hasBin: true - tunnel@0.0.6: - resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} - engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} - type-fest@0.13.1: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} @@ -4271,9 +4505,25 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - url-parse-lax@3.0.0: - resolution: {integrity: sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==} - engines: {node: '>=4'} + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true use-sync-external-store@1.5.0: resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} @@ -5085,17 +5335,17 @@ snapshots: - enquirer - supports-color - '@electron-toolkit/preload@3.0.2(electron@21.4.4)': + '@electron-toolkit/preload@3.0.2(electron@22.3.27)': dependencies: - electron: 21.4.4 + electron: 22.3.27 '@electron-toolkit/tsconfig@1.0.1(@types/node@20.19.1)': dependencies: '@types/node': 20.19.1 - '@electron-toolkit/utils@4.0.0(electron@21.4.4)': + '@electron-toolkit/utils@4.0.0(electron@22.3.27)': dependencies: - electron: 21.4.4 + electron: 22.3.27 '@electron/asar@3.2.18': dependencies: @@ -5115,21 +5365,6 @@ snapshots: fs-extra: 9.1.0 minimist: 1.2.8 - '@electron/get@1.14.1': - dependencies: - debug: 4.4.1 - env-paths: 2.2.1 - fs-extra: 8.1.0 - got: 9.6.0 - progress: 2.0.3 - semver: 6.3.1 - sumchecker: 3.0.1 - optionalDependencies: - global-agent: 3.0.0 - global-tunnel-ng: 2.7.1 - transitivePeerDependencies: - - supports-color - '@electron/get@2.0.3': dependencies: debug: 4.4.1 @@ -5366,6 +5601,23 @@ snapshots: lodash.isundefined: 3.0.1 lodash.uniq: 4.5.0 + '@floating-ui/core@1.7.4': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.5': + dependencies: + '@floating-ui/core': 1.7.4 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@floating-ui/dom': 1.7.5 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@floating-ui/utils@0.2.10': {} + '@gar/promisify@1.1.3': {} '@hapi/hoek@9.3.0': {} @@ -5676,6 +5928,244 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-context@1.1.2(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) + aria-hidden: 1.2.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-remove-scroll: 2.7.2(@types/react@19.2.13)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-id@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) + aria-hidden: 1.2.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-remove-scroll: 2.7.2(@types/react@19.2.13)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@floating-ui/react-dom': 2.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/rect': 1.1.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-slot@1.2.3(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/rect@1.1.1': {} + '@rolldown/pluginutils@1.0.0-beta.9': {} '@rollup/rollup-android-arm-eabi@4.41.1': @@ -5812,17 +6302,11 @@ snapshots: '@sideway/pinpoint@2.0.0': {} - '@sindresorhus/is@0.14.0': {} - '@sindresorhus/is@4.6.0': {} - '@stitches/react@1.2.8(react@18.3.1)': + '@stitches/react@1.2.8(react@19.2.4)': dependencies: - react: 18.3.1 - - '@szmarczak/http-timer@1.1.2': - dependencies: - defer-to-connect: 1.1.3 + react: 19.2.4 '@szmarczak/http-timer@4.0.6': dependencies: @@ -5836,27 +6320,27 @@ snapshots: '@tanstack/query-core@5.81.1': {} - '@tanstack/react-form@1.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tanstack/react-form@1.11.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@tanstack/form-core': 1.11.0 - '@tanstack/react-store': 0.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/react-store': 0.7.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) decode-formdata: 0.9.0 devalue: 5.1.1 - react: 18.3.1 + react: 19.2.4 transitivePeerDependencies: - react-dom - '@tanstack/react-query@5.81.1(react@18.3.1)': + '@tanstack/react-query@5.81.1(react@19.2.4)': dependencies: '@tanstack/query-core': 5.81.1 - react: 18.3.1 + react: 19.2.4 - '@tanstack/react-router-devtools@1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(lightningcss@1.30.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(solid-js@1.9.10)(tsx@4.20.6)': + '@tanstack/react-router-devtools@1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(lightningcss@1.30.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(tsx@4.20.6)': dependencies: - '@tanstack/react-router': 1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@tanstack/router-devtools-core': 1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(lightningcss@1.30.2)(solid-js@1.9.10)(tsx@4.20.6) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@tanstack/react-router': 1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-devtools-core': 1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(lightningcss@1.30.2)(solid-js@1.9.10)(tsx@4.20.6) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) vite: 7.2.4(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6) optionalDependencies: '@tanstack/router-core': 1.139.12 @@ -5875,30 +6359,30 @@ snapshots: - tsx - yaml - '@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@tanstack/history': 1.139.0 - '@tanstack/react-store': 0.8.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/react-store': 0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/router-core': 1.139.12 isbot: 5.1.32 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - '@tanstack/react-store@0.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tanstack/react-store@0.7.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@tanstack/store': 0.7.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - use-sync-external-store: 1.5.0(react@18.3.1) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.5.0(react@19.2.4) - '@tanstack/react-store@0.8.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tanstack/react-store@0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@tanstack/store': 0.8.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - use-sync-external-store: 1.6.0(react@18.3.1) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) '@tanstack/router-core@1.139.12': dependencies: @@ -5910,16 +6394,16 @@ snapshots: tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - '@tanstack/router-devtools-core@1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.1.3)(lightningcss@1.30.2)(solid-js@1.9.10)(tsx@4.20.6)': + '@tanstack/router-devtools-core@1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(lightningcss@1.30.2)(solid-js@1.9.10)(tsx@4.20.6)': dependencies: '@tanstack/router-core': 1.139.12 clsx: 2.1.1 - goober: 2.1.18(csstype@3.1.3) + goober: 2.1.18(csstype@3.2.3) solid-js: 1.9.10 tiny-invariant: 1.3.3 vite: 7.2.4(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6) optionalDependencies: - csstype: 3.1.3 + csstype: 3.2.3 transitivePeerDependencies: - '@types/node' - jiti @@ -5946,7 +6430,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.139.12(@tanstack/react-router@1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6))': + '@tanstack/router-plugin@1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) @@ -5963,7 +6447,7 @@ snapshots: unplugin: 2.3.11 zod: 3.25.76 optionalDependencies: - '@tanstack/react-router': 1.139.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/react-router': 1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) vite: 6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6) transitivePeerDependencies: - supports-color @@ -6059,16 +6543,13 @@ snapshots: xmlbuilder: 15.1.1 optional: true - '@types/prop-types@15.7.14': {} - - '@types/react-dom@18.3.7(@types/react@18.3.22)': + '@types/react-dom@19.2.3(@types/react@19.2.13)': dependencies: - '@types/react': 18.3.22 + '@types/react': 19.2.13 - '@types/react@18.3.22': + '@types/react@19.2.13': dependencies: - '@types/prop-types': 15.7.14 - csstype: 3.1.3 + csstype: 3.2.3 '@types/regex-escape@3.4.1': {} @@ -6141,7 +6622,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -6286,6 +6767,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + assert-plus@1.0.0: optional: true @@ -6311,10 +6796,10 @@ snapshots: transitivePeerDependencies: - debug - axios@1.9.0: + axios@1.13.4: dependencies: follow-redirects: 1.15.9 - form-data: 4.0.2 + form-data: 4.0.5 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug @@ -6476,16 +6961,6 @@ snapshots: cacheable-lookup@5.0.4: {} - cacheable-request@6.1.0: - dependencies: - clone-response: 1.0.3 - get-stream: 5.2.0 - http-cache-semantics: 4.2.0 - keyv: 3.1.0 - lowercase-keys: 2.0.0 - normalize-url: 4.5.1 - responselike: 1.0.2 - cacheable-request@7.0.4: dependencies: clone-response: 1.0.3 @@ -6643,12 +7118,6 @@ snapshots: confbox@0.2.2: {} - config-chain@1.1.13: - dependencies: - ini: 1.3.8 - proto-list: 1.2.4 - optional: true - config-file-ts@0.2.8-rc1: dependencies: glob: 10.4.5 @@ -6727,7 +7196,7 @@ snapshots: dependencies: postcss: 8.5.6 - csstype@3.1.3: {} + csstype@3.2.3: {} date-fns@2.30.0: dependencies: @@ -6759,10 +7228,6 @@ snapshots: decode-formdata@0.9.0: {} - decompress-response@3.3.0: - dependencies: - mimic-response: 1.0.1 - decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 @@ -6773,8 +7238,6 @@ snapshots: dependencies: clone: 1.0.4 - defer-to-connect@1.1.3: {} - defer-to-connect@2.0.1: {} define-data-property@1.1.4: @@ -6797,6 +7260,8 @@ snapshots: detect-libc@2.0.4: {} + detect-node-es@1.1.0: {} + detect-node@2.1.0: optional: true @@ -6857,8 +7322,6 @@ snapshots: dependencies: readable-stream: 2.3.8 - duplexer3@0.1.5: {} - eastasianwidth@0.2.0: {} ee-first@1.1.1: {} @@ -7036,9 +7499,9 @@ snapshots: transitivePeerDependencies: - supports-color - electron@21.4.4: + electron@22.3.27: dependencies: - '@electron/get': 1.14.1 + '@electron/get': 2.0.3 '@types/node': 16.18.126 extract-zip: 2.0.1 transitivePeerDependencies: @@ -7048,9 +7511,6 @@ snapshots: emoji-regex@9.2.2: {} - encodeurl@1.0.2: - optional: true - encodeurl@2.0.0: {} encoding@0.1.13: @@ -7332,6 +7792,14 @@ snapshots: es-set-tostringtag: 2.1.0 mime-types: 2.1.35 + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + forwarded@0.2.0: {} fresh@2.0.0: {} @@ -7431,6 +7899,8 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 + get-nonce@1.0.1: {} + get-package-info@1.0.0: dependencies: bluebird: 3.7.2 @@ -7527,14 +7997,6 @@ snapshots: is-windows: 1.0.2 which: 1.3.1 - global-tunnel-ng@2.7.1: - dependencies: - encodeurl: 1.0.2 - lodash: 4.17.21 - npm-conf: 1.1.3 - tunnel: 0.0.6 - optional: true - globals@11.12.0: {} globalthis@1.0.4: @@ -7543,9 +8005,9 @@ snapshots: gopd: 1.2.0 optional: true - goober@2.1.18(csstype@3.1.3): + goober@2.1.18(csstype@3.2.3): dependencies: - csstype: 3.1.3 + csstype: 3.2.3 gopd@1.2.0: {} @@ -7563,22 +8025,6 @@ snapshots: p-cancelable: 2.1.1 responselike: 2.0.1 - got@9.6.0: - dependencies: - '@sindresorhus/is': 0.14.0 - '@szmarczak/http-timer': 1.1.2 - '@types/keyv': 3.1.4 - '@types/responselike': 1.0.3 - cacheable-request: 6.1.0 - decompress-response: 3.3.0 - duplexer3: 0.1.5 - get-stream: 4.1.0 - lowercase-keys: 1.0.1 - mimic-response: 1.0.1 - p-cancelable: 1.1.0 - to-readable-stream: 1.0.0 - url-parse-lax: 3.0.0 - graceful-fs@4.2.11: {} has-flag@3.0.0: {} @@ -7628,7 +8074,7 @@ snapshots: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -7647,7 +8093,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -7805,8 +8251,6 @@ snapshots: jsesc@3.1.0: {} - json-buffer@3.0.0: {} - json-buffer@3.0.1: {} json-schema-traverse@0.4.1: {} @@ -7845,10 +8289,6 @@ snapshots: keyboardevents-areequal@0.2.2: {} - keyv@3.1.0: - dependencies: - json-buffer: 3.0.0 - keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -8036,12 +8476,6 @@ snapshots: look-it-up@2.1.0: {} - loose-envify@1.4.0: - dependencies: - js-tokens: 4.0.0 - - lowercase-keys@1.0.1: {} - lowercase-keys@2.0.0: {} lru-cache@10.4.3: {} @@ -8300,16 +8734,8 @@ snapshots: normalize-path@3.0.0: {} - normalize-url@4.5.1: {} - normalize-url@6.1.0: {} - npm-conf@1.1.3: - dependencies: - config-chain: 1.1.13 - pify: 3.0.0 - optional: true - npm-run-path@2.0.2: dependencies: path-key: 2.0.1 @@ -8357,8 +8783,6 @@ snapshots: outdent@0.8.0: {} - p-cancelable@1.1.0: {} - p-cancelable@2.1.1: {} p-defer@1.0.0: {} @@ -8456,9 +8880,9 @@ snapshots: perfect-debounce@1.0.0: {} - phosphor-react@1.4.1(react@18.3.1): + phosphor-react@1.4.1(react@19.2.4): dependencies: - react: 18.3.1 + react: 19.2.4 picocolors@1.1.1: {} @@ -8472,9 +8896,6 @@ snapshots: pify@2.3.0: {} - pify@3.0.0: - optional: true - pkce-challenge@5.0.1: {} pkg-dir@4.2.0: @@ -8551,8 +8972,6 @@ snapshots: commander: 9.5.0 optional: true - prepend-http@2.0.0: {} - prettier@2.8.8: {} prettier@3.2.5: {} @@ -8572,9 +8991,6 @@ snapshots: err-code: 2.0.3 retry: 0.12.0 - proto-list@1.2.4: - optional: true - proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -8612,17 +9028,41 @@ snapshots: dependencies: cross-spawn-windows-exe: 1.2.0 - react-dom@18.3.1(react@18.3.1): + react-dom@19.2.4(react@19.2.4): dependencies: - loose-envify: 1.4.0 - react: 18.3.1 - scheduler: 0.23.2 + react: 19.2.4 + scheduler: 0.27.0 react-refresh@0.17.0: {} - react@18.3.1: + react-remove-scroll-bar@2.3.8(@types/react@19.2.13)(react@19.2.4): dependencies: - loose-envify: 1.4.0 + react: 19.2.4 + react-style-singleton: 2.2.3(@types/react@19.2.13)(react@19.2.4) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.13 + + react-remove-scroll@2.7.2(@types/react@19.2.13)(react@19.2.4): + dependencies: + react: 19.2.4 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.13)(react@19.2.4) + react-style-singleton: 2.2.3(@types/react@19.2.13)(react@19.2.4) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.13)(react@19.2.4) + use-sidecar: 1.1.3(@types/react@19.2.13)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + + react-style-singleton@2.2.3(@types/react@19.2.13)(react@19.2.4): + dependencies: + get-nonce: 1.0.1 + react: 19.2.4 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.13 + + react@19.2.4: {} read-binary-file-arch@1.0.6: dependencies: @@ -8708,10 +9148,6 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - responselike@1.0.2: - dependencies: - lowercase-keys: 1.0.1 - responselike@2.0.1: dependencies: lowercase-keys: 2.0.0 @@ -8849,9 +9285,7 @@ snapshots: dependencies: xmlchars: 2.2.0 - scheduler@0.23.2: - dependencies: - loose-envify: 1.4.0 + scheduler@0.27.0: {} semver-compare@1.0.0: optional: true @@ -8988,7 +9422,7 @@ snapshots: socks-proxy-agent@7.0.0: dependencies: agent-base: 6.0.2 - debug: 4.4.1 + debug: 4.4.3 socks: 2.8.4 transitivePeerDependencies: - supports-color @@ -9000,7 +9434,7 @@ snapshots: solid-js@1.9.10: dependencies: - csstype: 3.1.3 + csstype: 3.2.3 seroval: 1.3.2 seroval-plugins: 1.3.3(seroval@1.3.2) @@ -9169,8 +9603,6 @@ snapshots: tmp@0.2.3: {} - to-readable-stream@1.0.0: {} - to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -9220,9 +9652,6 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - tunnel@0.0.6: - optional: true - type-fest@0.13.1: optional: true @@ -9302,17 +9731,28 @@ snapshots: dependencies: punycode: 2.3.1 - url-parse-lax@3.0.0: + use-callback-ref@1.3.3(@types/react@19.2.13)(react@19.2.4): dependencies: - prepend-http: 2.0.0 + react: 19.2.4 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.13 + + use-sidecar@1.1.3(@types/react@19.2.13)(react@19.2.4): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.4 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.13 - use-sync-external-store@1.5.0(react@18.3.1): + use-sync-external-store@1.5.0(react@19.2.4): dependencies: - react: 18.3.1 + react: 19.2.4 - use-sync-external-store@1.6.0(react@18.3.1): + use-sync-external-store@1.6.0(react@19.2.4): dependencies: - react: 18.3.1 + react: 19.2.4 username@5.1.0: dependencies: @@ -9491,8 +9931,8 @@ snapshots: zod@4.0.14: {} - zustand@5.0.7(@types/react@18.3.22)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): + zustand@5.0.7(@types/react@19.2.13)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)): optionalDependencies: - '@types/react': 18.3.22 - react: 18.3.1 - use-sync-external-store: 1.6.0(react@18.3.1) + '@types/react': 19.2.13 + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) From 504840d95601fe844347a8303e58b50f71ff07bf Mon Sep 17 00:00:00 2001 From: AymurAI Frontend <front-end@datagenero.org> Date: Sat, 21 Feb 2026 13:57:19 -0300 Subject: [PATCH 046/263] chore: export constants --- src/renderer/src/constants.ts | 25 ++++++++++++++++++++++++ src/renderer/src/types/features.ts | 11 ++++++++++- src/renderer/src/utils/config.ts | 5 ----- src/renderer/src/utils/file/isAllowed.ts | 2 +- 4 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 src/renderer/src/constants.ts diff --git a/src/renderer/src/constants.ts b/src/renderer/src/constants.ts new file mode 100644 index 00000000..22b14f47 --- /dev/null +++ b/src/renderer/src/constants.ts @@ -0,0 +1,25 @@ +import { Database, Detective, type Icon } from "phosphor-react"; +import { FeatureFlowEnum, featureName } from "./types/features"; + +export const DATAGENERO_URL = "https://www.datagenero.org/"; + +type Feature = { title: string; subtitle: string; icon: Icon }; + +export const FEATURES: Record<FeatureFlowEnum, Feature> = { + [FeatureFlowEnum.Dataset]: { + title: featureName(FeatureFlowEnum.Dataset), + subtitle: "Convertí resoluciones judiciales en set de datos estructurados", + icon: Database, + }, + [FeatureFlowEnum.Anonymizer]: { + title: featureName(FeatureFlowEnum.Anonymizer), + subtitle: + "Anonimiza resoluciones judiciales de manera automática y editable", + icon: Detective, + }, +}; + +/** + * Only allow these extensions to be analyzed + */ +export const WHITELISTED_EXTENSIONS = ["doc", "docx", "pdf"]; diff --git a/src/renderer/src/types/features.ts b/src/renderer/src/types/features.ts index 3d176997..bb05e2f6 100644 --- a/src/renderer/src/types/features.ts +++ b/src/renderer/src/types/features.ts @@ -1,4 +1,13 @@ -export enum Feature { +export enum FeatureFlowEnum { Dataset = "DATA_SET", Anonymizer = "ANONYMIZER", } + +export const featureName = (feature: FeatureFlowEnum): string => { + const names: Record<FeatureFlowEnum, string> = { + [FeatureFlowEnum.Dataset]: "Set de datos", + [FeatureFlowEnum.Anonymizer]: "Anonimizador", + }; + + return names[feature]; +}; diff --git a/src/renderer/src/utils/config.ts b/src/renderer/src/utils/config.ts index a3fb3144..64f1e384 100644 --- a/src/renderer/src/utils/config.ts +++ b/src/renderer/src/utils/config.ts @@ -3,11 +3,6 @@ */ export const PREDICT_PORT = 8899; -/** - * Only allow these extensions to be analyzed - */ -export const WHITELISTED_EXTENSIONS = ["doc", "docx", "pdf"]; - /** * Dataset Spreadsheet */ diff --git a/src/renderer/src/utils/file/isAllowed.ts b/src/renderer/src/utils/file/isAllowed.ts index c3fbcaa1..580f8b44 100644 --- a/src/renderer/src/utils/file/isAllowed.ts +++ b/src/renderer/src/utils/file/isAllowed.ts @@ -1,4 +1,4 @@ -import { WHITELISTED_EXTENSIONS } from "@/utils/config"; +import { WHITELISTED_EXTENSIONS } from "@/constants"; import getExtension from "./getExtension"; /** From 0a50bb1436e467adc01bbadffba41593ee59e43a Mon Sep 17 00:00:00 2001 From: AymurAI Frontend <front-end@datagenero.org> Date: Sat, 21 Feb 2026 14:09:02 -0300 Subject: [PATCH 047/263] fix: adjust stepper styles (sizing and colors) --- src/renderer/src/components/home/stepper.tsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/renderer/src/components/home/stepper.tsx b/src/renderer/src/components/home/stepper.tsx index fa04c966..ee6293fb 100644 --- a/src/renderer/src/components/home/stepper.tsx +++ b/src/renderer/src/components/home/stepper.tsx @@ -1,7 +1,10 @@ -import { sva } from "@/styled/css"; -import { styled } from "@/styled/jsx"; +import { css, sva } from "@/styled/css"; import { stack } from "@/styled/patterns"; +const stepper = css({ + ...stack.raw({ align: "center", direction: "row" }), +}); + const step = sva({ slots: ["container", "circle", "text"], base: { @@ -10,10 +13,14 @@ const step = sva({ padding: "2", }, circle: { + ...stack.raw({ direction: "row", align: "center", justify: "center" }), rounded: "full", - padding: "[10px]", + height: "9", + width: "9", + textStyle: "cta.md.strong", }, text: { + color: "text.default", textStyle: "label.md.default", display: "none", visibility: "hidden", @@ -39,7 +46,7 @@ const step = sva({ bg: "action.default", border: "primary-alt", }, - text: { display: "inline" }, + text: { display: "inline", visibility: "visible" }, }, }, }, @@ -72,7 +79,7 @@ export default function Stepper({ currentStep }: StepperProps) { }; return ( - <styled.div display="inline"> + <div className={stepper}> <Step number={1} status={status(1)}> Selección </Step> @@ -85,6 +92,6 @@ export default function Stepper({ currentStep }: StepperProps) { <Step number={4} status={status(4)}> Finalización </Step> - </styled.div> + </div> ); } From 2eba84b3c5edbd5bc48b3f911eef5a880af98270 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend <front-end@datagenero.org> Date: Sat, 21 Feb 2026 21:19:40 -0300 Subject: [PATCH 048/263] chore: refactor header so we can correctly position all elements --- src/renderer/src/components/layout/header.tsx | 57 +++++++++++-------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/src/renderer/src/components/layout/header.tsx b/src/renderer/src/components/layout/header.tsx index 8eb5831c..3237e3be 100644 --- a/src/renderer/src/components/layout/header.tsx +++ b/src/renderer/src/components/layout/header.tsx @@ -1,42 +1,53 @@ import { css } from "@/styled/css"; -import { Divider, Grid, Stack, styled } from "@/styled/jsx"; +import { Divider, Stack, styled } from "@/styled/jsx"; const header = css({ + position: "relative", width: "full", + height: "24", py: "6", - px: "8", + px: "12", bg: "bg.secondary", borderBottom: "[1px solid #BCBAB8]", + display: "flex", + alignItems: "center", + justifyContent: "space-between", +}); + +const centerSlot = css({ + position: "absolute", + left: "[50%]", + transform: "translateX(-50%)", }); interface HeaderProps { title?: string; - children?: React.ReactNode; + center?: React.ReactNode; + right?: React.ReactNode; } -export default function Header({ title, children }: HeaderProps) { +export default function Header({ title, center, right }: HeaderProps) { const img = title ? "/brand/aymurai-iso-darkpurple.svg" : "/brand/aymurai-hor-darkpurple.svg"; return ( - <div className={header}> - <Grid columns={3} gap="4" alignItems="center"> - <Stack gap="4" align="center" direction="row"> - <img height={40} src={img} alt="AymurAI logo" /> - {title && ( - <> - <Divider - orientation="vertical" - thickness="[2px]" - color="text.default" - height="4" - /> - <styled.span textStyle="subtitle.md.strong">{title}</styled.span> - </> - )} - </Stack> - <styled.div gridColumn="span 2">{children}</styled.div> - </Grid> - </div> + <header className={header}> + <Stack gap="4" align="center" direction="row"> + <img height={40} src={img} alt="AymurAI logo" /> + {title && ( + <> + <Divider + orientation="vertical" + thickness="[2px]" + color="text.default" + height="4" + /> + <styled.span textStyle="subtitle.md.strong">{title}</styled.span> + </> + )} + </Stack> + {center && <div className={centerSlot}>{center}</div>} + <div>{right}</div> + </header> ); } From 2344209500ade530a6a3c4dfd734da12bc2cb4ee Mon Sep 17 00:00:00 2001 From: AymurAI Frontend <front-end@datagenero.org> Date: Sat, 21 Feb 2026 21:20:14 -0300 Subject: [PATCH 049/263] chore: use constants and base card element on feature selector --- src/renderer/src/routes/home/features.tsx | 100 ++++++++++++---------- 1 file changed, 57 insertions(+), 43 deletions(-) diff --git a/src/renderer/src/routes/home/features.tsx b/src/renderer/src/routes/home/features.tsx index f770235f..15910420 100644 --- a/src/renderer/src/routes/home/features.tsx +++ b/src/renderer/src/routes/home/features.tsx @@ -1,66 +1,80 @@ -import CardTool from "@/components/home/card-tool"; -import { css } from "@/styled/css"; +import FeatureIcon from "@/components/feature-icon"; +import FeaturesMenu from "@/components/features-menu"; +import Header from "@/components/layout/header"; +import MainContent from "@/components/layout/main-content"; +import Card from "@/components/ui/card"; +import { FEATURES } from "@/constants"; import { Grid, Stack, styled } from "@/styled/jsx"; -import { Feature } from "@/types/features"; -import { createFileRoute } from "@tanstack/react-router"; -import { Database, Detective } from "phosphor-react"; +import { FeatureFlowEnum } from "@/types/features"; +import { + Link, + type LinkComponentProps, + createFileRoute, +} from "@tanstack/react-router"; +import type { Icon } from "phosphor-react"; + +interface CardToolProps extends LinkComponentProps { + title: string; + subtitle: string; + icon: Icon; + disabled?: boolean; +} +function CardTool({ + title, + subtitle, + icon: Icon, + disabled = false, + ...props +}: CardToolProps) { + return ( + <Link disabled={disabled} {...props}> + <Card> + <Stack align="start" gap="4"> + <FeatureIcon size="lg" icon={Icon} /> + <Stack gap="1"> + <styled.h2 textStyle="subtitle.md.strong">{title}</styled.h2> + <styled.p textStyle="subtitle.sm.default" color="text.lighter"> + {subtitle} + </styled.p> + </Stack> + </Stack> + </Card> + </Link> + ); +} export const Route = createFileRoute("/home/features")({ component: RouteComponent, }); -const header = css({ - width: "full", - py: "6", - px: "8", - bg: "bg.secondary", - borderBottom: "[1px solid #BCBAB8]", -}); -const content = css({ - display: "flex", - justifyContent: "center", - flex: "1", - - width: "full", - height: "full", - pt: "28", - - bg: "bg.primary", -}); - function RouteComponent() { return ( <Stack width="screen" height="screen" gap="0"> - <div className={header}> - <img - width={200} - src="brand/aymurai-hor-darkpurple.svg" - alt="AymurAI logo" - /> - </div> - <main className={content}> - <Stack gap="6" width="5xl" mx="8"> + <Header right={<FeaturesMenu />} /> + <MainContent> + <Stack gap="6"> <styled.h1 textStyle="title.md.strong"> ¡Hola! Selecciona la herramienta a utilizar </styled.h1> - <Grid columns={2}> + <Grid columns={2} rowGap="6" columnGap="6"> + {/* FIXME: fix the text wrapping on smaller screens */} <CardTool to="/app/$feature" - params={{ feature: Feature.Dataset }} - icon={Database} - title="Set de Datos" - subtitle="Convertí resoluciones judiciales en set de datos estructurados" + params={{ feature: FeatureFlowEnum.Dataset }} + title={FEATURES.DATA_SET.title} + subtitle={FEATURES.DATA_SET.subtitle} + icon={FEATURES.DATA_SET.icon} /> <CardTool to="/app/$feature" - params={{ feature: Feature.Dataset }} - icon={Detective} - title="Anonimizador" - subtitle="Anonimiza resoluciones judiciales de manera automática y editable" + params={{ feature: FeatureFlowEnum.Anonymizer }} + title={FEATURES.ANONYMIZER.title} + subtitle={FEATURES.ANONYMIZER.subtitle} + icon={FEATURES.ANONYMIZER.icon} /> </Grid> </Stack> - </main> + </MainContent> </Stack> ); } From beb63bc3b382848850ca04edf149617c1332aebb Mon Sep 17 00:00:00 2001 From: AymurAI Frontend <front-end@datagenero.org> Date: Sat, 21 Feb 2026 21:33:15 -0300 Subject: [PATCH 050/263] chore: migrate hidden input --- .../HiddenInput.styles.ts | 0 .../index.tsx | 2 +- src/renderer/src/components/hidden-input.tsx | 25 +++++++++++++++++++ src/renderer/src/components/index.ts | 2 +- 4 files changed, 27 insertions(+), 2 deletions(-) rename src/renderer/src/components/{hidden-input => hidden-input-old}/HiddenInput.styles.ts (100%) rename src/renderer/src/components/{hidden-input => hidden-input-old}/index.tsx (91%) create mode 100644 src/renderer/src/components/hidden-input.tsx diff --git a/src/renderer/src/components/hidden-input/HiddenInput.styles.ts b/src/renderer/src/components/hidden-input-old/HiddenInput.styles.ts similarity index 100% rename from src/renderer/src/components/hidden-input/HiddenInput.styles.ts rename to src/renderer/src/components/hidden-input-old/HiddenInput.styles.ts diff --git a/src/renderer/src/components/hidden-input/index.tsx b/src/renderer/src/components/hidden-input-old/index.tsx similarity index 91% rename from src/renderer/src/components/hidden-input/index.tsx rename to src/renderer/src/components/hidden-input-old/index.tsx index 2d225a58..bea4c95f 100644 --- a/src/renderer/src/components/hidden-input/index.tsx +++ b/src/renderer/src/components/hidden-input-old/index.tsx @@ -1,8 +1,8 @@ import { forwardRef } from "react"; +import { WHITELISTED_EXTENSIONS } from "@/constants"; import type { CSS } from "@/styles"; import type { NativeComponent } from "@/types/component"; -import { WHITELISTED_EXTENSIONS } from "@/utils/config"; import Input from "./HiddenInput.styles"; interface Props extends NativeComponent<"input"> { diff --git a/src/renderer/src/components/hidden-input.tsx b/src/renderer/src/components/hidden-input.tsx new file mode 100644 index 00000000..495c2421 --- /dev/null +++ b/src/renderer/src/components/hidden-input.tsx @@ -0,0 +1,25 @@ +import { WHITELISTED_EXTENSIONS } from "@/constants"; +import { css, cx } from "@/styled/css"; +import type { ComponentProps } from "react"; + +const input = css({ + display: "none", + visibility: "hidden", + opacity: 0, + pointerEvents: "none", +}); + +interface HiddenInputProps extends ComponentProps<"input"> {} +export default function HiddenInput({ className, ...props }: HiddenInputProps) { + // Convert the array into a '.dcox' form + const extensions = WHITELISTED_EXTENSIONS.map((ext) => `.${ext}`).join(","); + return ( + <input + type="file" + accept={extensions} + tabIndex={-1} + className={cx(input, className)} + {...props} + /> + ); +} diff --git a/src/renderer/src/components/index.ts b/src/renderer/src/components/index.ts index 3622ebad..6af0a8fd 100644 --- a/src/renderer/src/components/index.ts +++ b/src/renderer/src/components/index.ts @@ -10,7 +10,7 @@ export { default as FileStepper } from "./file-stepper"; export { FinishAnonymizer } from "./finish-anonymizer"; export { FinishDataset } from "./finish-dataset"; export { default as Grid } from "./grid"; -export { default as HiddenInput } from "./hidden-input"; +export { default as HiddenInput } from "./hidden-input-old"; export { default as Label } from "./label"; export { OnboardingCard } from "./onboarding-card"; export { OnboardingGrid } from "./onboarding-grid"; From 24f6de0767142c746f43b7818248b0b6f508909d Mon Sep 17 00:00:00 2001 From: AymurAI Frontend <front-end@datagenero.org> Date: Tue, 24 Feb 2026 14:52:22 -0300 Subject: [PATCH 051/263] build: add web or electron run modes --- package.json | 20 ++++++++++---------- src/renderer/src/app.tsx | 15 +++++++++------ src/renderer/src/vite-env.d.ts | 8 ++++++++ 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index aec1fb56..d7aede53 100644 --- a/package.json +++ b/package.json @@ -4,30 +4,30 @@ "private": true, "main": "./out/main/index.js", "scripts": { - "dev:web": "vite --config vite.config.ts", - "dev": "electron-vite dev", - "start": "electron-vite preview", - "start:web": "vite preview --config vite.config.ts", + "dev:web": "cross-env VITE_APP_MODE=web vite --config vite.config.ts", + "dev": "cross-env VITE_APP_MODE=electron electron-vite dev", + "start": "cross-env VITE_APP_MODE=electron electron-vite preview", + "start:web": "cross-env VITE_APP_MODE=web vite preview --config vite.config.ts", "lint": "biome check", "lint:fix": "biome check --write", "format": "biome format", "format:fix": "biome format --write", "typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false", "typecheck:web": "tsc --noEmit -p tsconfig.web.json --composite false", - "typecheck": "npm run typecheck:node && npm run typecheck:web", + "typecheck": "npm run typecheck:node; npm run typecheck:web", "validate": "npm run lint && npm run check-types:react && npm run check-types:renderer", "pre-commit": "lint-staged", "package": "rm -rf build && npm run build && electron-forge package", "make": "rm -rf build && npm run build && electron-forge make", - "postinstall": "electron-builder install-app-deps", + "postinstall": "electron-builder install-app-deps || true", "panda:codegen": "panda codegen", "prepare": "panda codegen", - "build:web": "vite build --config vite.config.ts", - "build": "npm run typecheck && electron-vite build", + "build:web": "cross-env VITE_APP_MODE=web vite build --config vite.config.ts", + "build": "npm run typecheck && cross-env VITE_APP_MODE=electron electron-vite build", "build:unpack": "npm run build && electron-builder --dir", "build:win": "npm run build && electron-builder --win", - "build:mac": "electron-vite build && electron-builder --mac", - "build:linux": "electron-vite build && electron-builder --linux" + "build:mac": "cross-env VITE_APP_MODE=electron electron-vite build && electron-builder --mac", + "build:linux": "cross-env VITE_APP_MODE=electron electron-vite build && electron-builder --linux" }, "dependencies": { "@electron-toolkit/preload": "^3.0.2", diff --git a/src/renderer/src/app.tsx b/src/renderer/src/app.tsx index a1695e2e..3fb87981 100644 --- a/src/renderer/src/app.tsx +++ b/src/renderer/src/app.tsx @@ -5,6 +5,7 @@ import { } from "@tanstack/react-router"; import { ThemeProvider } from "@/components"; +import { TooltipProvider } from "@/components/ui/tooltip"; import * as TanstackReactQuery from "@/features/ReactQueryProvider"; // Import the generated route tree @@ -12,13 +13,13 @@ import { routeTree } from "./routeTree.gen"; const TanStackQueryProviderContext = TanstackReactQuery.getContext(); -// Create a new router instance -const memoryHistory = createMemoryHistory({ - initialEntries: ["/"], // Pass your initial url -}); +const history = + import.meta.env.VITE_APP_MODE === "electron" + ? createMemoryHistory({ initialEntries: ["/"] }) + : undefined; const router = createRouter({ routeTree, - history: memoryHistory, + history, context: { ...TanStackQueryProviderContext }, defaultViewTransition: true, }); @@ -34,7 +35,9 @@ export default function App() { <TanstackReactQuery.Provider {...TanStackQueryProviderContext}> {/* Stitches global styles */} <ThemeProvider> - <RouterProvider router={router} /> + <TooltipProvider> + <RouterProvider router={router} /> + </TooltipProvider> </ThemeProvider> </TanstackReactQuery.Provider> ); diff --git a/src/renderer/src/vite-env.d.ts b/src/renderer/src/vite-env.d.ts index 11f02fe2..7ea578b0 100644 --- a/src/renderer/src/vite-env.d.ts +++ b/src/renderer/src/vite-env.d.ts @@ -1 +1,9 @@ /// <reference types="vite/client" /> + +interface ImportMetaEnv { + readonly VITE_APP_MODE: 'electron' | 'web' +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} From 1e15bb746c8bf29d1e12f31fa1b5ef3bf4afa131 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend <front-end@datagenero.org> Date: Tue, 24 Feb 2026 14:52:44 -0300 Subject: [PATCH 052/263] fix: typo on anonymizer label --- src/renderer/src/types/aymurai.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/src/types/aymurai.ts b/src/renderer/src/types/aymurai.ts index 01fd32a7..a716125b 100644 --- a/src/renderer/src/types/aymurai.ts +++ b/src/renderer/src/types/aymurai.ts @@ -100,7 +100,7 @@ export const anonymizerLabels: SelectOption[] = [ { id: "DENUNCIANTE", text: "Denunciante" }, { id: "ACUSADO/A", text: "Acusado/a" }, { id: "TESTIGO/A", text: "Testigo/a" }, - { id: "NINO/A_ADOLECENTE", text: "Niño/a adolecente" }, + { id: "NINO/A_ADOSLECENTE", text: "Niño/a adolescente" }, { id: "AFILIADO", text: "N° de afiliado" }, { id: "CAUSA", text: "N° de causa" }, { id: "INSTITUCION", text: "Nombre de institución" }, From 051b6bd43f291d3d6293d332c4159c99d14aae3c Mon Sep 17 00:00:00 2001 From: AymurAI Frontend <front-end@datagenero.org> Date: Tue, 24 Feb 2026 14:53:19 -0300 Subject: [PATCH 053/263] chore: add tutorial seen to local storage store --- src/renderer/src/store/useLocal.ts | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/renderer/src/store/useLocal.ts b/src/renderer/src/store/useLocal.ts index 87f72711..f78bbca5 100644 --- a/src/renderer/src/store/useLocal.ts +++ b/src/renderer/src/store/useLocal.ts @@ -1,19 +1,35 @@ import { create } from "zustand"; import { devtools, persist } from "zustand/middleware"; +import { FeatureFlowEnum } from "../types/features"; + +type TutorialsSeen = Record<FeatureFlowEnum, boolean>; interface LocalStorageStore { serverHost: string | null; setServerHost: (serverUrl: string) => void; clearServerHost: () => void; + tutorialsSeen: TutorialsSeen; + hasSeenTutorial: (feature: FeatureFlowEnum) => boolean; + setTutorialSeen: (feature: FeatureFlowEnum) => void; } const useLocalStore = create<LocalStorageStore>()( devtools( persist( - (set) => ({ + (set, get) => ({ serverHost: null, setServerHost: (serverHost: string) => set({ serverHost }), clearServerHost: () => set({ serverHost: null }), + tutorialsSeen: { + [FeatureFlowEnum.Anonymizer]: false, + [FeatureFlowEnum.Dataset]: false, + }, + hasSeenTutorial: (feature: FeatureFlowEnum) => + get().tutorialsSeen[feature], + setTutorialSeen: (feature: FeatureFlowEnum) => + set((state) => ({ + tutorialsSeen: { ...state.tutorialsSeen, [feature]: true }, + })), }), { name: "local-storage", @@ -22,6 +38,8 @@ const useLocalStore = create<LocalStorageStore>()( ), ); +// TODO: in the future, we should export all of these hooks under a single named exports +// usage will be like the following: `localStore.useServerHost` export const useServerHost = () => useLocalStore((state) => state.serverHost); export const useServerHostActions = () => { const setServerHost = useLocalStore((state) => state.setServerHost); @@ -32,3 +50,8 @@ export const useServerHostActions = () => { clearServerHost, }; }; + +export const useTutorialSeen = (feature: FeatureFlowEnum) => + useLocalStore((state) => state.tutorialsSeen[feature]); +export const useSetTutorialSeen = () => + useLocalStore((state) => state.setTutorialSeen); From dc59ad2ac166379a6c0f9cecd096bb7d6ac36ac3 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend <front-end@datagenero.org> Date: Tue, 24 Feb 2026 14:54:27 -0300 Subject: [PATCH 054/263] feat: make card clickable --- src/renderer/src/components/features-menu.tsx | 2 +- src/renderer/src/components/ui/card.tsx | 30 +++++++++++++++++-- src/renderer/src/routes/home/features.tsx | 2 +- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/renderer/src/components/features-menu.tsx b/src/renderer/src/components/features-menu.tsx index e10d479d..47a38bd9 100644 --- a/src/renderer/src/components/features-menu.tsx +++ b/src/renderer/src/components/features-menu.tsx @@ -25,7 +25,7 @@ export default function FeaturesMenu() { to="/app/$feature" params={{ feature: value as FeatureFlowEnum }} > - <Card size="sm"> + <Card size="sm" clickable> <Stack gap="3" align="center"> <FeatureIcon feature={value as FeatureFlowEnum} size="sm" /> <styled.p textStyle="label.md.strong"> diff --git a/src/renderer/src/components/ui/card.tsx b/src/renderer/src/components/ui/card.tsx index 53247b9b..a2d07a59 100644 --- a/src/renderer/src/components/ui/card.tsx +++ b/src/renderer/src/components/ui/card.tsx @@ -21,20 +21,42 @@ const styles = cva({ true: { border: "primary", bg: "bg.primary", - cursor: "not-allowed", color: "text.lighter", }, false: { border: "primary", bg: "bg.secondary", + }, + }, + clickable: { + true: {}, + false: {}, + }, + }, + compoundVariants: [ + { + clickable: true, + disabled: false, + css: { cursor: "pointer", - "&:hover": { border: "primary-alt", boxShadow: "[0px 0px 15px 0px #3F479D66]", }, }, }, + { + clickable: true, + disabled: true, + css: { + cursor: "not-allowed", + }, + }, + ], + defaultVariants: { + disabled: false, + clickable: false, + size: "lg", }, }); @@ -42,12 +64,14 @@ interface CardProps { children?: React.ReactNode; disabled?: boolean; size?: "lg" | "sm"; + clickable?: boolean; } export default function Card({ disabled = false, size = "lg", + clickable = false, children, }: CardProps) { - const classes = styles({ size, disabled }); + const classes = styles({ size, disabled, clickable }); return <div className={classes}>{children}</div>; } diff --git a/src/renderer/src/routes/home/features.tsx b/src/renderer/src/routes/home/features.tsx index 15910420..21ce5cff 100644 --- a/src/renderer/src/routes/home/features.tsx +++ b/src/renderer/src/routes/home/features.tsx @@ -28,7 +28,7 @@ function CardTool({ }: CardToolProps) { return ( <Link disabled={disabled} {...props}> - <Card> + <Card clickable> <Stack align="start" gap="4"> <FeatureIcon size="lg" icon={Icon} /> <Stack gap="1"> From cef7f882b6eda011ca0dc1ff996a997fc8637541 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend <front-end@datagenero.org> Date: Tue, 24 Feb 2026 14:55:44 -0300 Subject: [PATCH 055/263] chore: adjust button sizes and enum import --- .../decision-tabs/DecisionTabs.styles.ts | 3 +-- .../src/components/file-annotator/Mark.tsx | 6 +++--- .../src/components/file-preview/index.tsx | 4 ++-- .../components/finish-anonymizer/index.tsx | 20 +++++++------------ .../src/components/finish-dataset/index.tsx | 8 ++++---- src/renderer/src/components/toast/index.tsx | 2 +- .../src/routes/app.$feature/finish.tsx | 4 ++-- .../src/routes/app.$feature/process.tsx | 8 ++++---- .../src/routes/app.$feature/validation.tsx | 8 ++++---- 9 files changed, 28 insertions(+), 35 deletions(-) diff --git a/src/renderer/src/components/decision-tabs/DecisionTabs.styles.ts b/src/renderer/src/components/decision-tabs/DecisionTabs.styles.ts index 608f7bdd..0dd8c7a1 100644 --- a/src/renderer/src/components/decision-tabs/DecisionTabs.styles.ts +++ b/src/renderer/src/components/decision-tabs/DecisionTabs.styles.ts @@ -1,7 +1,6 @@ -import { Button as BaseButton } from "@/components"; import { styled } from "@/styles"; -export const PlusButton = styled(BaseButton, { +export const PlusButton = styled("button", { boxShadow: "4px 0px 4px rgba(0, 0, 0, 0.05)", // Marked as important because of Stitches hierarchy diff --git a/src/renderer/src/components/file-annotator/Mark.tsx b/src/renderer/src/components/file-annotator/Mark.tsx index 85ee3a2b..c30cff1b 100644 --- a/src/renderer/src/components/file-annotator/Mark.tsx +++ b/src/renderer/src/components/file-annotator/Mark.tsx @@ -1,5 +1,5 @@ -import Input from "@/components/input"; import Select, { type SelectOption } from "@/components/select"; +import Input from "@/components/ui/input"; import { useAnnotation } from "@/context/Annotation"; import { type AllLabels, @@ -7,8 +7,8 @@ import { anonymizerLabels, } from "@/types/aymurai"; import { type FC, type HTMLAttributes, useRef, useState } from "react"; -import Button from "../button"; -import Dialog, { DialogMessage, DialogButtons } from "../dialog"; +import Dialog, { DialogButtons, DialogMessage } from "../dialog"; +import Button from "../ui/button"; import * as S from "./FileAnnotator.styles"; import type { Annotation, LabelAnnotation, Metadata } from "./types"; diff --git a/src/renderer/src/components/file-preview/index.tsx b/src/renderer/src/components/file-preview/index.tsx index a4c3d7e4..a8a2ed88 100644 --- a/src/renderer/src/components/file-preview/index.tsx +++ b/src/renderer/src/components/file-preview/index.tsx @@ -6,7 +6,7 @@ import { toggleSelected } from "@/reducers/file/actions"; import { useFileParser } from "@/services/aymurai/useFileParser"; import type { DocFile } from "@/types/file"; -import { Feature } from "@/types/features"; +import { FeatureFlowEnum } from "@/types/features"; import { useParams } from "@tanstack/react-router"; import * as S from "./FilePreview.styles"; @@ -18,7 +18,7 @@ export default function FilePreview({ file }: Props) { const dispatch = useFileDispatch(); const { data: parsedFile, isError, isPending } = useFileParser(file.data); - const isAnonymizer = feature === Feature.Anonymizer; + const isAnonymizer = feature === FeatureFlowEnum.Anonymizer; const moreThanOneParagraph = parsedFile && parsedFile.document.length > 1; if (isError) { diff --git a/src/renderer/src/components/finish-anonymizer/index.tsx b/src/renderer/src/components/finish-anonymizer/index.tsx index c31d6246..20766879 100644 --- a/src/renderer/src/components/finish-anonymizer/index.tsx +++ b/src/renderer/src/components/finish-anonymizer/index.tsx @@ -8,12 +8,13 @@ import { Text, } from "@/components"; import { useFileDispatch, useFiles } from "@/hooks"; -import { Footer, Section } from "@/layout/main"; + import { removeAllFiles } from "@/reducers/file/actions"; import { aymuraiService } from "@/services/aymurai"; import { useQuery } from "@tanstack/react-query"; import { useNavigate, useParams } from "@tanstack/react-router"; -import * as S from "./FinishAnonymizer.styles"; +import Footer from "../layout/footer"; +import MainContent from "../layout/main-content"; const changeExtension = (name: string) => { const parts = name.split("."); @@ -56,7 +57,7 @@ export function FinishAnonymizer() { return ( <> - <Section> + <MainContent> <SectionTitle>4. Finalización</SectionTitle> <Text css={{ maxWidth: "60%" }}> Los datos encontrados por AymurAI y posteriormente validados ya han @@ -77,19 +78,12 @@ export function FinishAnonymizer() { /> </Grid> </Card> - </Section> + </MainContent> <Footer> - <S.Anchor - href="https://www.datagenero.org/" - target="_blank" - rel="noreferrer" - > - <img src="brand/data-genero.png" alt="DataGenero" width={150} /> - </S.Anchor> - <Button variant="secondary" onClick={handleRestart} size="l"> + <Button variant="secondary" onClick={handleRestart}> Cargar un nuevo documento </Button> - <Button onClick={downloadDocument} size="l" disabled={isError}> + <Button onClick={downloadDocument} disabled={isError}> Descargar documento </Button> </Footer> diff --git a/src/renderer/src/components/finish-dataset/index.tsx b/src/renderer/src/components/finish-dataset/index.tsx index a1cd1247..f51245d3 100644 --- a/src/renderer/src/components/finish-dataset/index.tsx +++ b/src/renderer/src/components/finish-dataset/index.tsx @@ -10,7 +10,7 @@ import { Text, } from "@/components"; import { useFileDispatch, useFiles } from "@/hooks"; -import { Footer, Section } from "@/layout/main"; +import { Footer, Section } from "@/layout/main-old"; import { removeAllFiles } from "@/reducers/file/actions"; import filesystem from "@/services/filesystem"; import type { DocFile } from "@/types/file"; @@ -96,13 +96,13 @@ export function FinishDataset() { target="_blank" rel="noreferrer" > - <img src="brand/data-genero.png" alt="DataGenero" width={150} /> + <img src="/brand/data-genero.png" alt="DataGenero" width={150} /> </S.Anchor> - <Button variant="secondary" onClick={handleRestart} size="l"> + <Button variant="secondary" onClick={handleRestart} size="md"> Cargar más documentos </Button> - <Button size="l" onClick={filesystem.excel.open}> + <Button size="md" onClick={filesystem.excel.open}> Ver set de datos </Button> </Footer> diff --git a/src/renderer/src/components/toast/index.tsx b/src/renderer/src/components/toast/index.tsx index 3524b37d..5e8798a3 100644 --- a/src/renderer/src/components/toast/index.tsx +++ b/src/renderer/src/components/toast/index.tsx @@ -1,8 +1,8 @@ import { X } from "phosphor-react"; import { cloneElement } from "react"; -import Button from "../button"; import Label from "../label"; +import Button from "../ui/button"; import * as S from "./Toast.styles"; import type { Props } from "./Toast.types"; diff --git a/src/renderer/src/routes/app.$feature/finish.tsx b/src/renderer/src/routes/app.$feature/finish.tsx index aeead319..0c1797ae 100644 --- a/src/renderer/src/routes/app.$feature/finish.tsx +++ b/src/renderer/src/routes/app.$feature/finish.tsx @@ -1,5 +1,5 @@ import { FinishAnonymizer, FinishDataset } from "@/components"; -import { Feature } from "@/types/features"; +import { FeatureFlowEnum } from "@/types/features"; import { createFileRoute, useParams } from "@tanstack/react-router"; export const Route = createFileRoute("/app/$feature/finish")({ @@ -9,6 +9,6 @@ export const Route = createFileRoute("/app/$feature/finish")({ function RouteComponent() { const { feature } = useParams({ from: "/app/$feature/finish" }); - if (feature === Feature.Dataset) return <FinishDataset />; + if (feature === FeatureFlowEnum.Dataset) return <FinishDataset />; return <FinishAnonymizer />; } diff --git a/src/renderer/src/routes/app.$feature/process.tsx b/src/renderer/src/routes/app.$feature/process.tsx index e5926043..2dbbdbe0 100644 --- a/src/renderer/src/routes/app.$feature/process.tsx +++ b/src/renderer/src/routes/app.$feature/process.tsx @@ -11,12 +11,12 @@ import { import { useFileDispatch, useFiles } from "@/hooks"; import useNotify from "@/hooks/useNotify"; import type { PredictStatus } from "@/hooks/usePredict"; -import { Footer, Section } from "@/layout/main"; +import { Footer, Section } from "@/layout/main-old"; import { filterUnprocessed, removeAllPredictions, } from "@/reducers/file/actions"; -import { Feature } from "@/types/features"; +import { FeatureFlowEnum } from "@/types/features"; import { canContinue } from "@/utils/process/canContinue"; import { type ProcessState, @@ -126,7 +126,7 @@ function GenericProcess({ </Card> </Section> <Footer> - <Button size="l" disabled={!canContinue(process)} onClick={handleNext}> + <Button size="md" disabled={!canContinue(process)} onClick={handleNext}> Siguiente </Button> </Footer> @@ -139,7 +139,7 @@ function RouteComponent() { from: "/app/$feature/process", }); - if (feature === Feature.Dataset) + if (feature === FeatureFlowEnum.Dataset) return ( <GenericProcess title="2. Procesamiento de los archivos" diff --git a/src/renderer/src/routes/app.$feature/validation.tsx b/src/renderer/src/routes/app.$feature/validation.tsx index 78a7cfb9..31f5647f 100644 --- a/src/renderer/src/routes/app.$feature/validation.tsx +++ b/src/renderer/src/routes/app.$feature/validation.tsx @@ -1,7 +1,7 @@ import { Button, FileAnnotator, Grid, ValidateDataset } from "@/components"; import { useFiles } from "@/hooks"; -import { Footer } from "@/layout/main"; -import { Feature } from "@/types/features"; +import { Footer } from "@/layout/main-old"; +import { FeatureFlowEnum } from "@/types/features"; import { createFileRoute, useNavigate, @@ -40,7 +40,7 @@ function ValidateAnonymizer() { gap: 150, }} > - <Button size="l" onClick={handleContinue}> + <Button size="md" onClick={handleContinue}> Anonimizar documento </Button> </Footer> @@ -51,6 +51,6 @@ function ValidateAnonymizer() { function ValidationRoute() { const { feature } = Route.useParams(); - if (feature === Feature.Dataset) return <ValidateDataset />; + if (feature === FeatureFlowEnum.Dataset) return <ValidateDataset />; return <ValidateAnonymizer />; } From 347054d58ce076f9718e1dc458e56d1959ccedfb Mon Sep 17 00:00:00 2001 From: AymurAI Frontend <front-end@datagenero.org> Date: Tue, 24 Feb 2026 14:55:57 -0300 Subject: [PATCH 056/263] chore: simplify main app layout --- .../src/routes/app.$feature/route.tsx | 24 ++++--------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/src/renderer/src/routes/app.$feature/route.tsx b/src/renderer/src/routes/app.$feature/route.tsx index 353731e7..1b5a9c45 100644 --- a/src/renderer/src/routes/app.$feature/route.tsx +++ b/src/renderer/src/routes/app.$feature/route.tsx @@ -1,14 +1,13 @@ import { Outlet, createFileRoute, redirect } from "@tanstack/react-router"; import { z } from "zod"; -import { ProfileInfo, Stepper, Title } from "@/components"; import FileProvider from "@/context/File"; -import { Header, Layout } from "@/layout/main"; -import { Feature } from "@/types/features"; +import { Stack } from "@/styled/jsx"; +import { FeatureFlowEnum } from "@/types/features"; // Validation schema for feature parameter const featureParamSchema = z.object({ - feature: z.enum([Feature.Dataset, Feature.Anonymizer]), + feature: z.enum([FeatureFlowEnum.Dataset, FeatureFlowEnum.Anonymizer]), }); export const Route = createFileRoute("/app/$feature")({ @@ -29,24 +28,11 @@ export const Route = createFileRoute("/app/$feature")({ function AppLayoutRoute() { const { feature } = Route.useParams(); - // Determine title based on feature - const title = feature === Feature.Dataset ? "Set de datos" : "Anonimizador"; - return ( - <Layout> - <Header> - {/* Title & Profile picture & Logout */} - <Title weight="strong" css={{ fontSize: 24 }}> - AymurAI {title} - - - - - + - {/* Child routes render here */} - + ); } From 6c9daf380a9327f061c9bec15e88399ead59cfa0 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Tue, 24 Feb 2026 14:56:20 -0300 Subject: [PATCH 057/263] feat: rework onboarding page --- .../src/routes/app.$feature/onboarding.tsx | 170 +++++++----------- 1 file changed, 68 insertions(+), 102 deletions(-) diff --git a/src/renderer/src/routes/app.$feature/onboarding.tsx b/src/renderer/src/routes/app.$feature/onboarding.tsx index 2496ba3a..40c91a68 100644 --- a/src/renderer/src/routes/app.$feature/onboarding.tsx +++ b/src/renderer/src/routes/app.$feature/onboarding.tsx @@ -3,129 +3,95 @@ import { useNavigate, useParams, } from "@tanstack/react-router"; -import { useRef } from "react"; +import DropArea from "@/components/drop-area"; +import FeaturesMenu from "@/components/features-menu"; +import HiddenInput from "@/components/hidden-input"; +import HowItWorks from "@/components/how-it-works"; +import HowItWorksModal from "@/components/how-it-works-modal"; +import Footer from "@/components/layout/footer"; +import Header from "@/components/layout/header"; +import MainContent from "@/components/layout/main-content"; +import BackButton from "@/components/ui/back-button"; +import Button from "@/components/ui/button"; import { useFileDispatch } from "@/hooks"; +import { SectionTitle } from "@/layout/section-title"; import { addFiles } from "@/reducers/file/actions"; - -import { - Button, - HiddenInput, - OnboardingCard, - OnboardingGrid, - Stack, - Text, - Title, -} from "@/components"; -import { Footer, Section } from "@/layout/main"; -import { Feature } from "@/types/features"; +import { useSetTutorialSeen, useTutorialSeen } from "@/store/useLocal"; +import { HStack, Stack, styled } from "@/styled/jsx"; +import { featureName } from "@/types/features"; +import { useRef } from "react"; // FIRST step of the processing workflow export const Route = createFileRoute("/app/$feature/onboarding")({ component: RouteComponent, }); -interface GenericOnboardingProps { - description: string; - actionText: string; - steps: string[]; - multipleFiles: boolean; -} -function GenericOnboarding({ - description, - actionText, - steps, - multipleFiles, -}: GenericOnboardingProps) { - const { feature } = useParams({ from: "/app/$feature/onboarding" }); +function RouteComponent() { + const { feature } = useParams({ + from: "/app/$feature/onboarding", + }); + const navigate = useNavigate(); + const inputRef = useRef(null); + const dispatch = useFileDispatch(); - const navigate = useNavigate(); + const tutorialSeen = useTutorialSeen(feature); + const toggleTutorialSeen = useSetTutorialSeen(); - const handleSelectFile = () => { - inputRef.current?.click(); + const handleAddFiles = async (files: File[]) => { + dispatch(addFiles(files)); + await navigate({ + to: "/app/$feature/preview", + params: { feature }, + }); + toggleTutorialSeen(feature); }; - const handleAddedFiles: React.ChangeEventHandler = (e) => { + const handleInputChange: React.ChangeEventHandler = (e) => { const rawFiles = e.target.files; + if (rawFiles) handleAddFiles(Array.from(rawFiles)); + }; - // Check if any file was added - if (rawFiles) { - const files = Array.from(rawFiles); - - dispatch(addFiles(files)); - navigate({ - to: "/app/$feature/preview", - params: { feature }, - }); - } + const handleOpenInput = () => { + inputRef.current?.click(); }; return ( <> - {/* Onboarding description */} -
- - ¿Cómo funciona AymurAI? - {description} - - - {steps.map((step, index) => ( - - ))} - -
- - {/* Input file */} -
- - Formatos válidos: .docx, .pdf - +
+ {tutorialSeen && } + + + } + /> + + {tutorialSeen ? ( + + + + 1. Selección de Archivos + + + + ) : ( + + )} + +
+ + {!tutorialSeen && ( + + Formatos válidos: .doc y .docx + + )} + +
+ ); } - -function RouteComponent() { - const { feature } = useParams({ - from: "/app/$feature/onboarding", - }); - - if (feature === Feature.Dataset) - return ( - - ); - - return ( - - ); -} From ee17865eab43400d259f9e7152fa0a307b9ba7d6 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Tue, 24 Feb 2026 14:56:55 -0300 Subject: [PATCH 058/263] feat(ui): create and/or adjust components --- src/renderer/src/components/hidden-input.tsx | 4 +++- src/renderer/src/components/home/stepper.tsx | 5 +---- src/renderer/src/components/ui/back-button.tsx | 16 ++++++++++++++++ .../src/components/validate-dataset/index.tsx | 6 +++--- src/renderer/src/layout/section-title.tsx | 8 ++++++++ 5 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 src/renderer/src/components/ui/back-button.tsx create mode 100644 src/renderer/src/layout/section-title.tsx diff --git a/src/renderer/src/components/hidden-input.tsx b/src/renderer/src/components/hidden-input.tsx index 495c2421..71738994 100644 --- a/src/renderer/src/components/hidden-input.tsx +++ b/src/renderer/src/components/hidden-input.tsx @@ -9,7 +9,9 @@ const input = css({ pointerEvents: "none", }); -interface HiddenInputProps extends ComponentProps<"input"> {} +interface HiddenInputProps extends Omit, "onChange"> { + onChange: React.ChangeEventHandler; +} export default function HiddenInput({ className, ...props }: HiddenInputProps) { // Convert the array into a '.dcox' form const extensions = WHITELISTED_EXTENSIONS.map((ext) => `.${ext}`).join(","); diff --git a/src/renderer/src/components/home/stepper.tsx b/src/renderer/src/components/home/stepper.tsx index ee6293fb..901e7a56 100644 --- a/src/renderer/src/components/home/stepper.tsx +++ b/src/renderer/src/components/home/stepper.tsx @@ -8,10 +8,7 @@ const stepper = css({ const step = sva({ slots: ["container", "circle", "text"], base: { - container: { - ...stack.raw({ direction: "row", align: "center", gap: "2" }), - padding: "2", - }, + container: stack.raw({ direction: "row", align: "center", gap: "2" }), circle: { ...stack.raw({ direction: "row", align: "center", justify: "center" }), rounded: "full", diff --git a/src/renderer/src/components/ui/back-button.tsx b/src/renderer/src/components/ui/back-button.tsx new file mode 100644 index 00000000..a481a208 --- /dev/null +++ b/src/renderer/src/components/ui/back-button.tsx @@ -0,0 +1,16 @@ +import { css, cx } from "@/styled/css"; +import { Link, type LinkComponentProps } from "@tanstack/react-router"; +import { ArrowLeft } from "phosphor-react"; + +const link = css({ + cursor: "pointer", +}); + +interface BackButtonProps extends LinkComponentProps {} +export default function BackButton({ className, ...props }: BackButtonProps) { + return ( + + + + ); +} diff --git a/src/renderer/src/components/validate-dataset/index.tsx b/src/renderer/src/components/validate-dataset/index.tsx index 00b67514..617b964b 100644 --- a/src/renderer/src/components/validate-dataset/index.tsx +++ b/src/renderer/src/components/validate-dataset/index.tsx @@ -8,7 +8,7 @@ import { SectionTitle, } from "@/components"; import { useFileDispatch, useFiles } from "@/hooks"; -import { Footer, Section } from "@/layout/main"; +import { Footer, Section } from "@/layout/main-old"; import { validate } from "@/reducers/file/actions"; import { isFileValidated, isValidationCompleted } from "@/utils/file"; import { useNavigate, useParams } from "@tanstack/react-router"; @@ -95,12 +95,12 @@ export function ValidateDataset() { )} {canContinue ? ( - ) : (
diff --git a/src/renderer/src/layout/loading.tsx b/src/renderer/src/layout/loading.tsx index 566422be..5bcecbbd 100644 --- a/src/renderer/src/layout/loading.tsx +++ b/src/renderer/src/layout/loading.tsx @@ -22,7 +22,7 @@ export default function Loading() {
AymurAI iso white diff --git a/src/renderer/src/layout/main/index.ts b/src/renderer/src/layout/main-old/index.ts similarity index 92% rename from src/renderer/src/layout/main/index.ts rename to src/renderer/src/layout/main-old/index.ts index 2345c1ed..4fe431ab 100644 --- a/src/renderer/src/layout/main/index.ts +++ b/src/renderer/src/layout/main-old/index.ts @@ -1,5 +1,8 @@ import { styled } from "@/styles"; +/** + * @deprecated + */ export const Layout = styled("main", { height: "100vh", @@ -7,6 +10,9 @@ export const Layout = styled("main", { flexDirection: "column", }); +/** + * @deprecated + */ export const Header = styled("header", { display: "flex", flexDirection: "row", @@ -26,6 +32,9 @@ export const Header = styled("header", { }, }); +/** + * @deprecated + */ export const Section = styled("section", { px: 40, py: "$xxl", @@ -56,6 +65,9 @@ export const Section = styled("section", { }, }); +/** + * @deprecated + */ export const Footer = styled("nav", { display: "flex", flexDirection: "row", From 5f9104702f2ad94ae73f8115903fd4627204e358 Mon Sep 17 00:00:00 2001 From: front-end2-lgtm Date: Wed, 25 Feb 2026 17:31:17 -0400 Subject: [PATCH 061/263] chore: ignore personal analysis folder --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index a0792194..e31ba0eb 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ yarn-error.log* # Panda CSS generated files src/renderer/src/styled + +/me/ \ No newline at end of file From 146905fbeadfb1a6aaec543867b5d814b5cbb489 Mon Sep 17 00:00:00 2001 From: front-end2-lgtm Date: Wed, 25 Feb 2026 17:31:51 -0400 Subject: [PATCH 062/263] feat: improve topbar accessibility with semantic icons and aria labels --- src/renderer/src/components/features-menu.tsx | 6 +++--- src/renderer/src/components/home/stepper.tsx | 16 ++++++++++++++-- .../src/components/how-it-works-modal.tsx | 10 +++++++--- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/renderer/src/components/features-menu.tsx b/src/renderer/src/components/features-menu.tsx index 47a38bd9..118c9cc2 100644 --- a/src/renderer/src/components/features-menu.tsx +++ b/src/renderer/src/components/features-menu.tsx @@ -2,7 +2,7 @@ import { FEATURES } from "@/constants"; import { Grid, Stack, styled } from "@/styled/jsx"; import type { FeatureFlowEnum } from "@/types/features"; import { Link } from "@tanstack/react-router"; -import { DotsNine } from "phosphor-react"; +import { House } from "phosphor-react"; import FeatureIcon from "./feature-icon"; import Button from "./ui/button"; import Card from "./ui/card"; @@ -13,8 +13,8 @@ export default function FeaturesMenu() { return ( - diff --git a/src/renderer/src/components/home/stepper.tsx b/src/renderer/src/components/home/stepper.tsx index 901e7a56..78b34fef 100644 --- a/src/renderer/src/components/home/stepper.tsx +++ b/src/renderer/src/components/home/stepper.tsx @@ -57,10 +57,22 @@ interface StepProps { } function Step({ children, status, number }: StepProps) { const classes = step({ status }); + // Used to hide text from visuals but expose to screen readers + const srOnly = css({ + srOnly: true, + }); + return (
-
{number}
- {children} + + + Paso {number}: {children} + +
); } diff --git a/src/renderer/src/components/how-it-works-modal.tsx b/src/renderer/src/components/how-it-works-modal.tsx index f3e80a38..b6c0b90b 100644 --- a/src/renderer/src/components/how-it-works-modal.tsx +++ b/src/renderer/src/components/how-it-works-modal.tsx @@ -2,7 +2,7 @@ import { SectionTitle } from "@/layout/section-title"; import { css } from "@/styled/css"; import { HStack, Stack } from "@/styled/jsx"; import type { FeatureFlowEnum } from "@/types/features"; -import { Question, X } from "phosphor-react"; +import { Info, X } from "phosphor-react"; import HowItWorks from "./how-it-works"; import { Dialog, DialogClose, DialogContent, DialogTrigger } from "./ui/dialog"; import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"; @@ -45,8 +45,12 @@ export default function HowItWorksModal({ feature }: HowItWorksModalProps) { - From 244027be983a7a0806bed190a54c0c7e3040edd0 Mon Sep 17 00:00:00 2001 From: front-end2-lgtm Date: Wed, 25 Feb 2026 17:32:06 -0400 Subject: [PATCH 063/263] refactor(layout): hoist Topbar and Stepper to global wizard route --- .../src/routes/app.$feature/onboarding.tsx | 13 ------- .../src/routes/app.$feature/preview.tsx | 10 ++--- .../src/routes/app.$feature/route.tsx | 38 +++++++++++++++++-- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/renderer/src/routes/app.$feature/onboarding.tsx b/src/renderer/src/routes/app.$feature/onboarding.tsx index 40c91a68..01e00fba 100644 --- a/src/renderer/src/routes/app.$feature/onboarding.tsx +++ b/src/renderer/src/routes/app.$feature/onboarding.tsx @@ -5,12 +5,9 @@ import { } from "@tanstack/react-router"; import DropArea from "@/components/drop-area"; -import FeaturesMenu from "@/components/features-menu"; import HiddenInput from "@/components/hidden-input"; import HowItWorks from "@/components/how-it-works"; -import HowItWorksModal from "@/components/how-it-works-modal"; import Footer from "@/components/layout/footer"; -import Header from "@/components/layout/header"; import MainContent from "@/components/layout/main-content"; import BackButton from "@/components/ui/back-button"; import Button from "@/components/ui/button"; @@ -19,7 +16,6 @@ import { SectionTitle } from "@/layout/section-title"; import { addFiles } from "@/reducers/file/actions"; import { useSetTutorialSeen, useTutorialSeen } from "@/store/useLocal"; import { HStack, Stack, styled } from "@/styled/jsx"; -import { featureName } from "@/types/features"; import { useRef } from "react"; // FIRST step of the processing workflow @@ -59,15 +55,6 @@ function RouteComponent() { return ( <> -
- {tutorialSeen && } - - - } - /> {tutorialSeen ? ( diff --git a/src/renderer/src/routes/app.$feature/preview.tsx b/src/renderer/src/routes/app.$feature/preview.tsx index c3eddba4..5f12e1c3 100644 --- a/src/renderer/src/routes/app.$feature/preview.tsx +++ b/src/renderer/src/routes/app.$feature/preview.tsx @@ -9,13 +9,13 @@ import { Text, } from "@/components"; import { useFileDispatch, useFiles } from "@/hooks"; -import { Footer, Section } from "@/layout/main"; +import { Footer, Section } from "@/layout/main-old"; import { addFiles, filterUnselected, removeAllFiles, } from "@/reducers/file/actions"; -import { Feature } from "@/types/features"; +import { FeatureFlowEnum } from "@/types/features"; import { createFileRoute, useNavigate, @@ -105,7 +105,7 @@ function GenericPreview({ title, supportMultipleFiles }: GenericPreviewProps) { {supportMultipleFiles && ( <> Formatos válidos: .docx, .pdf - @@ -115,7 +115,7 @@ function GenericPreview({ title, supportMultipleFiles }: GenericPreviewProps) { disabled={ !isAnyFileSelected || files.some((f) => !f.paragraphs?.length) } - size="l" + size="md" > Continuar @@ -129,7 +129,7 @@ function RouteComponent() { from: "/app/$feature/preview", }); - if (feature === Feature.Dataset) + if (feature === FeatureFlowEnum.Dataset) return ( +
+ ) : undefined + } + right={ + + {tutorialSeen && } + + + } + /> From 36d70bbdb28df77d1728d79e8b31c70c494b8b40 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 2 Mar 2026 11:28:32 -0300 Subject: [PATCH 064/263] build: add i18n --- package.json | 2 ++ pnpm-lock.yaml | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/package.json b/package.json index d7aede53..d304cff8 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "electron-vite": "^3.1.0", "exceljs": "^4.4.0", "husky": "^8.0.0", + "i18next": "^25.8.13", "lint-staged": "^13.0.3", "markdownlint-cli": "^0.32.2", "nodemon": "^2.0.20", @@ -74,6 +75,7 @@ "prettier": "^2.7.1", "react": "19", "react-dom": "19", + "react-i18next": "^16.5.4", "regex-escape": "^3.4.10", "typescript": "^5.9.2", "vite": "^6.3.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d5c8f984..d39047aa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,12 @@ importers: electron-squirrel-startup: specifier: ^1.0.0 version: 1.0.1 + i18next: + specifier: ^25.8.13 + version: 25.8.13(typescript@5.9.2) + react-i18next: + specifier: ^16.5.4 + version: 16.5.4(i18next@25.8.13(typescript@5.9.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.2) devDependencies: '@biomejs/biome': specifier: ^1.9.4 @@ -329,6 +335,10 @@ packages: resolution: {integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + '@babel/template@7.27.2': resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} @@ -2757,6 +2767,9 @@ packages: resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} engines: {node: '>=10'} + html-parse-stringify@3.0.1: + resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} + http-cache-semantics@4.2.0: resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} @@ -2796,6 +2809,14 @@ packages: engines: {node: '>=14'} hasBin: true + i18next@25.8.13: + resolution: {integrity: sha512-E0vzjBY1yM+nsFrtgkjLhST2NBkirkvOVoQa0MSldhsuZ3jUge7ZNpuwG0Cfc74zwo5ZwRzg3uOgT+McBn32iA==} + peerDependencies: + typescript: ^5 + peerDependenciesMeta: + typescript: + optional: true + iconv-corefoundation@1.1.7: resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==} engines: {node: ^8.11.2 || >=10} @@ -3862,6 +3883,22 @@ packages: peerDependencies: react: ^19.2.4 + react-i18next@16.5.4: + resolution: {integrity: sha512-6yj+dcfMncEC21QPhOTsW8mOSO+pzFmT6uvU7XXdvM/Cp38zJkmTeMeKmTrmCMD5ToT79FmiE/mRWiYWcJYW4g==} + peerDependencies: + i18next: '>= 25.6.2' + react: '>= 16.8.0' + react-dom: '*' + react-native: '*' + typescript: ^5 + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + typescript: + optional: true + react-refresh@0.17.0: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} @@ -4640,6 +4677,10 @@ packages: yaml: optional: true + void-elements@3.1.0: + resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} + engines: {node: '>=0.10.0'} + wait-on@6.0.1: resolution: {integrity: sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==} engines: {node: '>=10.0.0'} @@ -5024,6 +5065,8 @@ snapshots: '@babel/runtime@7.27.1': {} + '@babel/runtime@7.28.6': {} + '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 @@ -8060,6 +8103,10 @@ snapshots: dependencies: lru-cache: 6.0.0 + html-parse-stringify@3.0.1: + dependencies: + void-elements: 3.1.0 + http-cache-semantics@4.2.0: {} http-errors@2.0.1: @@ -8112,6 +8159,12 @@ snapshots: husky@8.0.3: {} + i18next@25.8.13(typescript@5.9.2): + dependencies: + '@babel/runtime': 7.28.6 + optionalDependencies: + typescript: 5.9.2 + iconv-corefoundation@1.1.7: dependencies: cli-truncate: 2.1.0 @@ -9033,6 +9086,17 @@ snapshots: react: 19.2.4 scheduler: 0.27.0 + react-i18next@16.5.4(i18next@25.8.13(typescript@5.9.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.2): + dependencies: + '@babel/runtime': 7.28.6 + html-parse-stringify: 3.0.1 + i18next: 25.8.13(typescript@5.9.2) + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) + optionalDependencies: + react-dom: 19.2.4(react@19.2.4) + typescript: 5.9.2 + react-refresh@0.17.0: {} react-remove-scroll-bar@2.3.8(@types/react@19.2.13)(react@19.2.4): @@ -9807,6 +9871,8 @@ snapshots: lightningcss: 1.30.2 tsx: 4.20.6 + void-elements@3.1.0: {} + wait-on@6.0.1: dependencies: axios: 0.25.0 From 59dc125eb3b699bb9596304aa97fb0b0bfa58d7a Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 2 Mar 2026 13:49:57 -0300 Subject: [PATCH 065/263] feat: add i18n support for the whole app --- .../src/components/brand/built-by.tsx | 6 +- src/renderer/src/components/drop-area.tsx | 16 ++-- src/renderer/src/components/feature-icon.tsx | 4 +- src/renderer/src/components/features-menu.tsx | 20 ++--- .../src/components/file-preview/index.tsx | 4 +- .../src/components/hidden-input-old/index.tsx | 2 +- src/renderer/src/components/hidden-input.tsx | 2 +- .../src/components/home/choose-host.tsx | 25 +++--- .../src/components/home/connect-to-host.tsx | 87 ++++++++++--------- src/renderer/src/components/home/stepper.tsx | 11 ++- .../src/components/how-it-works-modal.tsx | 7 +- src/renderer/src/components/how-it-works.tsx | 60 ++++++------- src/renderer/src/constants.ts | 25 ------ src/renderer/src/constants/config.ts | 6 ++ src/renderer/src/constants/i18n/index.ts | 27 ++++++ .../constants/i18n/locales/es/anonymizer.ts | 29 +++++++ .../src/constants/i18n/locales/es/common.ts | 62 +++++++++++++ .../src/constants/i18n/locales/es/dataset.ts | 28 ++++++ .../src/constants/i18n/locales/es/index.ts | 11 +++ src/renderer/src/main.tsx | 1 + .../src/routes/app.$feature/onboarding.tsx | 14 +-- src/renderer/src/routes/home/features.tsx | 18 ++-- src/renderer/src/types/features.ts | 12 +-- src/renderer/src/utils/file/isAllowed.ts | 2 +- 24 files changed, 319 insertions(+), 160 deletions(-) delete mode 100644 src/renderer/src/constants.ts create mode 100644 src/renderer/src/constants/config.ts create mode 100644 src/renderer/src/constants/i18n/index.ts create mode 100644 src/renderer/src/constants/i18n/locales/es/anonymizer.ts create mode 100644 src/renderer/src/constants/i18n/locales/es/common.ts create mode 100644 src/renderer/src/constants/i18n/locales/es/dataset.ts create mode 100644 src/renderer/src/constants/i18n/locales/es/index.ts diff --git a/src/renderer/src/components/brand/built-by.tsx b/src/renderer/src/components/brand/built-by.tsx index b9717ff2..a3d01812 100644 --- a/src/renderer/src/components/brand/built-by.tsx +++ b/src/renderer/src/components/brand/built-by.tsx @@ -1,12 +1,14 @@ -import { DATAGENERO_URL } from "@/constants"; +import { DATAGENERO_URL } from "@/constants/config"; import { styled } from "@/styled/jsx"; import { type StackStyles, stack } from "@/styled/patterns"; +import { useTranslation } from "react-i18next"; interface BuiltByProps { size?: number; gap?: StackStyles["gap"]; } export default function BuiltBy({ size = 150, gap = "2" }: BuiltByProps) { + const { t } = useTranslation(); return ( - Plataforma hecha por + {t("platformBuiltBy")} DataGenero isologo diff --git a/src/renderer/src/components/drop-area.tsx b/src/renderer/src/components/drop-area.tsx index 02eae626..621b3364 100644 --- a/src/renderer/src/components/drop-area.tsx +++ b/src/renderer/src/components/drop-area.tsx @@ -1,8 +1,9 @@ -import { WHITELISTED_EXTENSIONS } from "@/constants"; +import { WHITELISTED_EXTENSIONS } from "@/constants/config"; import { css, cva } from "@/styled/css"; import { Stack, styled } from "@/styled/jsx"; import { File } from "phosphor-react"; import { useCallback, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; function FileIcon() { return ( @@ -59,6 +60,7 @@ export default function DropArea({ onDropFiles, multiple = true, }: DropAreaProps) { + const { t } = useTranslation(); const [dragging, setDragging] = useState(false); const inputRef = useRef(null); const dragCounter = useRef(0); @@ -125,13 +127,15 @@ export default function DropArea({ > - - Selecciona el archivo para -
- agregar a la base de datos + + {t("dropArea.selectFile")} - Formatos válidos:{" "} + {t("dropArea.validFormats")}{" "} {WHITELISTED_EXTENSIONS.map((e) => `.${e}`).join(", ")}
diff --git a/src/renderer/src/components/feature-icon.tsx b/src/renderer/src/components/feature-icon.tsx index 5546851f..d83f1d5b 100644 --- a/src/renderer/src/components/feature-icon.tsx +++ b/src/renderer/src/components/feature-icon.tsx @@ -1,7 +1,7 @@ -import { FEATURES } from "@/constants"; import { cva } from "@/styled/css"; import { stack } from "@/styled/patterns"; import type { FeatureFlowEnum } from "@/types/features"; +import { FEATURE_ICON } from "@/utils/config"; import type { Icon } from "phosphor-react"; const styles = cva({ @@ -56,7 +56,7 @@ export default function FeatureIcon({ icon: OverrideIcon, disabled = false, }: FeatureIconProps) { - const Icon = OverrideIcon ?? FEATURES[feature].icon; + const Icon = OverrideIcon ?? FEATURE_ICON[feature]; return (
diff --git a/src/renderer/src/components/features-menu.tsx b/src/renderer/src/components/features-menu.tsx index 47a38bd9..7f013e49 100644 --- a/src/renderer/src/components/features-menu.tsx +++ b/src/renderer/src/components/features-menu.tsx @@ -1,15 +1,17 @@ -import { FEATURES } from "@/constants"; import { Grid, Stack, styled } from "@/styled/jsx"; -import type { FeatureFlowEnum } from "@/types/features"; +import { FeatureFlowEnum, featureNamespace } from "@/types/features"; import { Link } from "@tanstack/react-router"; import { DotsNine } from "phosphor-react"; +import { useTranslation } from "react-i18next"; import FeatureIcon from "./feature-icon"; import Button from "./ui/button"; import Card from "./ui/card"; import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover"; export default function FeaturesMenu() { - const features = Object.entries(FEATURES); + const { t } = useTranslation(); + const features = Object.values(FeatureFlowEnum); + return ( @@ -19,17 +21,13 @@ export default function FeaturesMenu() { - {features.map(([value, feature]) => ( - + {features.map((feature) => ( + - + - {feature.title} + {t("title", { ns: featureNamespace[feature] })} diff --git a/src/renderer/src/components/file-preview/index.tsx b/src/renderer/src/components/file-preview/index.tsx index a8a2ed88..e1847514 100644 --- a/src/renderer/src/components/file-preview/index.tsx +++ b/src/renderer/src/components/file-preview/index.tsx @@ -8,6 +8,7 @@ import type { DocFile } from "@/types/file"; import { FeatureFlowEnum } from "@/types/features"; import { useParams } from "@tanstack/react-router"; +import { useTranslation } from "react-i18next"; import * as S from "./FilePreview.styles"; interface Props { @@ -15,6 +16,7 @@ interface Props { } export default function FilePreview({ file }: Props) { const { feature } = useParams({ from: "/app/$feature/preview" }); + const { t } = useTranslation(); const dispatch = useFileDispatch(); const { data: parsedFile, isError, isPending } = useFileParser(file.data); @@ -42,7 +44,7 @@ export default function FilePreview({ file }: Props) { title={file.data.name} size="xs" > - No se pudo cargar el archivo + {t("filePreview.loadError")} ); diff --git a/src/renderer/src/components/hidden-input-old/index.tsx b/src/renderer/src/components/hidden-input-old/index.tsx index bea4c95f..3fede5e3 100644 --- a/src/renderer/src/components/hidden-input-old/index.tsx +++ b/src/renderer/src/components/hidden-input-old/index.tsx @@ -1,6 +1,6 @@ import { forwardRef } from "react"; -import { WHITELISTED_EXTENSIONS } from "@/constants"; +import { WHITELISTED_EXTENSIONS } from "@/constants/config"; import type { CSS } from "@/styles"; import type { NativeComponent } from "@/types/component"; import Input from "./HiddenInput.styles"; diff --git a/src/renderer/src/components/hidden-input.tsx b/src/renderer/src/components/hidden-input.tsx index 71738994..c7e2d085 100644 --- a/src/renderer/src/components/hidden-input.tsx +++ b/src/renderer/src/components/hidden-input.tsx @@ -1,4 +1,4 @@ -import { WHITELISTED_EXTENSIONS } from "@/constants"; +import { WHITELISTED_EXTENSIONS } from "@/constants/config"; import { css, cx } from "@/styled/css"; import type { ComponentProps } from "react"; diff --git a/src/renderer/src/components/home/choose-host.tsx b/src/renderer/src/components/home/choose-host.tsx index cc8a36a7..c2ee45a2 100644 --- a/src/renderer/src/components/home/choose-host.tsx +++ b/src/renderer/src/components/home/choose-host.tsx @@ -1,9 +1,10 @@ import { Button } from "@/components"; import { useRunLocalServer } from "@/services/aymurai"; import { css } from "@/styled/css"; -import { stack } from "@/styled/patterns"; +import { Stack } from "@/styled/jsx"; import { useNavigate } from "@tanstack/react-router"; import { HardDrives, Monitor } from "phosphor-react"; +import { useTranslation } from "react-i18next"; interface ChooseHostProps { onRemoteClick: () => void; @@ -17,40 +18,42 @@ export default function ChooseHost({ onRemoteClick }: ChooseHostProps) { }), }); + const { t } = useTranslation(); + return ( -
+ Logotipo AymurAI -
+

- ¿Como deseas conectarte a Aymurai? + {t("home.host.howToConnect")}

-
+

- o + {t("home.host.optionOr")}

-
-
-
+ + + ); } diff --git a/src/renderer/src/components/home/connect-to-host.tsx b/src/renderer/src/components/home/connect-to-host.tsx index b1bdb444..8581f422 100644 --- a/src/renderer/src/components/home/connect-to-host.tsx +++ b/src/renderer/src/components/home/connect-to-host.tsx @@ -5,7 +5,12 @@ import { Stack } from "@/styled/jsx"; import { useNavigate } from "@tanstack/react-router"; import { AxiosError } from "axios"; import { ArrowLeft } from "phosphor-react"; -import { type ChangeEventHandler, useState } from "react"; +import { + type ChangeEventHandler, + type SubmitEventHandler, + useState, +} from "react"; +import { useTranslation } from "react-i18next"; import { ZodError } from "zod"; import Button from "../ui/button"; import Input from "../ui/input"; @@ -32,6 +37,7 @@ export default function ConnectToHost({ onBackClick }: ConnectToHostProps) { const navigate = useNavigate(); const remoteHost = localStore.useServerHost() ?? ""; const { setServerHost } = localStore.useServerHostActions(); + const { t } = useTranslation(); const [host, setHost] = useState(remoteHost); @@ -42,10 +48,9 @@ export default function ConnectToHost({ onBackClick }: ConnectToHostProps) { reset(); }; - const tryConnection = () => { - // navigate({ - // to: "/home/features", - // }); + const tryConnection: SubmitEventHandler = (e) => { + e.preventDefault(); + connectToHost(host, { onSuccess: () => { setServerHost(host); @@ -56,46 +61,48 @@ export default function ConnectToHost({ onBackClick }: ConnectToHostProps) { }); }; + const errorMessage = (err: Error | null): string => { + console.error(err); + if (err instanceof AxiosError) { + if (err.code === "ERR_NETWORK") return t("home.host.errors.network"); + return t("home.host.errors.connection"); + } + + if (err instanceof ZodError) { + return t("home.host.errors.invalidResponse"); + } + + if (err instanceof TypeError) { + return t("home.host.errors.invalidUrl"); + } + + return t("home.host.errors.unknown"); + }; + return ( <> - -

- Ingresa la dirección del servidor al que deseas conectarte -

+
+ +

+ {t("home.host.connectServerExplanation")} +

- - - + + + - -
+ + +
); } - -function errorMessage(err: Error | null): string { - console.error(err); - if (err instanceof AxiosError) { - if (err.code === "ERR_NETWORK") return "No se pudo conectar al servidor"; - return "Error de conexión"; - } - - if (err instanceof ZodError) { - return "El servidor no respondió correctamente"; - } - - if (err instanceof TypeError) { - return "El formato de la URL es incorrecto."; - } - - return "Error desconocido"; -} diff --git a/src/renderer/src/components/home/stepper.tsx b/src/renderer/src/components/home/stepper.tsx index 901e7a56..6e680d42 100644 --- a/src/renderer/src/components/home/stepper.tsx +++ b/src/renderer/src/components/home/stepper.tsx @@ -1,5 +1,6 @@ import { css, sva } from "@/styled/css"; import { stack } from "@/styled/patterns"; +import { useTranslation } from "react-i18next"; const stepper = css({ ...stack.raw({ align: "center", direction: "row" }), @@ -69,6 +70,8 @@ interface StepperProps { currentStep: number; } export default function Stepper({ currentStep }: StepperProps) { + const { t } = useTranslation(); + const status = (step: number): StepStatus => { if (step === currentStep) return "in_progress"; if (step > currentStep) return "pending"; @@ -78,16 +81,16 @@ export default function Stepper({ currentStep }: StepperProps) { return (
- Selección + {t("stepper.selection")} - Extracción + {t("stepper.extraction")} - Validación + {t("stepper.validation")} - Finalización + {t("stepper.finalization")}
); diff --git a/src/renderer/src/components/how-it-works-modal.tsx b/src/renderer/src/components/how-it-works-modal.tsx index f3e80a38..65c7e999 100644 --- a/src/renderer/src/components/how-it-works-modal.tsx +++ b/src/renderer/src/components/how-it-works-modal.tsx @@ -3,6 +3,7 @@ import { css } from "@/styled/css"; import { HStack, Stack } from "@/styled/jsx"; import type { FeatureFlowEnum } from "@/types/features"; import { Question, X } from "phosphor-react"; +import { useTranslation } from "react-i18next"; import HowItWorks from "./how-it-works"; import { Dialog, DialogClose, DialogContent, DialogTrigger } from "./ui/dialog"; import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"; @@ -40,6 +41,8 @@ interface HowItWorksModalProps { feature: FeatureFlowEnum; } export default function HowItWorksModal({ feature }: HowItWorksModalProps) { + const { t } = useTranslation(); + return ( @@ -50,14 +53,14 @@ export default function HowItWorksModal({ feature }: HowItWorksModalProps) { - ¿Cómo funciona? + {t("howItWorks")} - ¿Cómo funciona? + {t("howItWorks")} diff --git a/src/renderer/src/components/how-it-works.tsx b/src/renderer/src/components/how-it-works.tsx index 9e619fe4..a1adbd79 100644 --- a/src/renderer/src/components/how-it-works.tsx +++ b/src/renderer/src/components/how-it-works.tsx @@ -2,7 +2,8 @@ import { SectionTitle } from "@/layout/section-title"; import { css } from "@/styled/css"; import { Grid, Stack, styled } from "@/styled/jsx"; import { hstack, stack } from "@/styled/patterns"; -import { FeatureFlowEnum } from "@/types/features"; +import { type FeatureFlowEnum, featureNamespace } from "@/types/features"; +import { useTranslation } from "react-i18next"; const card = css({ ...hstack.raw({ gap: "4", alignItems: "center" }), @@ -53,12 +54,16 @@ interface HowItWorksProps { title?: React.ReactNode; feature: FeatureFlowEnum; } -export default function HowItWorks({ - title = "¿Cómo funciona?", - feature, -}: HowItWorksProps) { +export default function HowItWorks({ title, feature }: HowItWorksProps) { + const { t } = useTranslation(); + const { t: tFeature } = useTranslation(featureNamespace[feature]); + const renderTitle = - typeof title === "string" ? {title} : title; + typeof title === "string" ? ( + {title} + ) : ( + (title ?? {t("howItWorks")}) + ); return ( @@ -66,43 +71,32 @@ export default function HowItWorks({ - {/* Last step depends on the feature we're seeing */} - {feature === FeatureFlowEnum.Dataset ? ( - - ) : ( - - )} + ); diff --git a/src/renderer/src/constants.ts b/src/renderer/src/constants.ts deleted file mode 100644 index 22b14f47..00000000 --- a/src/renderer/src/constants.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Database, Detective, type Icon } from "phosphor-react"; -import { FeatureFlowEnum, featureName } from "./types/features"; - -export const DATAGENERO_URL = "https://www.datagenero.org/"; - -type Feature = { title: string; subtitle: string; icon: Icon }; - -export const FEATURES: Record = { - [FeatureFlowEnum.Dataset]: { - title: featureName(FeatureFlowEnum.Dataset), - subtitle: "Convertí resoluciones judiciales en set de datos estructurados", - icon: Database, - }, - [FeatureFlowEnum.Anonymizer]: { - title: featureName(FeatureFlowEnum.Anonymizer), - subtitle: - "Anonimiza resoluciones judiciales de manera automática y editable", - icon: Detective, - }, -}; - -/** - * Only allow these extensions to be analyzed - */ -export const WHITELISTED_EXTENSIONS = ["doc", "docx", "pdf"]; diff --git a/src/renderer/src/constants/config.ts b/src/renderer/src/constants/config.ts new file mode 100644 index 00000000..fe82c644 --- /dev/null +++ b/src/renderer/src/constants/config.ts @@ -0,0 +1,6 @@ +export const DATAGENERO_URL = "https://www.datagenero.org/"; + +/** + * Only allow these extensions to be analyzed + */ +export const WHITELISTED_EXTENSIONS = ["doc", "docx", "pdf"]; diff --git a/src/renderer/src/constants/i18n/index.ts b/src/renderer/src/constants/i18n/index.ts new file mode 100644 index 00000000..06b788ca --- /dev/null +++ b/src/renderer/src/constants/i18n/index.ts @@ -0,0 +1,27 @@ +import i18n from "i18next"; +import { initReactI18next } from "react-i18next"; +import es from "./locales/es"; + +// --- TypeScript type augmentation --- +// Tells i18next the exact shape of every namespace, +// so t('key') calls are fully typed and autocompleted. +declare module "i18next" { + interface CustomTypeOptions { + defaultNS: "common"; + resources: typeof es; + } +} + +i18n.use(initReactI18next).init({ + lng: "es", + fallbackLng: "es", + defaultNS: "common", + resources: { + es, + }, + interpolation: { + escapeValue: false, // React already escapes values + }, +}); + +export default i18n; diff --git a/src/renderer/src/constants/i18n/locales/es/anonymizer.ts b/src/renderer/src/constants/i18n/locales/es/anonymizer.ts new file mode 100644 index 00000000..d8336ada --- /dev/null +++ b/src/renderer/src/constants/i18n/locales/es/anonymizer.ts @@ -0,0 +1,29 @@ +const anonymizer = { + title: "Anonimizador", + subtitle: + "Anonimiza resoluciones judiciales de manera automática y editable", + onboarding: { + sectionTitle: "1. Selección de Archivos", + validFormats: "Formatos válidos: .doc y .docx", + loadDocuments: "Cargar documentos", + }, + preview: { + sectionTitle: "1. Selección de Archivos", + filesLabel: "Archivos seleccionados", + validFormats: "Formatos válidos: .doc y .docx", + loadMore: "Cargar más documentos", + continue: "Continuar", + }, + howItWorks: { + step4: { + alt: "Binoculares con globo terráqueo", + title: "Generación del documento anonimizado", + subtitle: + "Proceso terminado. El documento esta listo para ser exportado.", + }, + }, + process: { sectionTitle: "" }, + result: { sectionTitle: "" }, +}; + +export default anonymizer; diff --git a/src/renderer/src/constants/i18n/locales/es/common.ts b/src/renderer/src/constants/i18n/locales/es/common.ts new file mode 100644 index 00000000..c2d9f92a --- /dev/null +++ b/src/renderer/src/constants/i18n/locales/es/common.ts @@ -0,0 +1,62 @@ +const common = { + back: "Volver", + howItWorks: "¿Cómo funciona?", + platformBuiltBy: "Plataforma hecha por", + home: { + features: { + greeting: "¡Hola! Selecciona la herramienta a utilizar", + }, + host: { + howToConnect: "¿Como deseas conectarte a Aymurai?", + optionLocal: "Local", + optionServer: "Servidor", + optionOr: "o", + connectServerExplanation: + "Ingresa la dirección del servidor al que deseas conectarte", + connectServerLabel: "Direccion del servidor", + connectServerSubmit: "Guardar y conectar", + errors: { + network: "No se pudo conectar al servidor", + connection: "Error de conexión", + invalidResponse: "El servidor no respondió correctamente", + invalidUrl: "El formato de la URL es incorrecto.", + unknown: "Error desconocido", + }, + }, + }, + stepper: { + selection: "Selección", + extraction: "Extracción", + validation: "Validación", + finalization: "Finalización", + }, + howItWorksSteps: { + step1: { + alt: "Interfaz web con selector y cursor", + title: "Selecciona las resoluciones judiciales", + subtitle: + "Sube los documentos que querés incorporar al set de datos.", + }, + step2: { + alt: "Barra de búsqueda con cursor", + title: "La inteligencia artificial analiza los documentos", + subtitle: + "Extrae automáticamente la información relevante de cada documento.", + }, + step3: { + alt: "Visor de documentos con controles de revisión", + title: "Revisión y validación humana", + subtitle: + "Es importante que verifiques que los datos sean correctos antes de exportar el archivo", + }, + }, + dropArea: { + selectFile: "Selecciona el archivo para\nagregar a la base de datos", + validFormats: "Formatos válidos:", + }, + filePreview: { + loadError: "No se pudo cargar el archivo", + }, +}; + +export default common; diff --git a/src/renderer/src/constants/i18n/locales/es/dataset.ts b/src/renderer/src/constants/i18n/locales/es/dataset.ts new file mode 100644 index 00000000..df15e86d --- /dev/null +++ b/src/renderer/src/constants/i18n/locales/es/dataset.ts @@ -0,0 +1,28 @@ +const dataset = { + title: "Set de datos", + subtitle: "Convertí resoluciones judiciales en set de datos estructurados", + onboarding: { + sectionTitle: "1. Selección de Archivos", + validFormats: "Formatos válidos: .doc y .docx", + loadDocuments: "Cargar documentos", + }, + preview: { + sectionTitle: "1. Selección de Archivos", + filesLabel: "Archivos seleccionados", + validFormats: "Formatos válidos: .doc y .docx", + loadMore: "Cargar más documentos", + continue: "Continuar", + }, + howItWorks: { + step4: { + alt: "Binoculares con globo terráqueo", + title: "Generación del set de datos", + subtitle: + "Los documentos pasan a formar parte del set de datos abiertos.", + }, + }, + process: { sectionTitle: "" }, + result: { sectionTitle: "" }, +}; + +export default dataset; diff --git a/src/renderer/src/constants/i18n/locales/es/index.ts b/src/renderer/src/constants/i18n/locales/es/index.ts new file mode 100644 index 00000000..d3cf487c --- /dev/null +++ b/src/renderer/src/constants/i18n/locales/es/index.ts @@ -0,0 +1,11 @@ +import anonymizer from "./anonymizer"; +import common from "./common"; +import dataset from "./dataset"; + +const es = { + common, + dataset, + anonymizer, +}; + +export default es; diff --git a/src/renderer/src/main.tsx b/src/renderer/src/main.tsx index c1a50bac..9f8c88be 100644 --- a/src/renderer/src/main.tsx +++ b/src/renderer/src/main.tsx @@ -2,6 +2,7 @@ import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; +import "./constants/i18n"; import App from "./app"; ReactDOM.createRoot(document.getElementById("root")!).render( diff --git a/src/renderer/src/routes/app.$feature/onboarding.tsx b/src/renderer/src/routes/app.$feature/onboarding.tsx index 40c91a68..a48ba6b4 100644 --- a/src/renderer/src/routes/app.$feature/onboarding.tsx +++ b/src/renderer/src/routes/app.$feature/onboarding.tsx @@ -19,8 +19,9 @@ import { SectionTitle } from "@/layout/section-title"; import { addFiles } from "@/reducers/file/actions"; import { useSetTutorialSeen, useTutorialSeen } from "@/store/useLocal"; import { HStack, Stack, styled } from "@/styled/jsx"; -import { featureName } from "@/types/features"; +import { featureNamespace } from "@/types/features"; import { useRef } from "react"; +import { useTranslation } from "react-i18next"; // FIRST step of the processing workflow export const Route = createFileRoute("/app/$feature/onboarding")({ @@ -32,6 +33,7 @@ function RouteComponent() { from: "/app/$feature/onboarding", }); const navigate = useNavigate(); + const { t } = useTranslation(featureNamespace[feature]); const inputRef = useRef(null); @@ -60,7 +62,7 @@ function RouteComponent() { return ( <>
{tutorialSeen && } @@ -73,7 +75,7 @@ function RouteComponent() { - 1. Selección de Archivos + {t("onboarding.sectionTitle")} @@ -85,10 +87,12 @@ function RouteComponent() { {!tutorialSeen && ( - Formatos válidos: .doc y .docx + {t("onboarding.validFormats")} )} - + diff --git a/src/renderer/src/routes/home/features.tsx b/src/renderer/src/routes/home/features.tsx index 21ce5cff..da97b956 100644 --- a/src/renderer/src/routes/home/features.tsx +++ b/src/renderer/src/routes/home/features.tsx @@ -3,7 +3,8 @@ import FeaturesMenu from "@/components/features-menu"; import Header from "@/components/layout/header"; import MainContent from "@/components/layout/main-content"; import Card from "@/components/ui/card"; -import { FEATURES } from "@/constants"; +import { FEATURES } from "@/constants/config"; +import { css } from "@/styled/css"; import { Grid, Stack, styled } from "@/styled/jsx"; import { FeatureFlowEnum } from "@/types/features"; import { @@ -12,6 +13,7 @@ import { createFileRoute, } from "@tanstack/react-router"; import type { Icon } from "phosphor-react"; +import { useTranslation } from "react-i18next"; interface CardToolProps extends LinkComponentProps { title: string; @@ -28,7 +30,7 @@ function CardTool({ }: CardToolProps) { return ( - + @@ -48,28 +50,30 @@ export const Route = createFileRoute("/home/features")({ }); function RouteComponent() { + const { t } = useTranslation(["common", "dataset", "anonymizer"]); + return (
} /> - ¡Hola! Selecciona la herramienta a utilizar + {t("home.features.greeting")} {/* FIXME: fix the text wrapping on smaller screens */} diff --git a/src/renderer/src/types/features.ts b/src/renderer/src/types/features.ts index bb05e2f6..0dce5042 100644 --- a/src/renderer/src/types/features.ts +++ b/src/renderer/src/types/features.ts @@ -3,11 +3,7 @@ export enum FeatureFlowEnum { Anonymizer = "ANONYMIZER", } -export const featureName = (feature: FeatureFlowEnum): string => { - const names: Record = { - [FeatureFlowEnum.Dataset]: "Set de datos", - [FeatureFlowEnum.Anonymizer]: "Anonimizador", - }; - - return names[feature]; -}; +export const featureNamespace = { + [FeatureFlowEnum.Dataset]: "dataset", + [FeatureFlowEnum.Anonymizer]: "anonymizer", +} as const satisfies Record; diff --git a/src/renderer/src/utils/file/isAllowed.ts b/src/renderer/src/utils/file/isAllowed.ts index 580f8b44..ddc35d93 100644 --- a/src/renderer/src/utils/file/isAllowed.ts +++ b/src/renderer/src/utils/file/isAllowed.ts @@ -1,4 +1,4 @@ -import { WHITELISTED_EXTENSIONS } from "@/constants"; +import { WHITELISTED_EXTENSIONS } from "@/constants/config"; import getExtension from "./getExtension"; /** From cd15a776d3356cc0da3d330fd86dc2a880ddf404 Mon Sep 17 00:00:00 2001 From: front-end2-lgtm Date: Fri, 20 Mar 2026 10:09:05 -0400 Subject: [PATCH 066/263] fix(layout): address PR review on header and icon changes - Replace House icon with DotsNine in FeaturesMenu - Replace Info icon with Question in HowItWorksModal - Remove Header from shared route layout (route.tsx) - Restore Header to onboarding.tsx and add it to each feature page - Each page now controls its own Header, Stepper step, and right section --- src/renderer/src/components/features-menu.tsx | 4 +-- .../src/components/how-it-works-modal.tsx | 4 +-- .../src/routes/app.$feature/finish.tsx | 34 +++++++++++++++++-- .../src/routes/app.$feature/onboarding.tsx | 19 +++++++++++ .../src/routes/app.$feature/preview.tsx | 23 ++++++++++++- .../src/routes/app.$feature/process.tsx | 23 ++++++++++++- .../src/routes/app.$feature/route.tsx | 34 ++----------------- .../src/routes/app.$feature/validation.tsx | 34 +++++++++++++++++-- 8 files changed, 131 insertions(+), 44 deletions(-) diff --git a/src/renderer/src/components/features-menu.tsx b/src/renderer/src/components/features-menu.tsx index 118c9cc2..c5ec83c9 100644 --- a/src/renderer/src/components/features-menu.tsx +++ b/src/renderer/src/components/features-menu.tsx @@ -2,7 +2,7 @@ import { FEATURES } from "@/constants"; import { Grid, Stack, styled } from "@/styled/jsx"; import type { FeatureFlowEnum } from "@/types/features"; import { Link } from "@tanstack/react-router"; -import { House } from "phosphor-react"; +import { DotsNine } from "phosphor-react"; import FeatureIcon from "./feature-icon"; import Button from "./ui/button"; import Card from "./ui/card"; @@ -14,7 +14,7 @@ export default function FeaturesMenu() { diff --git a/src/renderer/src/components/how-it-works-modal.tsx b/src/renderer/src/components/how-it-works-modal.tsx index b6c0b90b..5c76eb04 100644 --- a/src/renderer/src/components/how-it-works-modal.tsx +++ b/src/renderer/src/components/how-it-works-modal.tsx @@ -2,7 +2,7 @@ import { SectionTitle } from "@/layout/section-title"; import { css } from "@/styled/css"; import { HStack, Stack } from "@/styled/jsx"; import type { FeatureFlowEnum } from "@/types/features"; -import { Info, X } from "phosphor-react"; +import { Question, X } from "phosphor-react"; import HowItWorks from "./how-it-works"; import { Dialog, DialogClose, DialogContent, DialogTrigger } from "./ui/dialog"; import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"; @@ -50,7 +50,7 @@ export default function HowItWorksModal({ feature }: HowItWorksModalProps) { className={modalButton} aria-label="Información sobre AymurAI" > - + diff --git a/src/renderer/src/routes/app.$feature/finish.tsx b/src/renderer/src/routes/app.$feature/finish.tsx index 0c1797ae..c66d3bca 100644 --- a/src/renderer/src/routes/app.$feature/finish.tsx +++ b/src/renderer/src/routes/app.$feature/finish.tsx @@ -1,5 +1,11 @@ import { FinishAnonymizer, FinishDataset } from "@/components"; -import { FeatureFlowEnum } from "@/types/features"; +import FeaturesMenu from "@/components/features-menu"; +import HowItWorksModal from "@/components/how-it-works-modal"; +import Stepper from "@/components/home/stepper"; +import Header from "@/components/layout/header"; +import { useTutorialSeen } from "@/store/useLocal"; +import { HStack } from "@/styled/jsx"; +import { FeatureFlowEnum, featureName } from "@/types/features"; import { createFileRoute, useParams } from "@tanstack/react-router"; export const Route = createFileRoute("/app/$feature/finish")({ @@ -8,7 +14,29 @@ export const Route = createFileRoute("/app/$feature/finish")({ function RouteComponent() { const { feature } = useParams({ from: "/app/$feature/finish" }); + const tutorialSeen = useTutorialSeen(feature); - if (feature === FeatureFlowEnum.Dataset) return ; - return ; + return ( + <> +
+ ) : undefined + } + right={ + + {tutorialSeen && } + + + } + /> + {feature === FeatureFlowEnum.Dataset ? ( + + ) : ( + + )} + + ); } diff --git a/src/renderer/src/routes/app.$feature/onboarding.tsx b/src/renderer/src/routes/app.$feature/onboarding.tsx index 01e00fba..34ae7fa5 100644 --- a/src/renderer/src/routes/app.$feature/onboarding.tsx +++ b/src/renderer/src/routes/app.$feature/onboarding.tsx @@ -5,9 +5,13 @@ import { } from "@tanstack/react-router"; import DropArea from "@/components/drop-area"; +import FeaturesMenu from "@/components/features-menu"; import HiddenInput from "@/components/hidden-input"; import HowItWorks from "@/components/how-it-works"; +import HowItWorksModal from "@/components/how-it-works-modal"; +import Stepper from "@/components/home/stepper"; import Footer from "@/components/layout/footer"; +import Header from "@/components/layout/header"; import MainContent from "@/components/layout/main-content"; import BackButton from "@/components/ui/back-button"; import Button from "@/components/ui/button"; @@ -16,6 +20,7 @@ import { SectionTitle } from "@/layout/section-title"; import { addFiles } from "@/reducers/file/actions"; import { useSetTutorialSeen, useTutorialSeen } from "@/store/useLocal"; import { HStack, Stack, styled } from "@/styled/jsx"; +import { FeatureFlowEnum, featureName } from "@/types/features"; import { useRef } from "react"; // FIRST step of the processing workflow @@ -55,6 +60,20 @@ function RouteComponent() { return ( <> +
+ ) : undefined + } + right={ + + {tutorialSeen && } + + + } + /> {tutorialSeen ? ( diff --git a/src/renderer/src/routes/app.$feature/preview.tsx b/src/renderer/src/routes/app.$feature/preview.tsx index 5f12e1c3..94cdf5ef 100644 --- a/src/renderer/src/routes/app.$feature/preview.tsx +++ b/src/renderer/src/routes/app.$feature/preview.tsx @@ -8,6 +8,10 @@ import { Subtitle, Text, } from "@/components"; +import FeaturesMenu from "@/components/features-menu"; +import HowItWorksModal from "@/components/how-it-works-modal"; +import Stepper from "@/components/home/stepper"; +import Header from "@/components/layout/header"; import { useFileDispatch, useFiles } from "@/hooks"; import { Footer, Section } from "@/layout/main-old"; import { @@ -15,7 +19,9 @@ import { filterUnselected, removeAllFiles, } from "@/reducers/file/actions"; -import { FeatureFlowEnum } from "@/types/features"; +import { useTutorialSeen } from "@/store/useLocal"; +import { HStack } from "@/styled/jsx"; +import { FeatureFlowEnum, featureName } from "@/types/features"; import { createFileRoute, useNavigate, @@ -38,6 +44,7 @@ function GenericPreview({ title, supportMultipleFiles }: GenericPreviewProps) { const files = useFiles(); const dispatch = useFileDispatch(); + const tutorialSeen = useTutorialSeen(feature); const isAnyFileSelected = files.some((file) => file.selected); @@ -74,6 +81,20 @@ function GenericPreview({ title, supportMultipleFiles }: GenericPreviewProps) { return ( <> +
+ ) : undefined + } + right={ + + {tutorialSeen && } + + + } + /> {/* MAIN SECTION */}
{title} diff --git a/src/renderer/src/routes/app.$feature/process.tsx b/src/renderer/src/routes/app.$feature/process.tsx index 2dbbdbe0..2b2fd971 100644 --- a/src/renderer/src/routes/app.$feature/process.tsx +++ b/src/renderer/src/routes/app.$feature/process.tsx @@ -8,6 +8,10 @@ import { Text, Toast, } from "@/components"; +import FeaturesMenu from "@/components/features-menu"; +import HowItWorksModal from "@/components/how-it-works-modal"; +import Stepper from "@/components/home/stepper"; +import Header from "@/components/layout/header"; import { useFileDispatch, useFiles } from "@/hooks"; import useNotify from "@/hooks/useNotify"; import type { PredictStatus } from "@/hooks/usePredict"; @@ -16,7 +20,9 @@ import { filterUnprocessed, removeAllPredictions, } from "@/reducers/file/actions"; -import { FeatureFlowEnum } from "@/types/features"; +import { useTutorialSeen } from "@/store/useLocal"; +import { HStack } from "@/styled/jsx"; +import { FeatureFlowEnum, featureName } from "@/types/features"; import { canContinue } from "@/utils/process/canContinue"; import { type ProcessState, @@ -68,6 +74,7 @@ function GenericProcess({ const files = useFiles(); const [process, setProcess] = useState(initProcessState(files)); const { isToastVisible, hideToast } = useNotify(process); + const tutorialSeen = useTutorialSeen(feature); const handleStatusChange = (name: string) => (newValue: PredictStatus) => { // Replace the newValue @@ -97,6 +104,20 @@ function GenericProcess({ return ( <> +
+ ) : undefined + } + right={ + + {tutorialSeen && } + + + } + />
}> {finishText} diff --git a/src/renderer/src/routes/app.$feature/route.tsx b/src/renderer/src/routes/app.$feature/route.tsx index 3f9c664d..da55df73 100644 --- a/src/renderer/src/routes/app.$feature/route.tsx +++ b/src/renderer/src/routes/app.$feature/route.tsx @@ -2,18 +2,12 @@ import { Outlet, createFileRoute, redirect, - useLocation, } from "@tanstack/react-router"; import { z } from "zod"; -import FeaturesMenu from "@/components/features-menu"; -import Stepper from "@/components/home/stepper"; -import HowItWorksModal from "@/components/how-it-works-modal"; -import Header from "@/components/layout/header"; import FileProvider from "@/context/File"; -import { useTutorialSeen } from "@/store/useLocal"; -import { HStack, Stack } from "@/styled/jsx"; -import { FeatureFlowEnum, featureName } from "@/types/features"; +import { Stack } from "@/styled/jsx"; +import { FeatureFlowEnum } from "@/types/features"; // Validation schema for feature parameter const featureParamSchema = z.object({ @@ -36,32 +30,8 @@ export const Route = createFileRoute("/app/$feature")({ }); function AppLayoutRoute() { - const { feature } = Route.useParams(); - const location = useLocation(); - const tutorialSeen = useTutorialSeen(feature); - - let currentStep = 1; - const path = location.pathname; - if (path.includes("/process")) currentStep = 2; - else if (path.includes("/validation")) currentStep = 3; - else if (path.includes("/finish")) currentStep = 4; - return ( -
- ) : undefined - } - right={ - - {tutorialSeen && } - - - } - /> diff --git a/src/renderer/src/routes/app.$feature/validation.tsx b/src/renderer/src/routes/app.$feature/validation.tsx index 31f5647f..0ae183a6 100644 --- a/src/renderer/src/routes/app.$feature/validation.tsx +++ b/src/renderer/src/routes/app.$feature/validation.tsx @@ -1,7 +1,13 @@ import { Button, FileAnnotator, Grid, ValidateDataset } from "@/components"; +import FeaturesMenu from "@/components/features-menu"; +import HowItWorksModal from "@/components/how-it-works-modal"; +import Stepper from "@/components/home/stepper"; +import Header from "@/components/layout/header"; import { useFiles } from "@/hooks"; import { Footer } from "@/layout/main-old"; -import { FeatureFlowEnum } from "@/types/features"; +import { useTutorialSeen } from "@/store/useLocal"; +import { HStack } from "@/styled/jsx"; +import { FeatureFlowEnum, featureName } from "@/types/features"; import { createFileRoute, useNavigate, @@ -50,7 +56,29 @@ function ValidateAnonymizer() { function ValidationRoute() { const { feature } = Route.useParams(); + const tutorialSeen = useTutorialSeen(feature); - if (feature === FeatureFlowEnum.Dataset) return ; - return ; + return ( + <> +
+ ) : undefined + } + right={ + + {tutorialSeen && } + + + } + /> + {feature === FeatureFlowEnum.Dataset ? ( + + ) : ( + + )} + + ); } From 088bed8260f9283991fdc16572ebdce623edbe8c Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 6 Apr 2026 21:45:41 -0300 Subject: [PATCH 067/263] feat: add api base url protection and apply it --- src/renderer/src/features/withAPIProtection.tsx | 12 ++++++++++++ src/renderer/src/routes/app.$feature/route.tsx | 9 +++++++-- src/renderer/src/routes/home/features.tsx | 9 +++++---- 3 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 src/renderer/src/features/withAPIProtection.tsx diff --git a/src/renderer/src/features/withAPIProtection.tsx b/src/renderer/src/features/withAPIProtection.tsx new file mode 100644 index 00000000..2a4b4bf0 --- /dev/null +++ b/src/renderer/src/features/withAPIProtection.tsx @@ -0,0 +1,12 @@ +import api from "@/services/api"; +import { Navigate } from "@tanstack/react-router"; +import type { ComponentType } from "react"; + +export function withAPIProtection

( + Component: ComponentType

+) { + return function ProtectedComponent(props: P) { + if (!api.defaults.baseURL) return ; + return ; + }; +} diff --git a/src/renderer/src/routes/app.$feature/route.tsx b/src/renderer/src/routes/app.$feature/route.tsx index 1b5a9c45..33cade0d 100644 --- a/src/renderer/src/routes/app.$feature/route.tsx +++ b/src/renderer/src/routes/app.$feature/route.tsx @@ -1,7 +1,12 @@ -import { Outlet, createFileRoute, redirect } from "@tanstack/react-router"; +import { + Outlet, + createFileRoute, + redirect, +} from "@tanstack/react-router"; import { z } from "zod"; import FileProvider from "@/context/File"; +import { withAPIProtection } from "@/features/withAPIProtection"; import { Stack } from "@/styled/jsx"; import { FeatureFlowEnum } from "@/types/features"; @@ -22,7 +27,7 @@ export const Route = createFileRoute("/app/$feature")({ }, stringify: (params) => params, }, - component: AppLayoutRoute, + component: withAPIProtection(AppLayoutRoute), }); function AppLayoutRoute() { diff --git a/src/renderer/src/routes/home/features.tsx b/src/renderer/src/routes/home/features.tsx index da97b956..b2b9373e 100644 --- a/src/renderer/src/routes/home/features.tsx +++ b/src/renderer/src/routes/home/features.tsx @@ -3,10 +3,11 @@ import FeaturesMenu from "@/components/features-menu"; import Header from "@/components/layout/header"; import MainContent from "@/components/layout/main-content"; import Card from "@/components/ui/card"; -import { FEATURES } from "@/constants/config"; +import { withAPIProtection } from "@/features/withAPIProtection"; import { css } from "@/styled/css"; import { Grid, Stack, styled } from "@/styled/jsx"; import { FeatureFlowEnum } from "@/types/features"; +import { FEATURE_ICON } from "@/utils/config"; import { Link, type LinkComponentProps, @@ -46,7 +47,7 @@ function CardTool({ } export const Route = createFileRoute("/home/features")({ - component: RouteComponent, + component: withAPIProtection(RouteComponent), }); function RouteComponent() { @@ -67,14 +68,14 @@ function RouteComponent() { params={{ feature: FeatureFlowEnum.Dataset }} title={t("dataset:title")} subtitle={t("dataset:subtitle")} - icon={FEATURES.DATA_SET.icon} + icon={FEATURE_ICON.DATA_SET} /> From cf9def05238544d3a954775f5c06e0626d18b21d Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 6 Apr 2026 21:51:16 -0300 Subject: [PATCH 068/263] chore: restructure HOC to be a regular component --- src/renderer/src/features/APIProtected.tsx | 12 ++++ .../src/features/withAPIProtection.tsx | 12 ---- .../src/routes/app.$feature/route.tsx | 22 ++++--- src/renderer/src/routes/home/features.tsx | 60 ++++++++++--------- 4 files changed, 53 insertions(+), 53 deletions(-) create mode 100644 src/renderer/src/features/APIProtected.tsx delete mode 100644 src/renderer/src/features/withAPIProtection.tsx diff --git a/src/renderer/src/features/APIProtected.tsx b/src/renderer/src/features/APIProtected.tsx new file mode 100644 index 00000000..0ccd1a76 --- /dev/null +++ b/src/renderer/src/features/APIProtected.tsx @@ -0,0 +1,12 @@ +import api from "@/services/api"; +import { Navigate } from "@tanstack/react-router"; +import type { ReactNode } from "react"; + +interface Props { + children: ReactNode; +} + +export default function APIProtected({ children }: Props) { + if (!api.defaults.baseURL) return ; + return children; +} diff --git a/src/renderer/src/features/withAPIProtection.tsx b/src/renderer/src/features/withAPIProtection.tsx deleted file mode 100644 index 2a4b4bf0..00000000 --- a/src/renderer/src/features/withAPIProtection.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import api from "@/services/api"; -import { Navigate } from "@tanstack/react-router"; -import type { ComponentType } from "react"; - -export function withAPIProtection

( - Component: ComponentType

-) { - return function ProtectedComponent(props: P) { - if (!api.defaults.baseURL) return ; - return ; - }; -} diff --git a/src/renderer/src/routes/app.$feature/route.tsx b/src/renderer/src/routes/app.$feature/route.tsx index 33cade0d..af6806c9 100644 --- a/src/renderer/src/routes/app.$feature/route.tsx +++ b/src/renderer/src/routes/app.$feature/route.tsx @@ -1,12 +1,8 @@ -import { - Outlet, - createFileRoute, - redirect, -} from "@tanstack/react-router"; +import { Outlet, createFileRoute, redirect } from "@tanstack/react-router"; import { z } from "zod"; import FileProvider from "@/context/File"; -import { withAPIProtection } from "@/features/withAPIProtection"; +import APIProtected from "@/features/APIProtected"; import { Stack } from "@/styled/jsx"; import { FeatureFlowEnum } from "@/types/features"; @@ -27,17 +23,19 @@ export const Route = createFileRoute("/app/$feature")({ }, stringify: (params) => params, }, - component: withAPIProtection(AppLayoutRoute), + component: AppLayoutRoute, }); function AppLayoutRoute() { const { feature } = Route.useParams(); return ( - - - - - + + + + + + + ); } diff --git a/src/renderer/src/routes/home/features.tsx b/src/renderer/src/routes/home/features.tsx index b2b9373e..f825157f 100644 --- a/src/renderer/src/routes/home/features.tsx +++ b/src/renderer/src/routes/home/features.tsx @@ -3,7 +3,7 @@ import FeaturesMenu from "@/components/features-menu"; import Header from "@/components/layout/header"; import MainContent from "@/components/layout/main-content"; import Card from "@/components/ui/card"; -import { withAPIProtection } from "@/features/withAPIProtection"; +import APIProtected from "@/features/APIProtected"; import { css } from "@/styled/css"; import { Grid, Stack, styled } from "@/styled/jsx"; import { FeatureFlowEnum } from "@/types/features"; @@ -47,39 +47,41 @@ function CardTool({ } export const Route = createFileRoute("/home/features")({ - component: withAPIProtection(RouteComponent), + component: RouteComponent, }); function RouteComponent() { const { t } = useTranslation(["common", "dataset", "anonymizer"]); return ( - -

} /> - - - - {t("home.features.greeting")} - - - {/* FIXME: fix the text wrapping on smaller screens */} - - - - - - + + +
} /> + + + + {t("home.features.greeting")} + + + {/* FIXME: fix the text wrapping on smaller screens */} + + + + + + + ); } From 31078ff5cc0da10821e518ec21e1b127e3dbfb0f Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 6 Apr 2026 21:55:53 -0300 Subject: [PATCH 069/263] chore: cleanup --- src/renderer/src/schema/extract.ts | 2 +- src/renderer/src/services/aymurai/queries.ts | 2 -- src/renderer/src/types/react-query.d.ts | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/renderer/src/schema/extract.ts b/src/renderer/src/schema/extract.ts index 4fff6673..93436f00 100644 --- a/src/renderer/src/schema/extract.ts +++ b/src/renderer/src/schema/extract.ts @@ -1,7 +1,7 @@ import z from "zod"; export const documentExtractSchema = z.object({ - document_id: z.string().uuid(), + document_id: z.uuid(), footer: z.string().nullable(), header: z.string().nullable(), document: z.array(z.string()), diff --git a/src/renderer/src/services/aymurai/queries.ts b/src/renderer/src/services/aymurai/queries.ts index ed8ed884..26f781d2 100644 --- a/src/renderer/src/services/aymurai/queries.ts +++ b/src/renderer/src/services/aymurai/queries.ts @@ -44,8 +44,6 @@ export const anonymize = (file: DocFile) => }, ); - console.log(response); - return response.data; }, select: (data) => URL.createObjectURL(data), diff --git a/src/renderer/src/types/react-query.d.ts b/src/renderer/src/types/react-query.d.ts index 5d56ad7f..4d996c21 100644 --- a/src/renderer/src/types/react-query.d.ts +++ b/src/renderer/src/types/react-query.d.ts @@ -2,7 +2,6 @@ import "@tanstack/react-query"; declare module "@tanstack/react-query" { interface Register { - queryMeta: MyMeta; mutationMeta: { invalidates?: Array; awaits?: boolean; From c34951e8e090b61784ea28a1dca1c169cda651ed Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 6 Apr 2026 21:58:12 -0300 Subject: [PATCH 070/263] fix: redo home layout --- .../src/layout/{home/index.tsx => home.tsx} | 0 src/renderer/src/layout/home/Home.styles.ts | 41 ------------------- 2 files changed, 41 deletions(-) rename src/renderer/src/layout/{home/index.tsx => home.tsx} (100%) delete mode 100644 src/renderer/src/layout/home/Home.styles.ts diff --git a/src/renderer/src/layout/home/index.tsx b/src/renderer/src/layout/home.tsx similarity index 100% rename from src/renderer/src/layout/home/index.tsx rename to src/renderer/src/layout/home.tsx diff --git a/src/renderer/src/layout/home/Home.styles.ts b/src/renderer/src/layout/home/Home.styles.ts deleted file mode 100644 index 50f188ce..00000000 --- a/src/renderer/src/layout/home/Home.styles.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { styled } from "@/styles"; -import { Link } from "@tanstack/react-router"; - -export const Background = styled("main", { - bg: "$secondary", - - display: "flex", - - height: "100vh", - width: "100vw", - - p: 32, -}); - -export const InnerBackground = styled("div", { - display: "flex", - flexDirection: "column", - justifyContent: "center", - alignItems: "center", - gap: 48, - - position: "relative", - - bg: "$white", - b: "1px solid $borderPrimary", - - width: "100%", - height: "100%", -}); - -export const BackButton = styled(Link, { - position: "absolute", - - top: "$m", - left: "$m", -}); - -export const BuiltBy = styled("div", { - position: "absolute", - bottom: "$xxl", -}); From 394121d99998a4e1a6e7de2b14992fe667e4672c Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 6 Apr 2026 21:58:42 -0300 Subject: [PATCH 071/263] feat: add more copies to locale file --- .../src/constants/i18n/locales/es/anonymizer.ts | 14 +++++++++++--- .../src/constants/i18n/locales/es/common.ts | 7 +------ .../src/constants/i18n/locales/es/dataset.ts | 11 ++++++++++- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/renderer/src/constants/i18n/locales/es/anonymizer.ts b/src/renderer/src/constants/i18n/locales/es/anonymizer.ts index d8336ada..d495b99f 100644 --- a/src/renderer/src/constants/i18n/locales/es/anonymizer.ts +++ b/src/renderer/src/constants/i18n/locales/es/anonymizer.ts @@ -1,11 +1,14 @@ +import { WHITELISTED_EXTENSIONS } from "@/constants/config"; + const anonymizer = { title: "Anonimizador", - subtitle: - "Anonimiza resoluciones judiciales de manera automática y editable", + subtitle: "Anonimiza resoluciones judiciales de manera automática y editable", onboarding: { sectionTitle: "1. Selección de Archivos", validFormats: "Formatos válidos: .doc y .docx", loadDocuments: "Cargar documentos", + dropAreaTitle: "Selecciona el archivo para anonimizar", + dropAreaFormats: `Formatos válidos: ${WHITELISTED_EXTENSIONS.map((e) => `.${e}`).join(", ")}`, }, preview: { sectionTitle: "1. Selección de Archivos", @@ -22,7 +25,12 @@ const anonymizer = { "Proceso terminado. El documento esta listo para ser exportado.", }, }, - process: { sectionTitle: "" }, + process: { + sectionTitle: "2. Procesamiento del archivo", + processingTitle: "AymurAI está extrayendo los datos del archivo", + processingSubtitle: "Este proceso puede tardar algunos minutos.", + finishText: "Se finalizó el análisis del documento.", + }, result: { sectionTitle: "" }, }; diff --git a/src/renderer/src/constants/i18n/locales/es/common.ts b/src/renderer/src/constants/i18n/locales/es/common.ts index c2d9f92a..45f88e83 100644 --- a/src/renderer/src/constants/i18n/locales/es/common.ts +++ b/src/renderer/src/constants/i18n/locales/es/common.ts @@ -34,8 +34,7 @@ const common = { step1: { alt: "Interfaz web con selector y cursor", title: "Selecciona las resoluciones judiciales", - subtitle: - "Sube los documentos que querés incorporar al set de datos.", + subtitle: "Sube los documentos que querés incorporar al set de datos.", }, step2: { alt: "Barra de búsqueda con cursor", @@ -50,10 +49,6 @@ const common = { "Es importante que verifiques que los datos sean correctos antes de exportar el archivo", }, }, - dropArea: { - selectFile: "Selecciona el archivo para\nagregar a la base de datos", - validFormats: "Formatos válidos:", - }, filePreview: { loadError: "No se pudo cargar el archivo", }, diff --git a/src/renderer/src/constants/i18n/locales/es/dataset.ts b/src/renderer/src/constants/i18n/locales/es/dataset.ts index df15e86d..bd66474e 100644 --- a/src/renderer/src/constants/i18n/locales/es/dataset.ts +++ b/src/renderer/src/constants/i18n/locales/es/dataset.ts @@ -1,3 +1,5 @@ +import { WHITELISTED_EXTENSIONS } from "@/constants/config"; + const dataset = { title: "Set de datos", subtitle: "Convertí resoluciones judiciales en set de datos estructurados", @@ -5,6 +7,8 @@ const dataset = { sectionTitle: "1. Selección de Archivos", validFormats: "Formatos válidos: .doc y .docx", loadDocuments: "Cargar documentos", + dropAreaTitle: "Selecciona el archivo para\nagregar a la base de datos", + dropAreaFormats: `Formatos válidos: ${WHITELISTED_EXTENSIONS.map((e) => `.${e}`).join(", ")}`, }, preview: { sectionTitle: "1. Selección de Archivos", @@ -21,7 +25,12 @@ const dataset = { "Los documentos pasan a formar parte del set de datos abiertos.", }, }, - process: { sectionTitle: "" }, + process: { + sectionTitle: "2. Procesamiento de los archivos", + processingTitle: "AymurAI está extrayendo los datos de los archivos", + processingSubtitle: "Este proceso puede tardar algunos minutos.", + finishText: "Se finalizó el análisis de tus documentos.", + }, result: { sectionTitle: "" }, }; From 617ea9741b8b0726374e788203eaddbe3464afe8 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 6 Apr 2026 23:31:30 -0300 Subject: [PATCH 072/263] feat: use a11y on finish page --- .../src/components/finish-anonymizer/index.tsx | 15 +++++++-------- .../finish-dataset/FinishDataset.styles.ts | 3 +++ .../src/components/finish-dataset/index.tsx | 15 +++++++-------- src/renderer/src/components/grid/index.ts | 3 +++ src/renderer/src/routes/app.$feature/finish.tsx | 6 ++++-- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/renderer/src/components/finish-anonymizer/index.tsx b/src/renderer/src/components/finish-anonymizer/index.tsx index 20766879..9ae17254 100644 --- a/src/renderer/src/components/finish-anonymizer/index.tsx +++ b/src/renderer/src/components/finish-anonymizer/index.tsx @@ -13,6 +13,7 @@ import { removeAllFiles } from "@/reducers/file/actions"; import { aymuraiService } from "@/services/aymurai"; import { useQuery } from "@tanstack/react-query"; import { useNavigate, useParams } from "@tanstack/react-router"; +import { useTranslation } from "react-i18next"; import Footer from "../layout/footer"; import MainContent from "../layout/main-content"; @@ -23,6 +24,7 @@ const changeExtension = (name: string) => { }; export function FinishAnonymizer() { + const { t } = useTranslation("anonymizer"); const params = useParams({ from: "/app/$feature/finish" }); // We are sure that there is only one file, because we came from // anonimization workflow @@ -58,13 +60,10 @@ export function FinishAnonymizer() { return ( <> - 4. Finalización - - Los datos encontrados por AymurAI y posteriormente validados ya han - sido anonimizados correctamente. - + {t("finish.sectionTitle")} + {t("finish.description")} - Archivo procesado + {t("finish.subtitle")}
diff --git a/src/renderer/src/components/finish-dataset/FinishDataset.styles.ts b/src/renderer/src/components/finish-dataset/FinishDataset.styles.ts index 642cdc8c..9670762a 100644 --- a/src/renderer/src/components/finish-dataset/FinishDataset.styles.ts +++ b/src/renderer/src/components/finish-dataset/FinishDataset.styles.ts @@ -1,5 +1,8 @@ import { styled } from "@/styles"; +/** + * @deprecated + */ export const Anchor = styled("a", { mr: "auto", }); diff --git a/src/renderer/src/components/finish-dataset/index.tsx b/src/renderer/src/components/finish-dataset/index.tsx index f51245d3..d1e94ad2 100644 --- a/src/renderer/src/components/finish-dataset/index.tsx +++ b/src/renderer/src/components/finish-dataset/index.tsx @@ -16,9 +16,11 @@ import filesystem from "@/services/filesystem"; import type { DocFile } from "@/types/file"; import { submitValidations } from "@/utils/file"; import { useNavigate, useParams } from "@tanstack/react-router"; +import { useTranslation } from "react-i18next"; import * as S from "./FinishDataset.styles"; export function FinishDataset() { + const { t } = useTranslation("dataset"); const params = useParams({ from: "/app/$feature/finish" }); const files = useFiles(); const dispatch = useFileDispatch(); @@ -65,14 +67,11 @@ export function FinishDataset() { return ( <>
- 4. Finalización - - Los datos encontrados por AymurAI y posteriormente validados ya son - parte del set de datos abiertos con perspectiva de género. - + {t("finish.sectionTitle")} + {t("finish.description")} - Archivos procesados + {t("finish.subtitle")} diff --git a/src/renderer/src/components/grid/index.ts b/src/renderer/src/components/grid/index.ts index 04f343d8..3dc79deb 100644 --- a/src/renderer/src/components/grid/index.ts +++ b/src/renderer/src/components/grid/index.ts @@ -12,6 +12,9 @@ function rowRepeat(rows: number) { }; } +/** + * @deprecated + */ const Grid = styled("div", { display: "grid", diff --git a/src/renderer/src/routes/app.$feature/finish.tsx b/src/renderer/src/routes/app.$feature/finish.tsx index c66d3bca..68115441 100644 --- a/src/renderer/src/routes/app.$feature/finish.tsx +++ b/src/renderer/src/routes/app.$feature/finish.tsx @@ -5,8 +5,9 @@ import Stepper from "@/components/home/stepper"; import Header from "@/components/layout/header"; import { useTutorialSeen } from "@/store/useLocal"; import { HStack } from "@/styled/jsx"; -import { FeatureFlowEnum, featureName } from "@/types/features"; +import { FeatureFlowEnum, featureNamespace } from "@/types/features"; import { createFileRoute, useParams } from "@tanstack/react-router"; +import { useTranslation } from "react-i18next"; export const Route = createFileRoute("/app/$feature/finish")({ component: RouteComponent, @@ -14,12 +15,13 @@ export const Route = createFileRoute("/app/$feature/finish")({ function RouteComponent() { const { feature } = useParams({ from: "/app/$feature/finish" }); + const { t } = useTranslation(featureNamespace[feature]); const tutorialSeen = useTutorialSeen(feature); return ( <>
From 2fd61a7f52b9b280df7aaec6d64457fcc23cf1e9 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 6 Apr 2026 23:34:20 -0300 Subject: [PATCH 073/263] fix: add missing feature param call on route.tsx --- src/renderer/src/routes/app.$feature/route.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/renderer/src/routes/app.$feature/route.tsx b/src/renderer/src/routes/app.$feature/route.tsx index 0bb08d82..c78449d9 100644 --- a/src/renderer/src/routes/app.$feature/route.tsx +++ b/src/renderer/src/routes/app.$feature/route.tsx @@ -2,6 +2,7 @@ import { Outlet, createFileRoute, redirect, + useParams, } from "@tanstack/react-router"; import { z } from "zod"; @@ -31,6 +32,7 @@ export const Route = createFileRoute("/app/$feature")({ }); function AppLayoutRoute() { + const { feature } = useParams({ from: "/app/$feature" }); return ( From 9d915cab58c2e38cb275bfceb83a5b07c3d591ba Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Tue, 7 Apr 2026 00:31:54 -0300 Subject: [PATCH 074/263] chore: kill unused old hidden input component --- .../hidden-input-old/HiddenInput.styles.ts | 8 ----- .../src/components/hidden-input-old/index.tsx | 29 ------------------- src/renderer/src/components/index.ts | 1 - 3 files changed, 38 deletions(-) delete mode 100644 src/renderer/src/components/hidden-input-old/HiddenInput.styles.ts delete mode 100644 src/renderer/src/components/hidden-input-old/index.tsx diff --git a/src/renderer/src/components/hidden-input-old/HiddenInput.styles.ts b/src/renderer/src/components/hidden-input-old/HiddenInput.styles.ts deleted file mode 100644 index f76785a0..00000000 --- a/src/renderer/src/components/hidden-input-old/HiddenInput.styles.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { styled } from "@/styles"; - -const Input = styled("input", { - opacity: 0, - pointerEvents: "none", -}); - -export default Input; diff --git a/src/renderer/src/components/hidden-input-old/index.tsx b/src/renderer/src/components/hidden-input-old/index.tsx deleted file mode 100644 index 3fede5e3..00000000 --- a/src/renderer/src/components/hidden-input-old/index.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { forwardRef } from "react"; - -import { WHITELISTED_EXTENSIONS } from "@/constants/config"; -import type { CSS } from "@/styles"; -import type { NativeComponent } from "@/types/component"; -import Input from "./HiddenInput.styles"; - -interface Props extends NativeComponent<"input"> { - css?: CSS; -} - -export default forwardRef(function HiddenInput( - { multiple = true, ...props }, - ref, -) { - // Convert the array into a '.dcox' form - const extensions = WHITELISTED_EXTENSIONS.map((ext) => `.${ext}`).join(","); - - return ( - - ); -}); diff --git a/src/renderer/src/components/index.ts b/src/renderer/src/components/index.ts index 6af0a8fd..66d56a52 100644 --- a/src/renderer/src/components/index.ts +++ b/src/renderer/src/components/index.ts @@ -10,7 +10,6 @@ export { default as FileStepper } from "./file-stepper"; export { FinishAnonymizer } from "./finish-anonymizer"; export { FinishDataset } from "./finish-dataset"; export { default as Grid } from "./grid"; -export { default as HiddenInput } from "./hidden-input-old"; export { default as Label } from "./label"; export { OnboardingCard } from "./onboarding-card"; export { OnboardingGrid } from "./onboarding-grid"; From baa9835cb2b8899cb6ae491910ffb190b1f598a3 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Tue, 7 Apr 2026 02:29:36 -0300 Subject: [PATCH 075/263] feat: add more copies for the finish page --- src/renderer/src/constants/i18n/locales/es/anonymizer.ts | 8 ++++++++ src/renderer/src/constants/i18n/locales/es/dataset.ts | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/renderer/src/constants/i18n/locales/es/anonymizer.ts b/src/renderer/src/constants/i18n/locales/es/anonymizer.ts index d495b99f..d1706464 100644 --- a/src/renderer/src/constants/i18n/locales/es/anonymizer.ts +++ b/src/renderer/src/constants/i18n/locales/es/anonymizer.ts @@ -32,6 +32,14 @@ const anonymizer = { finishText: "Se finalizó el análisis del documento.", }, result: { sectionTitle: "" }, + finish: { + sectionTitle: "4. Finalización", + description: + "Los datos encontrados por AymurAI y posteriormente validados ya han sido anonimizados correctamente.", + subtitle: "Archivo procesado", + restart: "Cargar un nuevo documento", + download: "Descargar documento", + }, }; export default anonymizer; diff --git a/src/renderer/src/constants/i18n/locales/es/dataset.ts b/src/renderer/src/constants/i18n/locales/es/dataset.ts index bd66474e..04cb3eb9 100644 --- a/src/renderer/src/constants/i18n/locales/es/dataset.ts +++ b/src/renderer/src/constants/i18n/locales/es/dataset.ts @@ -32,6 +32,14 @@ const dataset = { finishText: "Se finalizó el análisis de tus documentos.", }, result: { sectionTitle: "" }, + finish: { + sectionTitle: "4. Finalización", + description: + "Los datos encontrados por AymurAI y posteriormente validados ya son parte del set de datos abiertos con perspectiva de género.", + subtitle: "Archivos procesados", + restart: "Cargar más documentos", + viewDataset: "Ver set de datos", + }, }; export default dataset; From d4830e488cacf0b4dea933b51c2914cc1f2ea2d0 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Tue, 7 Apr 2026 02:30:08 -0300 Subject: [PATCH 076/263] feat: create label manager component --- .../anonymizer/label-manager/config-tab.tsx | 7 +++ .../anonymizer/label-manager/entity-tab.tsx | 0 .../anonymizer/label-manager/index.tsx | 61 +++++++++++++++++++ .../anonymizer/label-manager/section.tsx | 55 +++++++++++++++++ .../anonymizer/label-manager/tab.tsx | 25 ++++++++ 5 files changed, 148 insertions(+) create mode 100644 src/renderer/src/components/anonymizer/label-manager/config-tab.tsx create mode 100644 src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx create mode 100644 src/renderer/src/components/anonymizer/label-manager/index.tsx create mode 100644 src/renderer/src/components/anonymizer/label-manager/section.tsx create mode 100644 src/renderer/src/components/anonymizer/label-manager/tab.tsx diff --git a/src/renderer/src/components/anonymizer/label-manager/config-tab.tsx b/src/renderer/src/components/anonymizer/label-manager/config-tab.tsx new file mode 100644 index 00000000..b09d9df4 --- /dev/null +++ b/src/renderer/src/components/anonymizer/label-manager/config-tab.tsx @@ -0,0 +1,7 @@ + + +export default function ConfigTab() { + return ( + + ) +} \ No newline at end of file diff --git a/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx b/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/renderer/src/components/anonymizer/label-manager/index.tsx b/src/renderer/src/components/anonymizer/label-manager/index.tsx new file mode 100644 index 00000000..bb55f3a3 --- /dev/null +++ b/src/renderer/src/components/anonymizer/label-manager/index.tsx @@ -0,0 +1,61 @@ +import { useState } from "react"; + +import { sva } from "@/styled/css"; +import { HStack } from "@/styled/jsx"; +import { stack } from "@/styled/patterns"; +import Section from "./section"; +import LabelManagerTab from "./tab"; + +const styles = sva({ + slots: ["container", "body"], + base: { + container: { + ...stack.raw({ gap: "11" }), + px: "8", + pt: "6", + pb: "0", + width: "[400px]", + + bg: "bg.primary", + }, + body: {}, + }, +}); + +interface LabelManagerProps { + onClose: () => void; +} +export default function LabelManager({ onClose }: LabelManagerProps) { + const [selectedTab, setSelectedTab] = useState<"entity" | "config">("entity"); + + const classes = styles(); + + return ( +
+ + + setSelectedTab("entity")} + > + Entidades + + setSelectedTab("config")} + > + Configuracion + + + + +
+
+
+
+
+
+ ); +} diff --git a/src/renderer/src/components/anonymizer/label-manager/section.tsx b/src/renderer/src/components/anonymizer/label-manager/section.tsx new file mode 100644 index 00000000..fd1989ef --- /dev/null +++ b/src/renderer/src/components/anonymizer/label-manager/section.tsx @@ -0,0 +1,55 @@ +import { useState } from "react"; + +import { css } from "@/styled/css"; +import { HStack, styled } from "@/styled/jsx"; +import { CaretUp } from "phosphor-react"; + +const header = css({ + cursor: "pointer", +}); + +const caret = css({ + transition: "transform", + transitionDuration: "[0.2s]", + transitionTimingFunction: "[ease]", +}); + +const contentOuter = css({ + display: "grid", + transition: "[grid-template-rows]", + transitionDuration: "[0.3s]", + transitionTimingFunction: "[ease]", +}); + +const contentInner = css({ + minHeight: "[0]", + overflow: "hidden", +}); + +interface SectionProps { + children: React.ReactNode; + title: string; +} +export default function Section({ title: sectionTitle, children }: SectionProps) { + const [open, setOpen] = useState(true); + + return ( +
+ setOpen((prev) => !prev)}> +
+ +
+ {sectionTitle} +
+
+
{children}
+
+
+ ); +} diff --git a/src/renderer/src/components/anonymizer/label-manager/tab.tsx b/src/renderer/src/components/anonymizer/label-manager/tab.tsx new file mode 100644 index 00000000..34ef83c6 --- /dev/null +++ b/src/renderer/src/components/anonymizer/label-manager/tab.tsx @@ -0,0 +1,25 @@ +import { Tab } from "@/components/tabs"; +import { css } from "@/styled/css"; + +const button = css({ + cursor: "pointer", +}); + +interface LabelManagerTabProps { + children: string; + onClick: () => void; + isSelected: boolean; +} +export default function LabelManagerTab({ + onClick, + children, + isSelected, +}: LabelManagerTabProps) { + return ( + + ); +} From 4a9a255722c802bf2705cb47c33431ca54b5d8bb Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Thu, 9 Apr 2026 02:59:39 -0300 Subject: [PATCH 077/263] feat: create switch component --- package.json | 6 ++- pnpm-lock.yaml | 58 ++++++++++++++++++++--- src/renderer/src/components/ui/switch.tsx | 57 ++++++++++++++++++++++ 3 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 src/renderer/src/components/ui/switch.tsx diff --git a/package.json b/package.json index d304cff8..1f51ab0a 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "@pandacss/dev": "^1.8.1", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-switch": "^1.2.6", "@radix-ui/react-tooltip": "^1.2.8", "@stitches/react": "^1.2.8", "@tanstack/react-form": "1.11.0", @@ -84,6 +85,9 @@ "zustand": "^5.0.7" }, "pnpm": { - "onlyBuiltDependencies": ["electron", "esbuild"] + "onlyBuiltDependencies": [ + "electron", + "esbuild" + ] } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d39047aa..b6c8da5a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,12 +17,6 @@ importers: electron-squirrel-startup: specifier: ^1.0.0 version: 1.0.1 - i18next: - specifier: ^25.8.13 - version: 25.8.13(typescript@5.9.2) - react-i18next: - specifier: ^16.5.4 - version: 16.5.4(i18next@25.8.13(typescript@5.9.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.2) devDependencies: '@biomejs/biome': specifier: ^1.9.4 @@ -54,6 +48,9 @@ importers: '@radix-ui/react-popover': specifier: ^1.1.15 version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-switch': + specifier: ^1.2.6 + version: 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/react-tooltip': specifier: ^1.2.8 version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -120,6 +117,9 @@ importers: husky: specifier: ^8.0.0 version: 8.0.3 + i18next: + specifier: ^25.8.13 + version: 25.8.13(typescript@5.9.2) lint-staged: specifier: ^13.0.3 version: 13.3.0 @@ -141,6 +141,9 @@ importers: react-dom: specifier: '19' version: 19.2.4(react@19.2.4) + react-i18next: + specifier: ^16.5.4 + version: 16.5.4(i18next@25.8.13(typescript@5.9.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.2) regex-escape: specifier: ^3.4.10 version: 3.4.11 @@ -1063,6 +1066,19 @@ packages: '@types/react': optional: true + '@radix-ui/react-switch@1.2.6': + resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-tooltip@1.2.8': resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} peerDependencies: @@ -1121,6 +1137,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-previous@1.1.1': + resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-rect@1.1.1': resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} peerDependencies: @@ -6130,6 +6155,21 @@ snapshots: optionalDependencies: '@types/react': 19.2.13 + '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6184,6 +6224,12 @@ snapshots: optionalDependencies: '@types/react': 19.2.13 + '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.13)(react@19.2.4)': dependencies: '@radix-ui/rect': 1.1.1 diff --git a/src/renderer/src/components/ui/switch.tsx b/src/renderer/src/components/ui/switch.tsx new file mode 100644 index 00000000..dfb2442b --- /dev/null +++ b/src/renderer/src/components/ui/switch.tsx @@ -0,0 +1,57 @@ +import * as RadixSwitch from "@radix-ui/react-switch"; +import { css } from "@/styled/css"; + +const rootStyle = css({ + width: "[44px]", + height: "[24px]", + borderRadius: "full", + border: "none", + cursor: "pointer", + position: "relative", + flexShrink: "0", + bg: "bg.primary-highlight", + + transitionProperty: "[background-color]", + transitionDuration: "slow", + transitionTimingFunction: "default", + + '&[data-state="checked"]': { + bg: "brand.primary", + }, + + "&:disabled": { + cursor: "not-allowed", + opacity: "0.4", + }, +}); + +const thumbStyle = css({ + display: "block", + width: "[20px]", + height: "[20px]", + borderRadius: "full", + bg: "white", + position: "absolute", + top: "[2px]", + left: "[2px]", + + transitionProperty: "[transform]", + transitionDuration: "slow", + transitionTimingFunction: "default", + + '&[data-state="checked"]': { + transform: "[translateX(20px)]", + }, +}); + +type SwitchProps = RadixSwitch.SwitchProps; + +function Switch(props: SwitchProps) { + return ( + + + + ); +} + +export default Switch; From df53488db20fff8432badcf418b77351845db14b Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Thu, 9 Apr 2026 03:03:37 -0300 Subject: [PATCH 078/263] chore: minor changes --- src/renderer/src/components/tabs/index.ts | 8 +++++--- src/renderer/src/components/ui/back-button.tsx | 17 +++++++++-------- src/renderer/src/components/ui/button.tsx | 4 ++++ src/renderer/src/components/ui/card.tsx | 6 ++++-- src/renderer/src/components/ui/input.tsx | 6 +++++- 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/renderer/src/components/tabs/index.ts b/src/renderer/src/components/tabs/index.ts index 8eb24c08..320a5514 100644 --- a/src/renderer/src/components/tabs/index.ts +++ b/src/renderer/src/components/tabs/index.ts @@ -11,17 +11,19 @@ export const Tab = styled("div", { p: "$m", + fontSize: 16, + variants: { status: { completed: { - "& label": { + "& label, & span": { color: "$textOnButtonAlternative", }, bg: "$actionPressed", b: "none", }, focus: { - "& label": { + "& label, & span": { color: "$textOnButtonDefault", }, bg: "$actionFocus", @@ -29,7 +31,7 @@ export const Tab = styled("div", { b: "1px solid $borderPrimaryAlt", }, default: { - "& label": { + "& label, & span": { color: "$textOnButtonDefault", }, bg: "$primaryAlt", diff --git a/src/renderer/src/components/ui/back-button.tsx b/src/renderer/src/components/ui/back-button.tsx index a481a208..c70c9070 100644 --- a/src/renderer/src/components/ui/back-button.tsx +++ b/src/renderer/src/components/ui/back-button.tsx @@ -1,16 +1,17 @@ import { css, cx } from "@/styled/css"; -import { Link, type LinkComponentProps } from "@tanstack/react-router"; +import { createLink } from "@tanstack/react-router"; import { ArrowLeft } from "phosphor-react"; const link = css({ cursor: "pointer", }); -interface BackButtonProps extends LinkComponentProps {} -export default function BackButton({ className, ...props }: BackButtonProps) { - return ( - +const BackButton = createLink( + ({ className, children: _, ref, ...props }: React.AnchorHTMLAttributes & { ref?: React.Ref }) => ( + - - ); -} + + ), +); + +export default BackButton; diff --git a/src/renderer/src/components/ui/button.tsx b/src/renderer/src/components/ui/button.tsx index b1ebf72b..5e00321d 100644 --- a/src/renderer/src/components/ui/button.tsx +++ b/src/renderer/src/components/ui/button.tsx @@ -89,6 +89,10 @@ const button = cva({ tertiary: { // TODO: not implemented }, + none: { + padding: "0", + bg: "[inherit]", + }, }, size: { md: { height: "12", padding: "4", rounded: "sm" }, diff --git a/src/renderer/src/components/ui/card.tsx b/src/renderer/src/components/ui/card.tsx index a2d07a59..bc2b77e5 100644 --- a/src/renderer/src/components/ui/card.tsx +++ b/src/renderer/src/components/ui/card.tsx @@ -1,4 +1,4 @@ -import { cva } from "@/styled/css"; +import { cva, cx } from "@/styled/css"; const styles = cva({ base: { @@ -65,13 +65,15 @@ interface CardProps { disabled?: boolean; size?: "lg" | "sm"; clickable?: boolean; + className?: string; } export default function Card({ disabled = false, size = "lg", clickable = false, children, + className, }: CardProps) { const classes = styles({ size, disabled, clickable }); - return
{children}
; + return
{children}
; } diff --git a/src/renderer/src/components/ui/input.tsx b/src/renderer/src/components/ui/input.tsx index 4eecdc3f..9a2c51ed 100644 --- a/src/renderer/src/components/ui/input.tsx +++ b/src/renderer/src/components/ui/input.tsx @@ -100,7 +100,7 @@ const affix = cva({ }, }); -interface InputProps { +interface InputProps extends Omit, "prefix" | "suffix">, React.RefAttributes { // Rendering label?: string; placeholder?: string; @@ -126,11 +126,13 @@ export default function Input({ helper, // Control id, + ref, value, onChange, disabled = false, error, type, + ...props }: InputProps) { const randomId = useId(); const inputId = id ?? randomId; @@ -157,6 +159,8 @@ export default function Input({ )} Date: Thu, 9 Apr 2026 03:03:47 -0300 Subject: [PATCH 079/263] fix: title in anonymizer locale --- src/renderer/src/constants/i18n/locales/es/anonymizer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/constants/i18n/locales/es/anonymizer.ts b/src/renderer/src/constants/i18n/locales/es/anonymizer.ts index d1706464..384e2855 100644 --- a/src/renderer/src/constants/i18n/locales/es/anonymizer.ts +++ b/src/renderer/src/constants/i18n/locales/es/anonymizer.ts @@ -4,14 +4,14 @@ const anonymizer = { title: "Anonimizador", subtitle: "Anonimiza resoluciones judiciales de manera automática y editable", onboarding: { - sectionTitle: "1. Selección de Archivos", + sectionTitle: "1. Selección de Archivo", validFormats: "Formatos válidos: .doc y .docx", loadDocuments: "Cargar documentos", dropAreaTitle: "Selecciona el archivo para anonimizar", dropAreaFormats: `Formatos válidos: ${WHITELISTED_EXTENSIONS.map((e) => `.${e}`).join(", ")}`, }, preview: { - sectionTitle: "1. Selección de Archivos", + sectionTitle: "1. Selección de Archivo", filesLabel: "Archivos seleccionados", validFormats: "Formatos válidos: .doc y .docx", loadMore: "Cargar más documentos", From 962961e4b605eac4627d540abf4f71595f2b78f9 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Wed, 15 Apr 2026 01:51:56 -0300 Subject: [PATCH 080/263] chore: remove stepper component --- src/renderer/src/components/index.ts | 1 - src/renderer/src/components/stepper/Step.tsx | 76 ------------------- src/renderer/src/components/stepper/index.tsx | 37 --------- src/renderer/src/components/stepper/utils.ts | 32 -------- 4 files changed, 146 deletions(-) delete mode 100644 src/renderer/src/components/stepper/Step.tsx delete mode 100644 src/renderer/src/components/stepper/index.tsx delete mode 100644 src/renderer/src/components/stepper/utils.ts diff --git a/src/renderer/src/components/index.ts b/src/renderer/src/components/index.ts index 66d56a52..83aa71cc 100644 --- a/src/renderer/src/components/index.ts +++ b/src/renderer/src/components/index.ts @@ -19,7 +19,6 @@ export { default as SectionTitle } from "./section-title"; export { default as Select } from "./select"; export { default as Spinner } from "./spinner"; export { default as Stack } from "./stack"; -export { default as Stepper } from "./stepper"; export { default as Subtitle } from "./subtitle"; export { default as Suggestion } from "./suggestion"; export { Tab, TabName } from "./tabs"; diff --git a/src/renderer/src/components/stepper/Step.tsx b/src/renderer/src/components/stepper/Step.tsx deleted file mode 100644 index 663bcd20..00000000 --- a/src/renderer/src/components/stepper/Step.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { Label, Stack } from "@/components"; -import { styled } from "@/styles"; - -const StepNumber = styled("div", { - display: "flex", - justifyContent: "center", - alignItems: "center", - - width: 36, - height: 36, - - borderRadius: "100%", - - fontWeight: "$strong", - fontSize: "$ctaMd", - lineHeight: "$ctaMd", - textAlign: "center", - - variants: { - status: { - completed: { - bg: "$actionDefaultAlt", - color: "$textOnButtonAlternative", - }, - focus: { - bg: "$actionDefault", - color: "$textOnButtonDefault", - b: "1px solid $borderPrimaryAlt", - }, - disabled: { - bg: "$actionDisabled", - color: "$textOnButtonDefault", - }, - }, - }, - defaultVariants: { - status: "completed", - }, -}); - -interface Props { - currentStep: number; - step: number; - children: React.ReactNode; -} -/** - * - * @param currentStep Current file validation step, between 0 and 4 (0 being validation process hasn't started) - * @param step Step number used to get the Step variant and render the number - * @returns - */ -export default function Step({ currentStep, step, children }: Props) { - const getStatus = () => { - if (currentStep === step) return "focus"; - if (currentStep > step) return "completed"; - return "disabled"; - }; - - return ( - - {step} - {getStatus() === "focus" && ( - - )} - - ); -} diff --git a/src/renderer/src/components/stepper/index.tsx b/src/renderer/src/components/stepper/index.tsx deleted file mode 100644 index 09aab8bf..00000000 --- a/src/renderer/src/components/stepper/index.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Stack } from "@/components"; -import { useLocation } from "@tanstack/react-router"; -import Step from "./Step"; -import { getStep } from "./utils"; - -/** - * Stepper representing the current state of file validation - * @param currentStep Current file validation step, between 0 and 4 (0 being validation process hasn't started) - */ -export default function Stepper() { - const location = useLocation(); - const currentStep = getStep(location); - - // step = 0 is used in the case we want to hide the stepper (for example, in Onboarding page) - if (currentStep === 0) return null; - - return ( - - {/* STEP 1 */} - - Previsualización - - {/* STEP 2 */} - - Procesamiento - - {/* STEP 3 */} - - Validación - - {/* STEP 4 */} - - Finalización - - - ); -} diff --git a/src/renderer/src/components/stepper/utils.ts b/src/renderer/src/components/stepper/utils.ts deleted file mode 100644 index 82a9aafa..00000000 --- a/src/renderer/src/components/stepper/utils.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { ParsedLocation } from "@tanstack/react-router"; - -const ROUTE_STEPS = { - preview: 1, - process: 2, - validation: 3, - finish: 4, -} as const; - -type RouteSegment = keyof typeof ROUTE_STEPS; -type StepNumber = (typeof ROUTE_STEPS)[RouteSegment] | 0; - -export const getStep = (location: ParsedLocation): StepNumber => { - // Extract the last segment of the pathname - // For routes like /app/$feature/preview, this gets 'preview' - const segments = location.pathname.split("/").filter(Boolean); - const lastSegment = segments.at(-1); - - if (!lastSegment) return 0; - - // Type-safe check: only return step if lastSegment is a valid RouteSegment - if (isValidRouteSegment(lastSegment)) { - return ROUTE_STEPS[lastSegment]; - } - - return 0; -}; - -// Type guard to check if a string is a valid route segment -function isValidRouteSegment(segment: string): segment is RouteSegment { - return segment in ROUTE_STEPS; -} From 0bc48bc97a8d111af73ca7979b7a4da8ac3a1f69 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Wed, 15 Apr 2026 02:17:20 -0300 Subject: [PATCH 081/263] chore: refactor Searchbar --- .../file-annotator/FileAnnotator.styles.ts | 16 +- .../file-annotator/SearchBar/Counter.tsx | 48 +++-- .../file-annotator/SearchBar/index.tsx | 190 ++++++++++++++---- 3 files changed, 187 insertions(+), 67 deletions(-) diff --git a/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts b/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts index ed6a2917..6ec38a30 100644 --- a/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts +++ b/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts @@ -1,7 +1,9 @@ import { styled } from "@/styles"; export const Container = styled("div", { - boxShadow: "0px 0px 10px rgba(0, 0, 0, 0.1)", + flex: 1, + minWidth: 0, + // boxShadow: "0px 0px 10px rgba(0, 0, 0, 0.1)", zIndex: 1, overflowY: "scroll", @@ -10,7 +12,7 @@ export const Container = styled("div", { export const File = styled("div", { px: "$xl", pb: "$xl", - pt: "$l", + // pt: "$l", "& p, & span, & em": { fontFamily: "$file", @@ -131,13 +133,3 @@ export const Mark = styled("mark", { annotable: false, }, }); - -export const SearchContainer = styled("div", { - p: "$l", - pb: 0, - - zIndex: 1, - top: 0, - position: "sticky", - background: "white", -}); diff --git a/src/renderer/src/components/file-annotator/SearchBar/Counter.tsx b/src/renderer/src/components/file-annotator/SearchBar/Counter.tsx index 6a040e5c..09b5d7f2 100644 --- a/src/renderer/src/components/file-annotator/SearchBar/Counter.tsx +++ b/src/renderer/src/components/file-annotator/SearchBar/Counter.tsx @@ -1,31 +1,53 @@ -import { CaretDown as NextIcon, CaretUp as PreviousIcon } from "phosphor-react"; -import * as S from "./SearchBar.styles"; +import { css } from "@/styled/css"; +import { Stack, styled } from "@/styled/jsx"; +import { + CaretDown as NextIcon, + CaretUp as PreviousIcon, + XCircle, +} from "phosphor-react"; -import { Button, Label, Stack } from "@/components"; +import { Button } from "@/components"; + +const counterClass = css({ + display: "flex", + alignItems: "center", + gap: "1", +}); interface Props { - matchesCount: number; count: number; + cursor: number; next: () => void; previous: () => void; + clear: () => void; } -export const Counter = ({ matchesCount, previous, next, count }: Props) => { +export const Counter = ({ count, previous, next, cursor, clear }: Props) => { // Only return the counter if there is a match - if (matchesCount === 0) return null; + if (count === 0) return null; return ( - - - - - - - +
); }; diff --git a/src/renderer/src/components/file-annotator/SearchBar/index.tsx b/src/renderer/src/components/file-annotator/SearchBar/index.tsx index 52c62cab..2e2b30be 100644 --- a/src/renderer/src/components/file-annotator/SearchBar/index.tsx +++ b/src/renderer/src/components/file-annotator/SearchBar/index.tsx @@ -1,34 +1,70 @@ import { type ChangeEvent, useRef, useState } from "react"; -import { Grid } from "@/components"; -import Select, { type SelectOption } from "@/components/select"; -import { anonymizerLabels } from "@/types/aymurai"; +import type { SelectOption } from "@/components/select"; +import Select from "@/components/select"; +import Button from "@/components/ui/button"; +import Input from "@/components/ui/input"; +import { sva } from "@/styled/css"; +import { Grid, HStack, styled } from "@/styled/jsx"; +import { hstack } from "@/styled/patterns"; +import { anonymizerLabels } from "@/types/aymurai"; import { MagnifyingGlass } from "phosphor-react"; import { Counter } from "./Counter"; -import * as S from "./SearchBar.styles"; import { useScroll } from "./useScroll"; +const searchClasses = sva({ + slots: ["searchBar", "input", "verticalHr"], + base: { + searchBar: { + ...hstack.raw({ alignItems: "center", gap: "2" }), + height: "12", + p: "3", + rounded: "3xl", + // minWidth: "[450px]", + width: "full", + border: "primary", + }, + input: { + outline: "none", + width: "full", + }, + verticalHr: { + width: "[1px]", + alignSelf: "stretch", + borderWidth: "0", + backgroundColor: "[#BCBAB8]", + height: "12", + }, + }, +}); + interface Props { isAnnotable?: boolean; + isLabelManagerOpen: boolean; onSearchChange?: (value: string) => void; onLabelChange?: (object: SelectOption | undefined) => void; onLabelSufixChange?: (value: number | null) => void; + onLabelManagerToggle: () => void; } export const SearchBar = ({ isAnnotable = false, + isLabelManagerOpen, onSearchChange, onLabelChange, onLabelSufixChange, + onLabelManagerToggle, }: Props) => { const [search, setSearch] = useState(""); + const [labelSufix, setLabelSufix] = useState(""); const inputSearchRef = useRef(null); - const inputLabelSufixRef = useRef(null); const { next, previous, count, matchesCount } = useScroll(search); + const classes = searchClasses(); + const changeSearchHandler = (e: ChangeEvent) => { const text = e.target.value; setSearch(text); @@ -41,64 +77,134 @@ export const SearchBar = ({ } }; + const handleClear = () => { + setSearch(""); + onSearchChange?.(""); + }; + const searchFocus = () => inputSearchRef.current?.focus(); // biome-ignore lint/suspicious/noExplicitAny: we should add a type in the future const changeLabelSelectHandler = (e: any | undefined) => { onLabelChange?.(e); onLabelSufixChange?.(null); - if (inputLabelSufixRef.current) { - inputLabelSufixRef.current.value = ""; - } + setLabelSufix(""); }; const changeLabelSufixHandler = (e: ChangeEvent) => { + setLabelSufix(e.target.value); onLabelSufixChange?.(Number(e.target.value)); }; return ( - - - - - - - - - +
+ + + + + +
{isAnnotable && ( - - + +
+ + Aplicar etiquetas + +
+
+ {!isLabelManagerOpen && ( + <> +
+ + + )} +
)}
); + // return ( + // + // + // + // + // + // + + // + // + + // {isAnnotable && ( + // + // + // setInputValue(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && handleAddWord()} + /> + + + {excludedWords.length > 0 && ( + + {excludedWords.map((word) => ( + handleRemoveWord(word)} + /> + ))} + + )} + + + + ); +} diff --git a/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx b/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx index e69de29b..7074fdd4 100644 --- a/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx +++ b/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx @@ -0,0 +1,373 @@ +import { Trash, XCircle } from "phosphor-react"; +import { useMemo, useState } from "react"; + +import { css } from "@/styled/css"; +import { HStack, Stack, styled } from "@/styled/jsx"; +import { useFiles } from "@/hooks"; +import { anonymizerLabels } from "@/types/aymurai"; +import Select from "@/components/select"; +import Button from "@/components/ui/button"; + +import LabelManagerSection from "./section"; + +// ─── Category config ──────────────────────────────────────────────────────── + +const categoryConfig: Record< + string, + { labelIds: string[]; placeholder: string } +> = { + Roles: { + placeholder: "Seleccionar Rol", + labelIds: [ + "PER", + "USUARIX", + "DENUNCIANTE", + "ACUSADO/A", + "TESTIGO/A", + "NINO/A_ADOSLECENTE", + ], + }, + Lugares: { + placeholder: "Seleccionar Lugar", + labelIds: ["DIRECCION", "LOC"], + }, + Documentos: { + placeholder: "Seleccionar Tipo de Documento", + labelIds: [ + "DNI", + "AFILIADO", + "CAUSA", + "CUIJ", + "CUIT_CUIL", + "CBU", + "NUM_ACTUACION", + "NUM_CAJA_AHORRO", + "NUM_EXPEDIENTE", + "NUM_MATRICULA", + "PATENTE_DOMINIO", + ], + }, + "Otra entidad": { + placeholder: "Seleccionar", + labelIds: [ + "TEL", + "CORREO_ELECTRÓNICO", + "BANCO", + "INSTITUCION", + "EDAD", + "ESTUDIOS", + "FECHA", + "LINK", + "MARCA_AUTOMOVIL", + "NACIONALIDAD", + "TEXTO_ANONIMIZAR", + ], + }, +}; + +const categories = Object.keys(categoryConfig); + +// Reverse lookup: labelId → category name +const labelToCategory: Record = {}; +for (const [cat, { labelIds }] of Object.entries(categoryConfig)) { + for (const id of labelIds) { + labelToCategory[id] = cat; + } +} + +// ─── State types ───────────────────────────────────────────────────────────── + +interface DerivedGroup { + canonicalId: string; + labelId: string; + values: string[]; +} + +interface ManualGroup { + id: string; + selectedLabelId: string | undefined; + values: string[]; +} + +type ManualCategoryGroups = Record; + +const initialManualGroups = (): ManualCategoryGroups => + Object.fromEntries(categories.map((cat) => [cat, []])); + +// ─── Styles ────────────────────────────────────────────────────────────────── + +const valueItem = css({ + display: "flex", + alignItems: "center", + justifyContent: "space-between", + px: "3", + py: "2", + bg: "white", + p: "1", + rounded: "sm", + textStyle: "label.md.default", + color: "text.default", +}); + +const iconButton = css({ + cursor: "pointer", + color: "text.lighter", + bg: "transparent", + border: "none", + display: "flex", + alignItems: "center", + p: "0", + "&:hover": { color: "text.default" }, +}); + +// ─── Props ─────────────────────────────────────────────────────────────────── + +interface LabelEntityTabProps { + onDerivedGroupRemove?: (canonicalId: string) => void; + onDerivedValueRemove?: (canonicalId: string, value: string) => void; + onDerivedLabelChange?: ( + canonicalId: string, + labelId: string | undefined, + ) => void; +} + +// ─── Component ─────────────────────────────────────────────────────────────── + +export default function LabelEntityTab({ + onDerivedGroupRemove, + onDerivedValueRemove, + onDerivedLabelChange, +}: LabelEntityTabProps = {}) { + const files = useFiles(); + const [manualGroups, setManualGroups] = + useState(initialManualGroups); + const [removedDerivedIds, setRemovedDerivedIds] = useState([]); + const [removedDerivedValues, setRemovedDerivedValues] = useState< + Record + >({}); + const [overriddenDerivedLabels, setOverriddenDerivedLabels] = useState< + Record + >({}); + + // Derive groups from predictions, merging by canonical_entity_id + const derivedGroups = useMemo(() => { + const result: Record = Object.fromEntries( + categories.map((cat) => [cat, []]), + ); + const byCanonicalId = new Map(); + + for (const file of files) { + for (const pred of file.predictions ?? []) { + const { canonical_entity_id, aymurai_label } = pred.attrs; + if (!canonical_entity_id) continue; + + const category = labelToCategory[aymurai_label]; + if (!category) continue; + + if (byCanonicalId.has(canonical_entity_id)) { + const group = byCanonicalId.get(canonical_entity_id)!; + if (!group.values.includes(pred.text)) { + group.values.push(pred.text); + } + } else { + const group: DerivedGroup = { + canonicalId: canonical_entity_id, + labelId: aymurai_label, + values: [pred.text], + }; + byCanonicalId.set(canonical_entity_id, group); + result[category].push(group); + } + } + } + + return result; + }, [files]); + + const removeDerivedGroup = (canonicalId: string) => { + setRemovedDerivedIds((prev) => [...prev, canonicalId]); + onDerivedGroupRemove?.(canonicalId); + }; + + const removeDerivedValue = (canonicalId: string, value: string) => { + setRemovedDerivedValues((prev) => ({ + ...prev, + [canonicalId]: [...(prev[canonicalId] ?? []), value], + })); + onDerivedValueRemove?.(canonicalId, value); + }; + + const changeDerivedLabel = ( + canonicalId: string, + labelId: string | undefined, + ) => { + setOverriddenDerivedLabels((prev) => ({ ...prev, [canonicalId]: labelId })); + onDerivedLabelChange?.(canonicalId, labelId); + }; + + const addManualGroup = (category: string) => { + setManualGroups((prev) => ({ + ...prev, + [category]: [ + ...prev[category], + { id: crypto.randomUUID(), selectedLabelId: undefined, values: [] }, + ], + })); + }; + + const removeManualGroup = (category: string, groupId: string) => { + setManualGroups((prev) => ({ + ...prev, + [category]: prev[category].filter((g) => g.id !== groupId), + })); + }; + + const setManualGroupLabel = ( + category: string, + groupId: string, + labelId: string | undefined, + ) => { + setManualGroups((prev) => ({ + ...prev, + [category]: prev[category].map((g) => + g.id === groupId ? { ...g, selectedLabelId: labelId } : g, + ), + })); + }; + + const removeManualValue = ( + category: string, + groupId: string, + value: string, + ) => { + setManualGroups((prev) => ({ + ...prev, + [category]: prev[category].map((g) => + g.id === groupId + ? { ...g, values: g.values.filter((v) => v !== value) } + : g, + ), + })); + }; + + return ( + + {categories.map((category, i) => { + const { labelIds, placeholder } = categoryConfig[category]; + const options = anonymizerLabels.filter((l) => labelIds.includes(l.id)); + const categoryDerived = derivedGroups[category]; + const categoryManual = manualGroups[category]; + + return ( + <> + {i > 0 && ( + + )} + + + {categoryDerived + .filter((g) => !removedDerivedIds.includes(g.canonicalId)) + .map((group) => { + const visibleValues = group.values.filter( + (v) => + !(removedDerivedValues[group.canonicalId] ?? []).includes( + v, + ), + ); + const selectedLabel = + overriddenDerivedLabels[group.canonicalId] ?? + group.labelId; + return ( + + + + setManualGroupLabel(category, group.id, opt?.id) + } + /> + + + + {group.values.map((value) => ( +
+ {value} + +
+ ))} +
+ ))} + + +
+
+ + ); + })} +
+ ); +} diff --git a/src/renderer/src/components/anonymizer/label-manager/index.tsx b/src/renderer/src/components/anonymizer/label-manager/index.tsx index bb55f3a3..7ec0718e 100644 --- a/src/renderer/src/components/anonymizer/label-manager/index.tsx +++ b/src/renderer/src/components/anonymizer/label-manager/index.tsx @@ -3,22 +3,26 @@ import { useState } from "react"; import { sva } from "@/styled/css"; import { HStack } from "@/styled/jsx"; import { stack } from "@/styled/patterns"; -import Section from "./section"; +import LabelConfigTab from "./config-tab"; +import LabelEntityTab from "./entity-tab"; import LabelManagerTab from "./tab"; const styles = sva({ - slots: ["container", "body"], + slots: ["container", "body", "close"], base: { container: { ...stack.raw({ gap: "11" }), px: "8", - pt: "6", - pb: "0", + py: "6", width: "[400px]", + overflow: "scroll", bg: "bg.primary", }, body: {}, + close: { + cursor: "pointer", + }, }, }); @@ -47,14 +51,12 @@ export default function LabelManager({ onClose }: LabelManagerProps) { Configuracion -
-
-
-
+ {selectedTab === "entity" ? : }
); diff --git a/src/renderer/src/components/anonymizer/label-manager/section.tsx b/src/renderer/src/components/anonymizer/label-manager/section.tsx index fd1989ef..2f3d1e7e 100644 --- a/src/renderer/src/components/anonymizer/label-manager/section.tsx +++ b/src/renderer/src/components/anonymizer/label-manager/section.tsx @@ -1,7 +1,7 @@ import { useState } from "react"; import { css } from "@/styled/css"; -import { HStack, styled } from "@/styled/jsx"; +import { HStack, Stack, styled } from "@/styled/jsx"; import { CaretUp } from "phosphor-react"; const header = css({ @@ -30,19 +30,28 @@ interface SectionProps { children: React.ReactNode; title: string; } -export default function Section({ title: sectionTitle, children }: SectionProps) { +export default function LabelManagerSection({ + title: sectionTitle, + children, +}: SectionProps) { const [open, setOpen] = useState(true); return ( -
- setOpen((prev) => !prev)}> + + setOpen((prev) => !prev)} + >
- {sectionTitle} + + {sectionTitle} +
{children}
-
+ ); } From 4e91d285df58a8ac9f2bf7a3e13c7cd9c812733c Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Wed, 15 Apr 2026 02:31:27 -0300 Subject: [PATCH 083/263] feat: add feature icon record --- src/renderer/src/utils/config.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/renderer/src/utils/config.ts b/src/renderer/src/utils/config.ts index 64f1e384..34ed8c4c 100644 --- a/src/renderer/src/utils/config.ts +++ b/src/renderer/src/utils/config.ts @@ -1,3 +1,6 @@ +import { FeatureFlowEnum } from "@/types/features"; +import { Database, Detective, type Icon } from "phosphor-react"; + /** * AI Predict port */ @@ -13,3 +16,8 @@ export const DATASET_URL = * AymurAI API URL */ export const AYMURAI_API_URL = `http://localhost:${PREDICT_PORT}`; + +export const FEATURE_ICON: Record = { + [FeatureFlowEnum.Dataset]: Database, + [FeatureFlowEnum.Anonymizer]: Detective, +}; From 7d1a71f3426bfa74db4099c3b0d53e1c4a6f0746 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Wed, 15 Apr 2026 02:33:13 -0300 Subject: [PATCH 084/263] add disambiguate and predict react query options --- src/renderer/src/schema/disambiguate.ts | 30 ++++++++ src/renderer/src/services/aymurai/queries.ts | 72 +++++++++++++++++++- 2 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 src/renderer/src/schema/disambiguate.ts diff --git a/src/renderer/src/schema/disambiguate.ts b/src/renderer/src/schema/disambiguate.ts new file mode 100644 index 00000000..7d3ef5ad --- /dev/null +++ b/src/renderer/src/schema/disambiguate.ts @@ -0,0 +1,30 @@ +import { z } from "zod"; + +const disambiguateLabelSchema = z.object({ + text: z.string(), + start_char: z.number(), + end_char: z.number(), + attrs: z.object({ + aymurai_label: z.string(), + aymurai_label_subclass: z.array(z.string()).nullable(), + aymurai_alt_text: z.string().nullable(), + aymurai_alt_start_char: z.number().nullable(), + aymurai_alt_end_char: z.number().nullable(), + aymurai_method: z.string().nullish(), + aymurai_score: z.number().nullish(), + aymurai_label_instance: z.number().nullish(), + aymurai_disambiguation: z.string().nullish(), + aymurai_anonymize: z.boolean().nullish(), + canonical_entity_id: z.string().nullish(), + }), +}); + +export const disambiguateSchema = z.object({ + data: z.array( + z.object({ + document: z.string(), + labels: z.array(disambiguateLabelSchema), + }), + ), + // label_policies is intentionally omitted +}); diff --git a/src/renderer/src/services/aymurai/queries.ts b/src/renderer/src/services/aymurai/queries.ts index 26f781d2..a3a91631 100644 --- a/src/renderer/src/services/aymurai/queries.ts +++ b/src/renderer/src/services/aymurai/queries.ts @@ -1,7 +1,9 @@ -import type { PredictLabel } from "@/types/aymurai"; -import type { DocFile } from "@/types/file"; +import { disambiguateSchema } from "@/schema/disambiguate"; +import type { PredictLabel, Workflows } from "@/types/aymurai"; +import type { DocFile, Paragraph } from "@/types/file"; import { queryOptions } from "@tanstack/react-query"; import api from "../api"; +import predict from "./predict"; interface Body { data: { @@ -11,6 +13,26 @@ interface Body { }[]; } +/** + * Query factory for a single paragraph prediction. + * Uses React Query's native cancellation signal — no manual AbortController needed. + */ +export const predictParagraph = ( + paragraph: Paragraph, + workflow: Workflows, + fileName: string, +) => + queryOptions({ + queryKey: ["predict", workflow, fileName, paragraph.id], + queryFn: ({ signal }) => { + const controller = new AbortController(); + signal?.addEventListener("abort", () => controller.abort()); + return predict(paragraph, controller, workflow); + }, + staleTime: Number.POSITIVE_INFINITY, + retry: false, + }); + const body = (file: DocFile): Body => { const paragraphs = file.paragraphs ?? []; const labels = file.predictions ?? []; @@ -48,3 +70,49 @@ export const anonymize = (file: DocFile) => }, select: (data) => URL.createObjectURL(data), }); + +export const disambiguate = (file: DocFile) => + queryOptions({ + queryKey: ["disambiguate", file.data.name], + queryFn: async (): Promise => { + if (!file.paragraphs) + throw new Error("File with no paragraphs tried to disambiguate"); + if (!file.predictions) + throw new Error("File with no predictions tried to disambiguate"); + + const { paragraphs, predictions } = file; + + const response = await api.post("/anonymizer/disambiguate", { + paragraphs: paragraphs.map((p) => ({ + document: p.value, + labels: predictions.filter((l) => l.paragraphId === p.id), + })), + }); + + const parsed = disambiguateSchema.parse(response.data); + + // Flatten all paragraph labels into a single PredictLabel[] and map back + // to the internal paragraphId (paragraph.id) using document_id as the key + return parsed.data.flatMap((item) => { + const paragraph = paragraphs.find( + (p) => p.document_id === item.document, + ); + + return item.labels.map((l) => ({ + text: l.attrs.aymurai_alt_text ?? l.text, + start_char: l.attrs.aymurai_alt_start_char ?? l.start_char, + end_char: l.attrs.aymurai_alt_end_char ?? l.end_char, + attrs: { + aymurai_label: l.attrs + .aymurai_label as PredictLabel["attrs"]["aymurai_label"], + aymurai_label_subclass: l.attrs.aymurai_label_subclass, + aymurai_alt_text: l.attrs.aymurai_alt_text ?? null, + aymurai_alt_start_char: l.attrs.aymurai_alt_start_char ?? null, + aymurai_alt_end_char: l.attrs.aymurai_alt_end_char ?? null, + canonical_entity_id: l.attrs.canonical_entity_id ?? null, + }, + paragraphId: paragraph?.id ?? item.document, + })); + }); + }, + }); From d31ec03438a2462d6f58806ed9abc2424b94823b Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Wed, 15 Apr 2026 02:33:40 -0300 Subject: [PATCH 085/263] finish onboarding page --- .../src/routes/app.$feature/onboarding.tsx | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/renderer/src/routes/app.$feature/onboarding.tsx b/src/renderer/src/routes/app.$feature/onboarding.tsx index a48ba6b4..4b8e4fe5 100644 --- a/src/renderer/src/routes/app.$feature/onboarding.tsx +++ b/src/renderer/src/routes/app.$feature/onboarding.tsx @@ -5,10 +5,8 @@ import { } from "@tanstack/react-router"; import DropArea from "@/components/drop-area"; -import FeaturesMenu from "@/components/features-menu"; import HiddenInput from "@/components/hidden-input"; import HowItWorks from "@/components/how-it-works"; -import HowItWorksModal from "@/components/how-it-works-modal"; import Footer from "@/components/layout/footer"; import Header from "@/components/layout/header"; import MainContent from "@/components/layout/main-content"; @@ -34,6 +32,7 @@ function RouteComponent() { }); const navigate = useNavigate(); const { t } = useTranslation(featureNamespace[feature]); + console.log({ feature, title: t("onboarding.dropAreaTitle") }); const inputRef = useRef(null); @@ -61,15 +60,7 @@ function RouteComponent() { return ( <> -
- {tutorialSeen && } - - - } - /> +
{tutorialSeen ? ( @@ -77,7 +68,11 @@ function RouteComponent() { {t("onboarding.sectionTitle")} - + ) : ( From 3c88d2f307b4a24ce95f1dd3a4ed82b5d01138d4 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Wed, 15 Apr 2026 02:34:02 -0300 Subject: [PATCH 086/263] finish preview page --- .../src/routes/app.$feature/preview.tsx | 196 +++++++----------- 1 file changed, 70 insertions(+), 126 deletions(-) diff --git a/src/renderer/src/routes/app.$feature/preview.tsx b/src/renderer/src/routes/app.$feature/preview.tsx index 94cdf5ef..9984cc5c 100644 --- a/src/renderer/src/routes/app.$feature/preview.tsx +++ b/src/renderer/src/routes/app.$feature/preview.tsx @@ -1,75 +1,57 @@ -import { - Button, - Card, - FilePreview, - Grid, - HiddenInput, - SectionTitle, - Subtitle, - Text, -} from "@/components"; -import FeaturesMenu from "@/components/features-menu"; -import HowItWorksModal from "@/components/how-it-works-modal"; +import { Button, FilePreview } from "@/components"; +import HiddenInput from "@/components/hidden-input"; import Stepper from "@/components/home/stepper"; +import Footer from "@/components/layout/footer"; import Header from "@/components/layout/header"; +import MainContent from "@/components/layout/main-content"; +import BackButton from "@/components/ui/back-button"; +import Card from "@/components/ui/card"; import { useFileDispatch, useFiles } from "@/hooks"; -import { Footer, Section } from "@/layout/main-old"; -import { - addFiles, - filterUnselected, - removeAllFiles, -} from "@/reducers/file/actions"; -import { useTutorialSeen } from "@/store/useLocal"; -import { HStack } from "@/styled/jsx"; -import { FeatureFlowEnum, featureName } from "@/types/features"; +import { SectionTitle } from "@/layout/section-title"; +import { addFiles, filterUnselected } from "@/reducers/file/actions"; +import { Grid, HStack, Stack, styled } from "@/styled/jsx"; +import { FeatureFlowEnum, featureNamespace } from "@/types/features"; import { createFileRoute, useNavigate, useParams, } from "@tanstack/react-router"; import { useRef } from "react"; +import { useTranslation } from "react-i18next"; export const Route = createFileRoute("/app/$feature/preview")({ component: RouteComponent, }); -interface GenericPreviewProps { - title: string; - supportMultipleFiles: boolean; -} -function GenericPreview({ title, supportMultipleFiles }: GenericPreviewProps) { - const { feature } = useParams({ from: "/app/$feature/preview" }); - const inputRef = useRef(null); +function RouteComponent() { + const { feature } = useParams({ + from: "/app/$feature/preview", + }); const navigate = useNavigate(); + const { t } = useTranslation(featureNamespace[feature]); + + const inputRef = useRef(null); const files = useFiles(); const dispatch = useFileDispatch(); - const tutorialSeen = useTutorialSeen(feature); - - const isAnyFileSelected = files.some((file) => file.selected); - const handlePrevious = () => { - dispatch(removeAllFiles()); - navigate({ - to: "/app/$feature/onboarding", - params: { feature }, - }); - }; - - const handleSelectFile = () => { - inputRef.current?.click(); - }; + const isProcessing = files.some((file) => !file.paragraphs); - const handleAddedFiles: React.ChangeEventHandler = (e) => { + const handleAddFiles: React.ChangeEventHandler = async ( + e, + ) => { const rawFiles = e.target.files; - - // Check if any file was added if (rawFiles) { - const fileArray = Array.from(rawFiles); - - dispatch(addFiles(fileArray)); + dispatch(addFiles([...rawFiles])); + await navigate({ + to: "/app/$feature/preview", + params: { feature }, + }); } }; + const handleOpenInput = () => { + inputRef.current?.click(); + }; const handleConfirmFiles = () => { dispatch(filterUnselected()); @@ -82,86 +64,48 @@ function GenericPreview({ title, supportMultipleFiles }: GenericPreviewProps) { return ( <>
- ) : undefined - } - right={ - - {tutorialSeen && } - - - } + title={t("title")} + center={} + feature={feature} /> - {/* MAIN SECTION */} -
- {title} - - {supportMultipleFiles && Archivos seleccionados} - - {files.map((file) => ( - - ))} - - -
- - {/* FOOTER */} -
- - {supportMultipleFiles && ( - <> - Formatos válidos: .docx, .pdf - - - )} - + + + + + {t("preview.sectionTitle")} + + + + + {t("preview.filesLabel")} + + + {files.map((file) => ( + + ))} + + + + + +
+ + {feature === FeatureFlowEnum.Dataset && ( + <> + + {t("preview.validFormats")} + + + + )} + +
+ ); } - -function RouteComponent() { - const { feature } = useParams({ - from: "/app/$feature/preview", - }); - - if (feature === FeatureFlowEnum.Dataset) - return ( - - ); - - return ( - - ); -} From 23fa8407c87543c0a5ae97bad6a208ac469d006a Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Wed, 15 Apr 2026 02:52:48 -0300 Subject: [PATCH 087/263] improve layout header component --- src/renderer/src/components/layout/header.tsx | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/renderer/src/components/layout/header.tsx b/src/renderer/src/components/layout/header.tsx index 3237e3be..fd6ec00f 100644 --- a/src/renderer/src/components/layout/header.tsx +++ b/src/renderer/src/components/layout/header.tsx @@ -1,5 +1,9 @@ +import { useTutorialSeen } from "@/store/useLocal"; import { css } from "@/styled/css"; -import { Divider, Stack, styled } from "@/styled/jsx"; +import { Divider, HStack, Stack, styled } from "@/styled/jsx"; +import type { FeatureFlowEnum } from "@/types/features"; +import FeaturesMenu from "../features-menu"; +import HowItWorksModal from "../how-it-works-modal"; const header = css({ position: "relative", @@ -20,16 +24,31 @@ const centerSlot = css({ transform: "translateX(-50%)", }); -interface HeaderProps { +type HeaderProps = { title?: string; center?: React.ReactNode; - right?: React.ReactNode; -} -export default function Header({ title, center, right }: HeaderProps) { +} & ( + | { feature: FeatureFlowEnum; right?: never } + | { right: React.ReactNode; feature?: never } + | { right?: never; feature?: never } +); + +export default function Header({ title, center, feature, right }: HeaderProps) { + const tutorialSeen = useTutorialSeen(feature!); + const img = title ? "/brand/aymurai-iso-darkpurple.svg" : "/brand/aymurai-hor-darkpurple.svg"; + const rightSlot = feature ? ( + + {tutorialSeen && } + + + ) : ( + right + ); + return (
@@ -47,7 +66,7 @@ export default function Header({ title, center, right }: HeaderProps) { )} {center &&
{center}
} -
{right}
+ {rightSlot}
); } From 5b069d680fa79973a2c8ee5a50f7766c67a1b44e Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Wed, 15 Apr 2026 03:12:45 -0300 Subject: [PATCH 088/263] connect rest of label manager --- .../anonymizer/label-manager/config-tab.tsx | 38 +++---------- .../anonymizer/label-manager/entity-tab.tsx | 55 +++++++++---------- .../anonymizer/label-manager/index.tsx | 39 ++++++++++++- .../anonymizer/label-manager/label.tsx | 28 ++++++++++ 4 files changed, 101 insertions(+), 59 deletions(-) create mode 100644 src/renderer/src/components/anonymizer/label-manager/label.tsx diff --git a/src/renderer/src/components/anonymizer/label-manager/config-tab.tsx b/src/renderer/src/components/anonymizer/label-manager/config-tab.tsx index 6560e3e1..055da784 100644 --- a/src/renderer/src/components/anonymizer/label-manager/config-tab.tsx +++ b/src/renderer/src/components/anonymizer/label-manager/config-tab.tsx @@ -1,11 +1,11 @@ -import { useState } from "react"; import { HStack, Stack, styled } from "@/styled/jsx"; import { anonymizerLabels } from "@/types/aymurai"; +import { useState } from "react"; import Button from "@/components/ui/button"; import Input from "@/components/ui/input"; import BaseSwitch from "@/components/ui/switch"; -import { XCircle } from "phosphor-react"; +import { Label } from "./label"; import LabelManagerSection from "./section"; interface ToggleProps { @@ -24,33 +24,13 @@ function Switch({ name, value, onToggle }: ToggleProps) { ); } -interface ExcludedWordProps { - value: string; - onRemove: () => void; -} -function ExcludedWord({ value, onRemove }: ExcludedWordProps) { - return ( - - {value} - - - - - ); -} - const initialToggles = Object.fromEntries( - anonymizerLabels.map((label) => [label.id, true]) + anonymizerLabels.map((label) => [label.id, true]), ); export default function LabelConfigTab() { - const [toggles, setToggles] = useState>(initialToggles); + const [toggles, setToggles] = + useState>(initialToggles); const [excludedWords, setExcludedWords] = useState([]); const [inputValue, setInputValue] = useState(""); @@ -101,11 +81,9 @@ export default function LabelConfigTab() { {excludedWords.length > 0 && ( {excludedWords.map((word) => ( - handleRemoveWord(word)} - /> + ))} )} diff --git a/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx b/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx index 7074fdd4..d084bce4 100644 --- a/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx +++ b/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx @@ -1,13 +1,14 @@ import { Trash, XCircle } from "phosphor-react"; import { useMemo, useState } from "react"; +import Select from "@/components/select"; +import Button from "@/components/ui/button"; +import { useFiles } from "@/hooks"; import { css } from "@/styled/css"; import { HStack, Stack, styled } from "@/styled/jsx"; -import { useFiles } from "@/hooks"; import { anonymizerLabels } from "@/types/aymurai"; -import Select from "@/components/select"; -import Button from "@/components/ui/button"; +import { Label } from "./label"; import LabelManagerSection from "./section"; // ─── Category config ──────────────────────────────────────────────────────── @@ -102,7 +103,7 @@ const valueItem = css({ justifyContent: "space-between", px: "3", py: "2", - bg: "white", + bg: "bg.primary-alternative", p: "1", rounded: "sm", textStyle: "label.md.default", @@ -120,24 +121,19 @@ const iconButton = css({ "&:hover": { color: "text.default" }, }); -// ─── Props ─────────────────────────────────────────────────────────────────── - interface LabelEntityTabProps { - onDerivedGroupRemove?: (canonicalId: string) => void; - onDerivedValueRemove?: (canonicalId: string, value: string) => void; - onDerivedLabelChange?: ( + onDerivedGroupRemove: (canonicalId: string) => void; + onDerivedValueRemove: (canonicalId: string, value: string) => void; + onDerivedLabelChange: ( canonicalId: string, labelId: string | undefined, ) => void; } - -// ─── Component ─────────────────────────────────────────────────────────────── - export default function LabelEntityTab({ onDerivedGroupRemove, onDerivedValueRemove, onDerivedLabelChange, -}: LabelEntityTabProps = {}) { +}: LabelEntityTabProps) { const files = useFiles(); const [manualGroups, setManualGroups] = useState(initialManualGroups); @@ -270,9 +266,9 @@ export default function LabelEntityTab({ .map((group) => { const visibleValues = group.values.filter( (v) => - !(removedDerivedValues[group.canonicalId] ?? []).includes( - v, - ), + !( + removedDerivedValues[group.canonicalId] ?? [] + ).includes(v), ); const selectedLabel = overriddenDerivedLabels[group.canonicalId] ?? @@ -299,21 +295,24 @@ export default function LabelEntityTab({ - {visibleValues.map((value) => ( -
- {value} - -
- ))} + {value} + + ))} + ); })} diff --git a/src/renderer/src/components/anonymizer/label-manager/index.tsx b/src/renderer/src/components/anonymizer/label-manager/index.tsx index 7ec0718e..a901a43b 100644 --- a/src/renderer/src/components/anonymizer/label-manager/index.tsx +++ b/src/renderer/src/components/anonymizer/label-manager/index.tsx @@ -1,5 +1,12 @@ import { useState } from "react"; +import { useFileDispatch } from "@/hooks"; +import { + removePredictionsByCanonicalId, + removePredictionValueByCanonicalId, + updatePredictionsByCanonicalId, +} from "@/reducers/file/actions"; +import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; import { sva } from "@/styled/css"; import { HStack } from "@/styled/jsx"; import { stack } from "@/styled/patterns"; @@ -31,9 +38,31 @@ interface LabelManagerProps { } export default function LabelManager({ onClose }: LabelManagerProps) { const [selectedTab, setSelectedTab] = useState<"entity" | "config">("entity"); + const dispatch = useFileDispatch(); const classes = styles(); + function handleDerivedGroupRemove(canonicalId: string) { + dispatch(removePredictionsByCanonicalId(canonicalId)); + } + + function handleDerivedValueRemove(canonicalId: string, value: string) { + dispatch(removePredictionValueByCanonicalId(canonicalId, value)); + } + + function handleDerivedLabelChange( + canonicalId: string, + labelId: string | undefined, + ) { + if (!labelId) return; + dispatch( + updatePredictionsByCanonicalId( + canonicalId, + labelId as AllLabels | AllLabelsWithSufix, + ), + ); + } + return (
@@ -56,7 +85,15 @@ export default function LabelManager({ onClose }: LabelManagerProps) {
- {selectedTab === "entity" ? : } + {selectedTab === "entity" ? ( + + ) : ( + + )}
); diff --git a/src/renderer/src/components/anonymizer/label-manager/label.tsx b/src/renderer/src/components/anonymizer/label-manager/label.tsx new file mode 100644 index 00000000..ebacff7e --- /dev/null +++ b/src/renderer/src/components/anonymizer/label-manager/label.tsx @@ -0,0 +1,28 @@ +import { HStack, styled } from "@/styled/jsx"; +import { XCircle } from "phosphor-react"; + +interface LabelProps { + children: string; + onRemove: () => void; +} +export function Label({ children, onRemove }: LabelProps) { + return ( + + {children} + + + + + ); +} From 0978aff679a7ea2b071f7ad75ea2a4e63ea6b56e Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Wed, 15 Apr 2026 03:13:17 -0300 Subject: [PATCH 089/263] add label manager to file annotator --- .../src/components/file-annotator/index.tsx | 62 +++++++++++-------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/src/renderer/src/components/file-annotator/index.tsx b/src/renderer/src/components/file-annotator/index.tsx index da2920c9..5d1f8bbf 100644 --- a/src/renderer/src/components/file-annotator/index.tsx +++ b/src/renderer/src/components/file-annotator/index.tsx @@ -4,8 +4,10 @@ import { SearchBar } from "./SearchBar"; import type { SelectOption } from "@/components/select"; import AnnotationProvider from "@/context/Annotation"; +import { HStack } from "@/styled/jsx"; import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; import type { DocFile } from "@/types/file"; +import LabelManager from "../anonymizer/label-manager"; import * as S from "./FileAnnotator.styles"; import { Mark } from "./Mark"; import { createAnnotationsWithSearch } from "./annotations"; @@ -45,6 +47,7 @@ export default function FileAnnotator({ file, isAnnotable = false }: Props) { const [labelSearch, setLabelSearch] = useState(null); const [sufixlabelSearch, setSufixLabelSearch] = useState(0); + const [labelManagerOpen, setLabelManagerOpen] = useState(false); const searchTag = useMemo(() => { return labelSearch @@ -62,39 +65,46 @@ export default function FileAnnotator({ file, isAnnotable = false }: Props) { setLabelSearch((option?.id as AllLabels) ?? null); }; + const toggleManagerLabel = () => { + setLabelManagerOpen(!labelManagerOpen); + }; + return ( - - + + - - - - {paragraphs.map((p) => { - const annotations = createAnnotationsWithSearch( - file.predictions ?? [], - search, - p, + + - {p.value} - - ); - })} - - - + }} + > + {paragraphs.map((p) => { + const annotations = createAnnotationsWithSearch( + file.predictions ?? [], + search, + p, + searchTag, + ); + return ( + + {p.value} + + ); + })} + + + + {labelManagerOpen && } + ); } From 091b2c58e4eda2bd0711e0cc93a0467808b44e4d Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Wed, 15 Apr 2026 03:13:27 -0300 Subject: [PATCH 090/263] make search bar static and follow scroll --- .../src/components/file-annotator/FileAnnotator.styles.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts b/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts index 6ec38a30..69a50ce5 100644 --- a/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts +++ b/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts @@ -6,10 +6,14 @@ export const Container = styled("div", { // boxShadow: "0px 0px 10px rgba(0, 0, 0, 0.1)", zIndex: 1, - overflowY: "scroll", + display: "flex", + flexDirection: "column", + overflow: "hidden", }); export const File = styled("div", { + flex: 1, + overflowY: "scroll", px: "$xl", pb: "$xl", // pt: "$l", From 9585726bca80097d75c4eff1f0124df9e7a7eccc Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Wed, 15 Apr 2026 03:21:35 -0300 Subject: [PATCH 091/263] use translation on droparea --- src/renderer/src/components/drop-area.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/renderer/src/components/drop-area.tsx b/src/renderer/src/components/drop-area.tsx index 621b3364..4226066f 100644 --- a/src/renderer/src/components/drop-area.tsx +++ b/src/renderer/src/components/drop-area.tsx @@ -3,7 +3,6 @@ import { css, cva } from "@/styled/css"; import { Stack, styled } from "@/styled/jsx"; import { File } from "phosphor-react"; import { useCallback, useRef, useState } from "react"; -import { useTranslation } from "react-i18next"; function FileIcon() { return ( @@ -53,14 +52,17 @@ const styles = cva({ interface DropAreaProps { onDropFiles: (files: File[]) => void; + title: string; + description: string; multiple?: boolean; } export default function DropArea({ onDropFiles, + title, + description, multiple = true, }: DropAreaProps) { - const { t } = useTranslation(); const [dragging, setDragging] = useState(false); const inputRef = useRef(null); const dragCounter = useRef(0); @@ -132,11 +134,10 @@ export default function DropArea({ textAlign="center" whiteSpace="pre-line" > - {t("dropArea.selectFile")} + {title} - {t("dropArea.validFormats")}{" "} - {WHITELISTED_EXTENSIONS.map((e) => `.${e}`).join(", ")} + {description} Date: Wed, 15 Apr 2026 03:21:45 -0300 Subject: [PATCH 092/263] clear files on features menu --- src/renderer/src/components/features-menu.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/renderer/src/components/features-menu.tsx b/src/renderer/src/components/features-menu.tsx index 397b2b4d..f2c9a8d7 100644 --- a/src/renderer/src/components/features-menu.tsx +++ b/src/renderer/src/components/features-menu.tsx @@ -1,5 +1,7 @@ import { Grid, Stack, styled } from "@/styled/jsx"; import { FeatureFlowEnum, featureNamespace } from "@/types/features"; +import { useFileDispatch } from "@/hooks/useFiles"; +import { removeAllFiles } from "@/reducers/file/actions"; import { Link } from "@tanstack/react-router"; import { DotsNine } from "phosphor-react"; import { useTranslation } from "react-i18next"; @@ -10,8 +12,13 @@ import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover"; export default function FeaturesMenu() { const { t } = useTranslation(); + const dispatch = useFileDispatch(); const features = Object.values(FeatureFlowEnum); + const handleClearFiles = () => { + dispatch(removeAllFiles()); + }; + return ( @@ -22,7 +29,12 @@ export default function FeaturesMenu() { {features.map((feature) => ( - + From 2c9d6cf8be2ef63c8fbf844da553ea52e71a64cf Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Wed, 15 Apr 2026 11:52:43 -0300 Subject: [PATCH 093/263] make dataset validation file annotator not annotable --- src/renderer/src/components/validate-dataset/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/src/components/validate-dataset/index.tsx b/src/renderer/src/components/validate-dataset/index.tsx index 617b964b..65ebdc5e 100644 --- a/src/renderer/src/components/validate-dataset/index.tsx +++ b/src/renderer/src/components/validate-dataset/index.tsx @@ -73,7 +73,7 @@ export function ValidateDataset() {
3. Validación de datos From 762cf823b4b707be7f5899b6ee02b216e50db1de Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Thu, 16 Apr 2026 02:08:24 -0300 Subject: [PATCH 094/263] add missing built by in features page --- src/renderer/src/routes/home/features.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/renderer/src/routes/home/features.tsx b/src/renderer/src/routes/home/features.tsx index f825157f..0105eb67 100644 --- a/src/renderer/src/routes/home/features.tsx +++ b/src/renderer/src/routes/home/features.tsx @@ -1,3 +1,4 @@ +import BuiltBy from "@/components/brand/built-by"; import FeatureIcon from "@/components/feature-icon"; import FeaturesMenu from "@/components/features-menu"; import Header from "@/components/layout/header"; @@ -16,6 +17,13 @@ import { import type { Icon } from "phosphor-react"; import { useTranslation } from "react-i18next"; +const builtBy = css({ + pos: "absolute", + bottom: "16", // 64px + left: "[50%]", + transform: "[translateX(-50%)]", +}); + interface CardToolProps extends LinkComponentProps { title: string; subtitle: string; @@ -80,6 +88,10 @@ function RouteComponent() { /> + {/* Floating content below */} +
+ +
From 4ed68454cecf7fb5839b348342c29adb04cef4ff Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Thu, 16 Apr 2026 02:52:55 -0300 Subject: [PATCH 095/263] drop file queries when resetting the progress --- src/renderer/src/routes/app.$feature/onboarding.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/routes/app.$feature/onboarding.tsx b/src/renderer/src/routes/app.$feature/onboarding.tsx index 4b8e4fe5..8abda4ee 100644 --- a/src/renderer/src/routes/app.$feature/onboarding.tsx +++ b/src/renderer/src/routes/app.$feature/onboarding.tsx @@ -18,7 +18,8 @@ import { addFiles } from "@/reducers/file/actions"; import { useSetTutorialSeen, useTutorialSeen } from "@/store/useLocal"; import { HStack, Stack, styled } from "@/styled/jsx"; import { featureNamespace } from "@/types/features"; -import { useRef } from "react"; +import { useQueryClient } from "@tanstack/react-query"; +import { useEffect, useRef } from "react"; import { useTranslation } from "react-i18next"; // FIRST step of the processing workflow @@ -27,12 +28,12 @@ export const Route = createFileRoute("/app/$feature/onboarding")({ }); function RouteComponent() { + const queryClient = useQueryClient(); const { feature } = useParams({ from: "/app/$feature/onboarding", }); const navigate = useNavigate(); const { t } = useTranslation(featureNamespace[feature]); - console.log({ feature, title: t("onboarding.dropAreaTitle") }); const inputRef = useRef(null); @@ -58,6 +59,11 @@ function RouteComponent() { inputRef.current?.click(); }; + useEffect(() => { + queryClient.removeQueries({ queryKey: ["predict"] }); + queryClient.removeQueries({ queryKey: ["file-parser"] }); + }, []); + return ( <>
From ba12dad249b885f2182db27231e7b69a308b4447 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Thu, 16 Apr 2026 03:17:56 -0300 Subject: [PATCH 096/263] add className prop to footer --- src/renderer/src/components/layout/footer.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/renderer/src/components/layout/footer.tsx b/src/renderer/src/components/layout/footer.tsx index a25d9170..6de643c4 100644 --- a/src/renderer/src/components/layout/footer.tsx +++ b/src/renderer/src/components/layout/footer.tsx @@ -1,4 +1,4 @@ -import { css } from "@/styled/css"; +import { css, cx } from "@/styled/css"; import BuiltBy from "../brand/built-by"; const content = css({ @@ -19,10 +19,15 @@ const childrenContainer = css({ interface FooterProps { withBuiltBy?: boolean; children?: React.ReactNode; + className?: string; } -export default function Footer({ withBuiltBy, children }: FooterProps) { +export default function Footer({ + withBuiltBy, + children, + className, +}: FooterProps) { return ( -
+
{withBuiltBy && }
{children}
From 490a1adb74aa8de8e4659bfca8585b53a3124377 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Thu, 16 Apr 2026 21:05:46 -0300 Subject: [PATCH 097/263] simplify finish dataset and anonymizer --- .../FinishAnonymizer.styles.ts | 5 - .../components/finish-anonymizer/index.tsx | 91 --------------- .../finish-dataset/FinishDataset.styles.ts | 8 -- .../src/components/finish-dataset/index.tsx | 110 ------------------ .../components/finish/finish-anonymizer.tsx | 65 +++++++++++ .../src/components/finish/finish-dataset.tsx | 79 +++++++++++++ .../components/finish/finish-main-content.tsx | 36 ++++++ .../constants/i18n/locales/es/anonymizer.ts | 2 +- .../src/constants/i18n/locales/es/dataset.ts | 2 +- 9 files changed, 182 insertions(+), 216 deletions(-) delete mode 100644 src/renderer/src/components/finish-anonymizer/FinishAnonymizer.styles.ts delete mode 100644 src/renderer/src/components/finish-anonymizer/index.tsx delete mode 100644 src/renderer/src/components/finish-dataset/FinishDataset.styles.ts delete mode 100644 src/renderer/src/components/finish-dataset/index.tsx create mode 100644 src/renderer/src/components/finish/finish-anonymizer.tsx create mode 100644 src/renderer/src/components/finish/finish-dataset.tsx create mode 100644 src/renderer/src/components/finish/finish-main-content.tsx diff --git a/src/renderer/src/components/finish-anonymizer/FinishAnonymizer.styles.ts b/src/renderer/src/components/finish-anonymizer/FinishAnonymizer.styles.ts deleted file mode 100644 index 642cdc8c..00000000 --- a/src/renderer/src/components/finish-anonymizer/FinishAnonymizer.styles.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { styled } from "@/styles"; - -export const Anchor = styled("a", { - mr: "auto", -}); diff --git a/src/renderer/src/components/finish-anonymizer/index.tsx b/src/renderer/src/components/finish-anonymizer/index.tsx deleted file mode 100644 index 9ae17254..00000000 --- a/src/renderer/src/components/finish-anonymizer/index.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { - Button, - Card, - FileCheck, - Grid, - SectionTitle, - Subtitle, - Text, -} from "@/components"; -import { useFileDispatch, useFiles } from "@/hooks"; - -import { removeAllFiles } from "@/reducers/file/actions"; -import { aymuraiService } from "@/services/aymurai"; -import { useQuery } from "@tanstack/react-query"; -import { useNavigate, useParams } from "@tanstack/react-router"; -import { useTranslation } from "react-i18next"; -import Footer from "../layout/footer"; -import MainContent from "../layout/main-content"; - -const changeExtension = (name: string) => { - const parts = name.split("."); - parts.pop(); - return `${[...parts].join(".")}_anonimizado.odt`; -}; - -export function FinishAnonymizer() { - const { t } = useTranslation("anonymizer"); - const params = useParams({ from: "/app/$feature/finish" }); - // We are sure that there is only one file, because we came from - // anonimization workflow - const file = useFiles()[0]; - const dispatch = useFileDispatch(); - const navigate = useNavigate(); - - const { - data: fileURI, - isLoading, - isError, - } = useQuery(aymuraiService.anonymize(file)); - - const downloadDocument = async () => { - if (!fileURI) { - console.error("Tried to download a file that is not ready."); - return; - } - const link = document.createElement("a"); - link.href = fileURI; - link.download = changeExtension(file.data.name); - - link.click(); - - document.removeChild(link); - }; - - const handleRestart = () => { - dispatch(removeAllFiles()); - navigate({ to: "/app/$feature/onboarding", params }); - }; - - return ( - <> - - {t("finish.sectionTitle")} - {t("finish.description")} - - {t("finish.subtitle")} - - - - - -
- - -
- - ); -} diff --git a/src/renderer/src/components/finish-dataset/FinishDataset.styles.ts b/src/renderer/src/components/finish-dataset/FinishDataset.styles.ts deleted file mode 100644 index 9670762a..00000000 --- a/src/renderer/src/components/finish-dataset/FinishDataset.styles.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { styled } from "@/styles"; - -/** - * @deprecated - */ -export const Anchor = styled("a", { - mr: "auto", -}); diff --git a/src/renderer/src/components/finish-dataset/index.tsx b/src/renderer/src/components/finish-dataset/index.tsx deleted file mode 100644 index d1e94ad2..00000000 --- a/src/renderer/src/components/finish-dataset/index.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { useEffect, useState } from "react"; - -import { - Button, - Card, - FileCheck, - Grid, - SectionTitle, - Subtitle, - Text, -} from "@/components"; -import { useFileDispatch, useFiles } from "@/hooks"; -import { Footer, Section } from "@/layout/main-old"; -import { removeAllFiles } from "@/reducers/file/actions"; -import filesystem from "@/services/filesystem"; -import type { DocFile } from "@/types/file"; -import { submitValidations } from "@/utils/file"; -import { useNavigate, useParams } from "@tanstack/react-router"; -import { useTranslation } from "react-i18next"; -import * as S from "./FinishDataset.styles"; - -export function FinishDataset() { - const { t } = useTranslation("dataset"); - const params = useParams({ from: "/app/$feature/finish" }); - const files = useFiles(); - const dispatch = useFileDispatch(); - const navigate = useNavigate(); - const [errorNames, setErrorNames] = useState([]); - const [isLoading, setIsLoading] = useState(true); - - const handleRestart = () => { - dispatch(removeAllFiles()); - navigate({ to: "/app/$feature/onboarding", params }); - }; - - const checkForErrors = (fileName: string) => - !!errorNames.find((name) => name === fileName); - - const submit = async (file: DocFile) => { - try { - // POST the validated data to the dataset - await submitValidations({ - isOnline: false, - validations: file.validationObject, - }); - } catch { - setErrorNames((names) => [...names, file.data.name]); - } - - // Export the feedback JSON - await filesystem.feedback.export(files); - }; - - // At first render, submit all the data - useEffect(() => { - const submitAll = async () => { - for (const file of files) { - await submit(file); - } - }; - - submitAll().then(() => setIsLoading(false)); - - // We strictly need to run this effect once - }, []); - - return ( - <> -
- {t("finish.sectionTitle")} - {t("finish.description")} - - - {t("finish.subtitle")} - - {files.map(({ data }) => ( - - ))} - - -
-
- - DataGenero - - - - -
- - ); -} diff --git a/src/renderer/src/components/finish/finish-anonymizer.tsx b/src/renderer/src/components/finish/finish-anonymizer.tsx new file mode 100644 index 00000000..0bb18fa7 --- /dev/null +++ b/src/renderer/src/components/finish/finish-anonymizer.tsx @@ -0,0 +1,65 @@ +import { useFiles } from "@/hooks"; +import { aymuraiService } from "@/services/aymurai"; +import { FeatureFlowEnum } from "@/types/features"; +import { useQuery } from "@tanstack/react-query"; +import { useTranslation } from "react-i18next"; +import FileCheck from "../file-check"; +import Footer from "../layout/footer"; +import Button from "../ui/button"; +import FinishMainContent from "./finish-main-content"; + +interface FinishAnonymizerProps { + onRestart: () => void; +} +export default function FinishAnonymizer({ onRestart }: FinishAnonymizerProps) { + const { t } = useTranslation("anonymizer"); + const file = useFiles().at(0); + + if (!file) throw new Error("Reached /finish but there's no file to read"); + + const { + data: fileURI, + isLoading, + isError, + } = useQuery(aymuraiService.anonymize(file)); + + const downloadDocument = async () => { + if (!fileURI) { + console.error("Tried to download a file that is not ready."); + return; + } + const link = document.createElement("a"); + link.href = fileURI; + link.download = changeExtension(file.data.name); + + link.click(); + + document.removeChild(link); + }; + + return ( + <> + + + +
+ + +
+ + ); +} + +function changeExtension(name: string) { + const parts = name.split("."); + parts.pop(); + return `${[...parts].join(".")}_anonimizado.odt`; +} diff --git a/src/renderer/src/components/finish/finish-dataset.tsx b/src/renderer/src/components/finish/finish-dataset.tsx new file mode 100644 index 00000000..a610121b --- /dev/null +++ b/src/renderer/src/components/finish/finish-dataset.tsx @@ -0,0 +1,79 @@ +import { useFiles } from "@/hooks/useFiles"; +import filesystem from "@/services/filesystem"; +import { HStack } from "@/styled/jsx"; +import { FeatureFlowEnum } from "@/types/features"; +import type { DocFile } from "@/types/file"; +import { submitValidations } from "@/utils/file"; +import { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import FileCheck from "../file-check"; +import Footer from "../layout/footer"; +import Button from "../ui/button"; +import FinishMainContent from "./finish-main-content"; + +interface FinishDatasetProps { + onRestart: () => void; +} +export default function FinishDataset({ onRestart }: FinishDatasetProps) { + const { t } = useTranslation("dataset"); + const files = useFiles(); + + const [errorNames, setErrorNames] = useState([]); + const [isLoading, setIsLoading] = useState(true); + + const checkForErrors = (fileName: string) => + !!errorNames.find((name) => name === fileName); + + const submit = async (file: DocFile) => { + try { + // POST the validated data to the dataset + await submitValidations({ + isOnline: false, + validations: file.validationObject, + }); + } catch { + setErrorNames((names) => [...names, file.data.name]); + } + + // Export the feedback JSON + await filesystem.feedback.export(files); + }; + + // At first render, submit all the data + useEffect(() => { + const submitAll = async () => { + for (const file of files) { + await submit(file); + } + }; + + submitAll().then(() => setIsLoading(false)); + + // We strictly need to run this effect once + }, []); + + return ( + <> + + {files.map(({ data }) => ( + + ))} + +
+ + + + +
+ + ); +} diff --git a/src/renderer/src/components/finish/finish-main-content.tsx b/src/renderer/src/components/finish/finish-main-content.tsx new file mode 100644 index 00000000..79a1f13d --- /dev/null +++ b/src/renderer/src/components/finish/finish-main-content.tsx @@ -0,0 +1,36 @@ +import { SectionTitle } from "@/layout/section-title"; +import { Grid, Stack, styled } from "@/styled/jsx"; +import { type FeatureFlowEnum, featureNamespace } from "@/types/features"; +import type React from "react"; +import { useTranslation } from "react-i18next"; +import MainContent from "../layout/main-content"; +import Card from "../ui/card"; + +interface FinishMainContentProps { + feature: FeatureFlowEnum; + children: React.ReactNode; +} +export default function FinishMainContent({ + feature, + children, +}: FinishMainContentProps) { + const { t } = useTranslation(featureNamespace[feature]); + return ( + + + + {t("finish.sectionTitle")} + + {t("finish.description")} + + + + {t("finish.subtitle")} + + {children} + + + + + ); +} diff --git a/src/renderer/src/constants/i18n/locales/es/anonymizer.ts b/src/renderer/src/constants/i18n/locales/es/anonymizer.ts index 384e2855..6d22c04f 100644 --- a/src/renderer/src/constants/i18n/locales/es/anonymizer.ts +++ b/src/renderer/src/constants/i18n/locales/es/anonymizer.ts @@ -38,7 +38,7 @@ const anonymizer = { "Los datos encontrados por AymurAI y posteriormente validados ya han sido anonimizados correctamente.", subtitle: "Archivo procesado", restart: "Cargar un nuevo documento", - download: "Descargar documento", + viewResult: "Descargar documento", }, }; diff --git a/src/renderer/src/constants/i18n/locales/es/dataset.ts b/src/renderer/src/constants/i18n/locales/es/dataset.ts index 04cb3eb9..6364809f 100644 --- a/src/renderer/src/constants/i18n/locales/es/dataset.ts +++ b/src/renderer/src/constants/i18n/locales/es/dataset.ts @@ -38,7 +38,7 @@ const dataset = { "Los datos encontrados por AymurAI y posteriormente validados ya son parte del set de datos abiertos con perspectiva de género.", subtitle: "Archivos procesados", restart: "Cargar más documentos", - viewDataset: "Ver set de datos", + viewResult: "Ver set de datos", }, }; From 12aa1c6b2af907bdf6800e6bb469038887ab5191 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Fri, 17 Apr 2026 09:19:13 -0300 Subject: [PATCH 098/263] update decision tabs to panda --- .../src/components/decision-tabs/index.tsx | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/renderer/src/components/decision-tabs/index.tsx b/src/renderer/src/components/decision-tabs/index.tsx index 4bfb5551..a6520c8d 100644 --- a/src/renderer/src/components/decision-tabs/index.tsx +++ b/src/renderer/src/components/decision-tabs/index.tsx @@ -1,30 +1,38 @@ -import { Plus as Icon } from "phosphor-react"; - -import { Stack, Tab, TabName } from "@/components"; +import { Tab, TabName } from "@/components"; +import { css } from "@/styled/css"; +import { Stack } from "@/styled/jsx"; import nArray from "@/utils/nArray"; -import { PlusButton } from "./DecisionTabs.styles"; +import { Plus } from "phosphor-react"; + +const button = css({ + cursor: "pointer", + p: "2", + display: "flex", + alignItems: "center", + justifyContent: "center", + + height: "full", + width: "12", +}); interface Props { selected: number; decisionAmount: number; addDecision: () => void; selectDecision: (n: number) => void; - // biome-ignore lint/suspicious/noExplicitAny: in the future this any will be removed - css?: any; } export default function DecisionTabs({ selected, decisionAmount, addDecision, selectDecision, - css, }: Props) { const decisionArr = nArray(decisionAmount, undefined).map((_, i) => i); const selectDecisionHandler = (n: number) => () => selectDecision(n); return ( - + {decisionArr.map((dec) => ( Decisión {dec + 1} ))} - - - + ); } From da1377ea9482d317407df7450e8b41ea55475357 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Fri, 17 Apr 2026 09:21:35 -0300 Subject: [PATCH 099/263] update file processing component --- .../src/components/file-processing/Button.tsx | 28 ------- .../src/components/file-processing/index.tsx | 76 ++++++++++++------- 2 files changed, 47 insertions(+), 57 deletions(-) delete mode 100644 src/renderer/src/components/file-processing/Button.tsx diff --git a/src/renderer/src/components/file-processing/Button.tsx b/src/renderer/src/components/file-processing/Button.tsx deleted file mode 100644 index 5614c494..00000000 --- a/src/renderer/src/components/file-processing/Button.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { ArrowsLeftRight as Restart, Stop } from "phosphor-react"; - -import { Button as BaseButton } from "@/components"; -import type { PredictStatus } from "@/hooks/usePredict"; - -interface Props { - status: PredictStatus; - onStop?: () => void; - onReplace?: () => void; -} -export default function Button({ status, onStop, onReplace }: Props) { - const style = { - minWidth: 210, - gap: "$xs", - }; - - return status === "processing" ? ( - - - Detener - - ) : ( - - - Reemplazar - - ); -} diff --git a/src/renderer/src/components/file-processing/index.tsx b/src/renderer/src/components/file-processing/index.tsx index e4cea92f..434baff3 100644 --- a/src/renderer/src/components/file-processing/index.tsx +++ b/src/renderer/src/components/file-processing/index.tsx @@ -1,26 +1,49 @@ -import { X } from "phosphor-react"; -import { type ChangeEventHandler, useRef } from "react"; +import { ArrowsLeftRight, Stop, X } from "phosphor-react"; +import { type ChangeEventHandler, type MouseEventHandler, useRef } from "react"; -import { Button as BaseButton, HiddenInput, Stack } from "@/components"; +import HiddenInput from "@/components/hidden-input"; +import Button from "@/components/ui/button"; import { useFileDispatch } from "@/hooks"; -import { type PredictStatus, usePredict } from "@/hooks/usePredict"; +import type { PredictStatus } from "@/hooks/usePredict"; import { removeFile, replaceFile } from "@/reducers/file/actions"; -import type { DocFile } from "@/types/file"; -import Button from "./Button"; +import { css } from "@/styled/css"; +import { Stack } from "@/styled/jsx"; import ProgressBar from "./ProgressBar"; +function ActionButton({ + status, + onClick, +}: { status: PredictStatus; onClick: MouseEventHandler }) { + return ( + + ); +} + interface Props { - file: DocFile; - onStatusChange?: (newStatus: PredictStatus) => void; - onFileReplace?: (newName: string) => void; + fileName: string; + status: PredictStatus; + progress: number; + onAbort?: () => void; } export default function FileProcessing({ - file, - onStatusChange, - onFileReplace, + fileName, + status, + progress, + onAbort, }: Props) { const inputRef = useRef(null); - const { progress, status, abort } = usePredict(file, { onStatusChange }); const dispatch = useFileDispatch(); const handleOpenFinder = () => { @@ -30,48 +53,43 @@ export default function FileProcessing({ const handleAddedFile: ChangeEventHandler = (e) => { const rawFiles = e.target.files; - // Check if any file was added if (rawFiles) { const files = Array.from(rawFiles); - - // Only one file can be used to replace the old one if (files.length > 0) { - onFileReplace?.(files[0].name); - dispatch(replaceFile(file.data.name, files[0])); + dispatch(replaceFile(fileName, files[0])); } } }; const handleStop = () => { - abort(); + onAbort?.(); }; const remove = () => { - abort(); - dispatch(removeFile(file.data.name)); + onAbort?.(); + dispatch(removeFile(fileName)); }; return ( - + - ); } From b39d5134ebeacdab988348f8bf891a15403766e7 Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 17 Apr 2026 14:18:32 -0300 Subject: [PATCH 100/263] chore: add .worktrees to .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index d0e24cbe..e534957c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. +# git worktrees +.worktrees/ + # dependencies /node_modules node_modules/* From 6f07cb3be2ad1ac4ae2b31cfbfbc65e9969334d1 Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 17 Apr 2026 14:33:11 -0300 Subject: [PATCH 101/263] feat(voice-to-text): add types, config flags, and zod schema Co-Authored-By: Claude Sonnet 4.6 --- src/renderer/src/schema/transcription.ts | 31 +++++++++++++++++++++ src/renderer/src/types/features.ts | 1 + src/renderer/src/types/transcription.ts | 35 ++++++++++++++++++++++++ src/renderer/src/utils/config.ts | 3 ++ 4 files changed, 70 insertions(+) create mode 100644 src/renderer/src/schema/transcription.ts create mode 100644 src/renderer/src/types/transcription.ts diff --git a/src/renderer/src/schema/transcription.ts b/src/renderer/src/schema/transcription.ts new file mode 100644 index 00000000..f162819e --- /dev/null +++ b/src/renderer/src/schema/transcription.ts @@ -0,0 +1,31 @@ +import { z } from "zod"; + +export const SpeakerSchema = z.object({ + id: z.string(), + label: z.string(), + initials: z.string().max(2), + color: z.enum(["primary", "secondary", "warning", "success"]), +}); + +export const TurnSchema = z.object({ + id: z.string().uuid(), + speakerId: z.string(), + text: z.string(), + startMs: z.number().nonnegative(), + endMs: z.number().nonnegative(), +}); + +export const TranscriptionSchema = z.object({ + id: z.string(), + title: z.string(), + audioFileName: z.string(), + audioDurationMs: z.number().nonnegative(), + audioObjectUrl: z.string(), + speakers: z.array(SpeakerSchema), + turns: z.array(TurnSchema), + createdAt: z.string(), +}); + +export type Transcription = z.infer; +export type Turn = z.infer; +export type Speaker = z.infer; diff --git a/src/renderer/src/types/features.ts b/src/renderer/src/types/features.ts index 3d176997..8c32e7d5 100644 --- a/src/renderer/src/types/features.ts +++ b/src/renderer/src/types/features.ts @@ -1,4 +1,5 @@ export enum Feature { Dataset = "DATA_SET", Anonymizer = "ANONYMIZER", + VoiceToText = "VOICE_TO_TEXT", } diff --git a/src/renderer/src/types/transcription.ts b/src/renderer/src/types/transcription.ts new file mode 100644 index 00000000..41b16ddf --- /dev/null +++ b/src/renderer/src/types/transcription.ts @@ -0,0 +1,35 @@ +export type SpeakerColor = "primary" | "secondary" | "warning" | "success"; +export type SpeakerId = string; + +export interface Speaker { + id: SpeakerId; + label: string; // "Locutor 1" | "Juez" | "Dra. Silva" + initials: string; // 2 chars derived from label + color: SpeakerColor; +} + +export interface Turn { + id: string; // uuid + speakerId: SpeakerId; + text: string; + startMs: number; // visible in UI as "mm:ss" + endMs: number; +} + +export interface Transcription { + id: string; + title: string; // "Audiencia 10/04/2025" + audioFileName: string; + audioDurationMs: number; + audioObjectUrl: string; // URL.createObjectURL(file) + speakers: Speaker[]; + turns: Turn[]; + createdAt: string; +} + +export interface SuggestedSpeaker { + id: string; + label: string; + initials: string; + color: SpeakerColor; +} diff --git a/src/renderer/src/utils/config.ts b/src/renderer/src/utils/config.ts index a3fb3144..bae0ba7a 100644 --- a/src/renderer/src/utils/config.ts +++ b/src/renderer/src/utils/config.ts @@ -18,3 +18,6 @@ export const DATASET_URL = * AymurAI API URL */ export const AYMURAI_API_URL = `http://localhost:${PREDICT_PORT}`; + +export const USE_MOCK_STT = true; +export const STT_MOCK_DELAY_MS = 4000; From 9653e3325e14774221cdd8d12a937a780d4fde0a Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 17 Apr 2026 14:35:35 -0300 Subject: [PATCH 102/263] feat(voice-to-text): add STT mock service, fixtures, and useTranscribe hook Creates the transcription fixture builder with Figma turns, the suggested speakers constant, the transcribe() service (mock + real path with Zod validation), and the useTranscribe hook following the usePredict pattern. Co-Authored-By: Claude Sonnet 4.6 --- src/renderer/src/hooks/useTranscribe.ts | 83 +++++++++++++++++++ .../aymurai/fixtures/suggestedSpeakers.ts | 9 ++ .../aymurai/fixtures/transcription.ts | 52 ++++++++++++ .../src/services/aymurai/transcribe.ts | 41 +++++++++ 4 files changed, 185 insertions(+) create mode 100644 src/renderer/src/hooks/useTranscribe.ts create mode 100644 src/renderer/src/services/aymurai/fixtures/suggestedSpeakers.ts create mode 100644 src/renderer/src/services/aymurai/fixtures/transcription.ts create mode 100644 src/renderer/src/services/aymurai/transcribe.ts diff --git a/src/renderer/src/hooks/useTranscribe.ts b/src/renderer/src/hooks/useTranscribe.ts new file mode 100644 index 00000000..cea4aa24 --- /dev/null +++ b/src/renderer/src/hooks/useTranscribe.ts @@ -0,0 +1,83 @@ +import { useCallback, useEffect, useRef, useState } from "react"; + +import { CanceledError } from "axios"; + +import { transcribe } from "@/services/aymurai/transcribe"; +import type { Transcription } from "@/types/transcription"; + +export type TranscribeStatus = + | "idle" + | "processing" + | "completed" + | "error" + | "stopped"; + +interface UseTranscribeOptions { + onTranscription?: (transcription: Transcription) => void; + onStatusChange?: (status: TranscribeStatus) => void; +} + +export function useTranscribe( + files: File[], + { onTranscription, onStatusChange }: UseTranscribeOptions = {}, +) { + const [progress, setProgress] = useState(0); + const [status, setStatus] = useState("idle"); + + const controller = useRef(new AbortController()); + + const updateStatus = useCallback((newValue: TranscribeStatus) => { + setStatus(newValue); + onStatusChange?.(newValue); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const abort = () => { + controller.current.abort(); + updateStatus("stopped"); + setProgress(0); + }; + + useEffect(() => { + if (files.length === 0) return; + + let active = true; + + const run = async () => { + updateStatus("processing"); + setProgress(0); + + const promises = files.map(async (file) => { + const result = await transcribe(file, controller.current.signal); + + if (!active) return; + + onTranscription?.(result); + setProgress((current) => current + 1 / files.length); + }); + + await Promise.all(promises) + .then(() => { + if (!active) return; + updateStatus("completed"); + }) + .catch((err) => { + if (!active) return; + if (err instanceof CanceledError) { + updateStatus("stopped"); + } else { + setProgress(0); + updateStatus("error"); + } + }); + }; + + run(); + + return () => { + active = false; + }; + }, [files]); + + return { progress, status, abort }; +} diff --git a/src/renderer/src/services/aymurai/fixtures/suggestedSpeakers.ts b/src/renderer/src/services/aymurai/fixtures/suggestedSpeakers.ts new file mode 100644 index 00000000..73c830d7 --- /dev/null +++ b/src/renderer/src/services/aymurai/fixtures/suggestedSpeakers.ts @@ -0,0 +1,9 @@ +import type { SuggestedSpeaker } from "@/types/transcription"; + +export const SUGGESTED_SPEAKERS: SuggestedSpeaker[] = [ + { id: "sg1", label: "Jueza", initials: "JU", color: "primary" }, + { id: "sg2", label: "Fiscal", initials: "FI", color: "secondary" }, + { id: "sg3", label: "Defensor", initials: "DE", color: "warning" }, + { id: "sg4", label: "Imputado", initials: "IM", color: "success" }, + { id: "sg5", label: "Testigo", initials: "TE", color: "primary" }, +]; diff --git a/src/renderer/src/services/aymurai/fixtures/transcription.ts b/src/renderer/src/services/aymurai/fixtures/transcription.ts new file mode 100644 index 00000000..90839a19 --- /dev/null +++ b/src/renderer/src/services/aymurai/fixtures/transcription.ts @@ -0,0 +1,52 @@ +import type { Transcription } from "@/types/transcription"; + +const TOTAL_DURATION_MS = 492_000; // 8min 12s + +const TURNS_TEXT = [ + { + speakerId: "s1", + text: "Estamos aquí reunidos en virtud de un caso que tiene el número 78274. La fiscalía está trabajando la investigación de ese caso, para lo cual estaba prevista la discusión de los hechos como corresponde en un juicio oral y público para ver si corresponde o no que las personas respondamos penalmente. Hasta ese momento resultamos todas las personas inocentes. Lo que me hicieron saber es que usted tenía una pretensión, y es que se analice la posibilidad de que el caso no avance y se efectúe ese juicio oral y público a resultas de un ofrecimiento.", + }, + { + speakerId: "s2", + text: "Nosotros lo que solicitamos es la suspensión del presente juicio a prueba en la primera parte del artículo 76 del código penal. A los efectos de la suspensión lo que propuso mi cliente fue el pago de 100.000 pesos en cuatro cuotas de 25.000 pesos, además de las pautas que considere la fiscalía respecto de la suspensión.", + }, + { + speakerId: "s1", + text: "Tiene alguna propuesta más allá de que las pautas obviamente están supeditadas a que la fiscalía pueda fundar respecto de los hechos y los objetivos?", + }, + { + speakerId: "s2", + text: "Nosotros habíamos pensado en un tipo de tarea comunitaria por un período. No tenemos una propuesta concreta, pero habíamos analizado la posibilidad de que sean 16 horas totales en el año.", + }, + { + speakerId: "s1", + text: "Señor Rodríguez, le voy a pedir que se acerque al micrófono lo más posible. Dígame su nombre completo, su DNI, su fecha de nacimiento, su género y dónde vive.", + }, +]; + +export function buildFixture(file: File): Transcription { + const sliceMs = TOTAL_DURATION_MS / TURNS_TEXT.length; + + const turns = TURNS_TEXT.map((t, i) => ({ + id: crypto.randomUUID(), + speakerId: t.speakerId, + text: t.text, + startMs: Math.round(i * sliceMs), + endMs: Math.round((i + 1) * sliceMs), + })); + + return { + id: crypto.randomUUID(), + title: "Audiencia 10/04/2025", + audioFileName: file.name, + audioDurationMs: TOTAL_DURATION_MS, + audioObjectUrl: URL.createObjectURL(file), + createdAt: new Date().toISOString(), + speakers: [ + { id: "s1", label: "Locutor 1", initials: "L1", color: "primary" }, + { id: "s2", label: "Locutor 2", initials: "L2", color: "secondary" }, + ], + turns, + }; +} diff --git a/src/renderer/src/services/aymurai/transcribe.ts b/src/renderer/src/services/aymurai/transcribe.ts new file mode 100644 index 00000000..c7b8c27b --- /dev/null +++ b/src/renderer/src/services/aymurai/transcribe.ts @@ -0,0 +1,41 @@ +import { CanceledError } from "axios"; + +import { USE_MOCK_STT, STT_MOCK_DELAY_MS } from "@/utils/config"; +import { TranscriptionSchema } from "@/schema/transcription"; +import { buildFixture } from "./fixtures/transcription"; +import type { Transcription } from "@/types/transcription"; +import api from "../api"; + +/** + * Sends an audio file to the STT service and returns a Transcription. + * When USE_MOCK_STT is true it resolves after STT_MOCK_DELAY_MS with fixture data. + * @param file Audio file to transcribe + * @param signal Optional AbortSignal for cancellation + */ +export async function transcribe( + file: File, + signal?: AbortSignal, +): Promise { + if (USE_MOCK_STT) { + return new Promise((resolve, reject) => { + const timer = setTimeout( + () => resolve(buildFixture(file)), + STT_MOCK_DELAY_MS, + ); + signal?.addEventListener("abort", () => { + clearTimeout(timer); + reject(new CanceledError()); + }); + }); + } + + const form = new FormData(); + form.append("audio", file); + + const data = await api.post("/stt/transcribe", form, { + headers: { "Content-Type": "multipart/form-data" }, + signal, + }); + + return TranscriptionSchema.parse(data); +} From e33eba1dba519062266471be6f0da3ea0354fd2e Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 17 Apr 2026 14:38:12 -0300 Subject: [PATCH 103/263] feat(voice-to-text): add transcription context, reducer, and hooks Implements TranscriptionContext/Provider, reducer with all action types, useTranscriptions/useTranscriptionDispatch hooks, mounts TranscriptionProvider in the main layout, and extends useTranscribe to dispatch to context. Co-Authored-By: Claude Sonnet 4.6 --- src/renderer/src/context/Transcription.tsx | 38 +++ src/renderer/src/hooks/useTranscribe.ts | 6 +- src/renderer/src/hooks/useTranscriptions.ts | 20 ++ src/renderer/src/layout/main/index.tsx | 11 +- .../src/reducers/transcription/actions.ts | 192 ++++++++++++++++ .../src/reducers/transcription/index.ts | 216 ++++++++++++++++++ 6 files changed, 478 insertions(+), 5 deletions(-) create mode 100644 src/renderer/src/context/Transcription.tsx create mode 100644 src/renderer/src/hooks/useTranscriptions.ts create mode 100644 src/renderer/src/reducers/transcription/actions.ts create mode 100644 src/renderer/src/reducers/transcription/index.ts diff --git a/src/renderer/src/context/Transcription.tsx b/src/renderer/src/context/Transcription.tsx new file mode 100644 index 00000000..e7b773dd --- /dev/null +++ b/src/renderer/src/context/Transcription.tsx @@ -0,0 +1,38 @@ +import { + type Dispatch, + type ReactNode, + createContext, + useReducer, +} from "react"; + +import reducer, { type TranscriptionAction } from "@/reducers/transcription"; +import type { Transcription } from "@/types/transcription"; + +/** + * Context used to provide transcriptions in the state + */ +export const TranscriptionContext = createContext([]); +TranscriptionContext.displayName = "TranscriptionContext"; + +/** + * Context used to provide the dispatch function + */ +export const TranscriptionDispatchContext = createContext>( + () => {}, +); +TranscriptionDispatchContext.displayName = "TranscriptionDispatchContext"; + +interface Props { + children: ReactNode; +} +export default function TranscriptionProvider({ children }: Props) { + const [state, dispatch] = useReducer(reducer, []); + + return ( + + + {children} + + + ); +} diff --git a/src/renderer/src/hooks/useTranscribe.ts b/src/renderer/src/hooks/useTranscribe.ts index cea4aa24..eb6fd2e7 100644 --- a/src/renderer/src/hooks/useTranscribe.ts +++ b/src/renderer/src/hooks/useTranscribe.ts @@ -2,8 +2,10 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { CanceledError } from "axios"; +import { addTranscription } from "@/reducers/transcription/actions"; import { transcribe } from "@/services/aymurai/transcribe"; import type { Transcription } from "@/types/transcription"; +import type { TranscriptionAction } from "@/reducers/transcription"; export type TranscribeStatus = | "idle" @@ -15,11 +17,12 @@ export type TranscribeStatus = interface UseTranscribeOptions { onTranscription?: (transcription: Transcription) => void; onStatusChange?: (status: TranscribeStatus) => void; + dispatch?: React.Dispatch; } export function useTranscribe( files: File[], - { onTranscription, onStatusChange }: UseTranscribeOptions = {}, + { onTranscription, onStatusChange, dispatch }: UseTranscribeOptions = {}, ) { const [progress, setProgress] = useState(0); const [status, setStatus] = useState("idle"); @@ -53,6 +56,7 @@ export function useTranscribe( if (!active) return; onTranscription?.(result); + dispatch?.(addTranscription(result)); setProgress((current) => current + 1 / files.length); }); diff --git a/src/renderer/src/hooks/useTranscriptions.ts b/src/renderer/src/hooks/useTranscriptions.ts new file mode 100644 index 00000000..c08483ee --- /dev/null +++ b/src/renderer/src/hooks/useTranscriptions.ts @@ -0,0 +1,20 @@ +import { useContext } from "react"; + +import { + TranscriptionContext, + TranscriptionDispatchContext, +} from "@/context/Transcription"; + +/** + * Hook used to view the transcriptions in the state + */ +export function useTranscriptions() { + return useContext(TranscriptionContext); +} + +/** + * Hook used to dispatch actions that modify the transcription state + */ +export function useTranscriptionDispatch() { + return useContext(TranscriptionDispatchContext); +} diff --git a/src/renderer/src/layout/main/index.tsx b/src/renderer/src/layout/main/index.tsx index f40e8cdf..44705e68 100644 --- a/src/renderer/src/layout/main/index.tsx +++ b/src/renderer/src/layout/main/index.tsx @@ -2,6 +2,7 @@ import { Outlet } from "react-router-dom"; import { ProfileInfo, Stepper, Title } from "@/components"; import FileProvider from "@/context/File"; +import TranscriptionProvider from "@/context/Transcription"; import FeatureRouter from "@/features/FeatureRouter"; import { Footer, Header, Layout, Section } from "./Main.styles"; import type { Props } from "./Main.types"; @@ -20,10 +21,12 @@ function GenericMain({ title }: Props) {
- - {/* Content as Outlet, managed by React-Router */} - - + + + {/* Content as Outlet, managed by React-Router */} + + + ); } diff --git a/src/renderer/src/reducers/transcription/actions.ts b/src/renderer/src/reducers/transcription/actions.ts new file mode 100644 index 00000000..994f35f6 --- /dev/null +++ b/src/renderer/src/reducers/transcription/actions.ts @@ -0,0 +1,192 @@ +import type { Speaker, SuggestedSpeaker, Transcription, Turn } from "@/types/transcription"; + +/** + * List of action types. + */ +export enum ActionTypes { + ADD_TRANSCRIPTION = "ADD_TRANSCRIPTION", + REMOVE_TRANSCRIPTION = "REMOVE_TRANSCRIPTION", + RENAME_SPEAKER_GLOBAL = "RENAME_SPEAKER_GLOBAL", + REASSIGN_TURN_SPEAKER = "REASSIGN_TURN_SPEAKER", + UPDATE_TURN_TEXT = "UPDATE_TURN_TEXT", + INSERT_TURN = "INSERT_TURN", + REMOVE_TURN = "REMOVE_TURN", + ADD_SPEAKER = "ADD_SPEAKER", + ASSIGN_SUGGESTED_SPEAKER_TO_TURN = "ASSIGN_SUGGESTED_SPEAKER_TO_TURN", +} + +/** + * Generic action + */ +type Action = { + type: Type; + payload: Payload; +}; + +export type AddTranscriptionAction = Action< + ActionTypes.ADD_TRANSCRIPTION, + { transcription: Transcription } +>; +/** + * Adds a new transcription to the state + * @param transcription Transcription to be added + */ +export function addTranscription(transcription: Transcription): AddTranscriptionAction { + return { + type: ActionTypes.ADD_TRANSCRIPTION, + payload: { transcription }, + }; +} + +export type RemoveTranscriptionAction = Action< + ActionTypes.REMOVE_TRANSCRIPTION, + { id: string } +>; +/** + * Removes a transcription from the state by id + * @param id ID of the transcription to remove + */ +export function removeTranscription(id: string): RemoveTranscriptionAction { + return { + type: ActionTypes.REMOVE_TRANSCRIPTION, + payload: { id }, + }; +} + +export type RenameSpeakerGlobalAction = Action< + ActionTypes.RENAME_SPEAKER_GLOBAL, + { transcriptionId: string; speakerId: string; newLabel: string } +>; +/** + * Renames a speaker globally across the transcription, recalculating initials + * @param transcriptionId ID of the transcription to modify + * @param speakerId ID of the speaker to rename + * @param newLabel New label for the speaker + */ +export function renameSpeakerGlobal( + transcriptionId: string, + speakerId: string, + newLabel: string, +): RenameSpeakerGlobalAction { + return { + type: ActionTypes.RENAME_SPEAKER_GLOBAL, + payload: { transcriptionId, speakerId, newLabel }, + }; +} + +export type ReassignTurnSpeakerAction = Action< + ActionTypes.REASSIGN_TURN_SPEAKER, + { transcriptionId: string; turnId: string; newSpeakerId: string } +>; +/** + * Reassigns a turn to a different speaker + * @param transcriptionId ID of the transcription to modify + * @param turnId ID of the turn to reassign + * @param newSpeakerId ID of the new speaker + */ +export function reassignTurnSpeaker( + transcriptionId: string, + turnId: string, + newSpeakerId: string, +): ReassignTurnSpeakerAction { + return { + type: ActionTypes.REASSIGN_TURN_SPEAKER, + payload: { transcriptionId, turnId, newSpeakerId }, + }; +} + +export type UpdateTurnTextAction = Action< + ActionTypes.UPDATE_TURN_TEXT, + { transcriptionId: string; turnId: string; text: string } +>; +/** + * Updates the text content of a turn + * @param transcriptionId ID of the transcription to modify + * @param turnId ID of the turn to update + * @param text New text content + */ +export function updateTurnText( + transcriptionId: string, + turnId: string, + text: string, +): UpdateTurnTextAction { + return { + type: ActionTypes.UPDATE_TURN_TEXT, + payload: { transcriptionId, turnId, text }, + }; +} + +export type InsertTurnAction = Action< + ActionTypes.INSERT_TURN, + { transcriptionId: string; afterTurnId: string | null; turn: Turn } +>; +/** + * Inserts a new turn after the specified turn, or at the end if afterTurnId is null + * @param transcriptionId ID of the transcription to modify + * @param afterTurnId ID of the turn to insert after, or null to append at end + * @param turn Turn to insert + */ +export function insertTurn( + transcriptionId: string, + afterTurnId: string | null, + turn: Turn, +): InsertTurnAction { + return { + type: ActionTypes.INSERT_TURN, + payload: { transcriptionId, afterTurnId, turn }, + }; +} + +export type RemoveTurnAction = Action< + ActionTypes.REMOVE_TURN, + { transcriptionId: string; turnId: string } +>; +/** + * Removes a turn from a transcription + * @param transcriptionId ID of the transcription to modify + * @param turnId ID of the turn to remove + */ +export function removeTurn(transcriptionId: string, turnId: string): RemoveTurnAction { + return { + type: ActionTypes.REMOVE_TURN, + payload: { transcriptionId, turnId }, + }; +} + +export type AddSpeakerAction = Action< + ActionTypes.ADD_SPEAKER, + { transcriptionId: string; speaker: Speaker } +>; +/** + * Adds a new speaker to a transcription + * @param transcriptionId ID of the transcription to modify + * @param speaker Speaker to add + */ +export function addSpeaker(transcriptionId: string, speaker: Speaker): AddSpeakerAction { + return { + type: ActionTypes.ADD_SPEAKER, + payload: { transcriptionId, speaker }, + }; +} + +export type AssignSuggestedSpeakerToTurnAction = Action< + ActionTypes.ASSIGN_SUGGESTED_SPEAKER_TO_TURN, + { transcriptionId: string; turnId: string; suggested: SuggestedSpeaker } +>; +/** + * Finds or creates the speaker in the transcription from a suggested speaker, + * then reassigns the turn to it + * @param transcriptionId ID of the transcription to modify + * @param turnId ID of the turn to reassign + * @param suggested The suggested speaker data + */ +export function assignSuggestedSpeakerToTurn( + transcriptionId: string, + turnId: string, + suggested: SuggestedSpeaker, +): AssignSuggestedSpeakerToTurnAction { + return { + type: ActionTypes.ASSIGN_SUGGESTED_SPEAKER_TO_TURN, + payload: { transcriptionId, turnId, suggested }, + }; +} diff --git a/src/renderer/src/reducers/transcription/index.ts b/src/renderer/src/reducers/transcription/index.ts new file mode 100644 index 00000000..d6271c19 --- /dev/null +++ b/src/renderer/src/reducers/transcription/index.ts @@ -0,0 +1,216 @@ +import type { Speaker, Transcription } from "@/types/transcription"; + +import { + ActionTypes, + type AddSpeakerAction, + type AddTranscriptionAction, + type AssignSuggestedSpeakerToTurnAction, + type InsertTurnAction, + type ReassignTurnSpeakerAction, + type RemoveTranscriptionAction, + type RemoveTurnAction, + type RenameSpeakerGlobalAction, + type UpdateTurnTextAction, +} from "./actions"; + +type State = Transcription[]; + +export type TranscriptionAction = + | AddTranscriptionAction + | RemoveTranscriptionAction + | RenameSpeakerGlobalAction + | ReassignTurnSpeakerAction + | UpdateTurnTextAction + | InsertTurnAction + | RemoveTurnAction + | AddSpeakerAction + | AssignSuggestedSpeakerToTurnAction; + +/** + * Computes speaker initials from a label. + * Takes the first character of each word, max 2 characters, uppercased. + * E.g. "Dra. Silva" → "DS", "Locutor 1" → "L1", "Jueza" → "JU" + */ +function computeInitials(label: string): string { + const words = label.trim().split(/\s+/); + + if (words.length === 1) { + // Single word: take first two characters + return words[0].slice(0, 2).toUpperCase(); + } + + // Multi-word: take first char of each word, max 2 + return words + .slice(0, 2) + .map((w) => w.charAt(0)) + .join("") + .toUpperCase(); +} + +/** + * Updates a specific transcription in the state by id + */ +function updateTranscription( + state: State, + transcriptionId: string, + updater: (t: Transcription) => Transcription, +): State { + return state.map((t) => (t.id === transcriptionId ? updater(t) : t)); +} + +/** + * Reducer function for `Transcription[]` state + * @param state Current state + * @param action Action to perform + * @returns A new state + */ +export default function reducer(state: State, action: TranscriptionAction): State { + const { type, payload } = action; + + switch (type) { + // ---------------- + // ADD TRANSCRIPTION + // ---------------- + case ActionTypes.ADD_TRANSCRIPTION: { + const { transcription } = payload; + return [...state, transcription]; + } + + // ---------------- + // REMOVE TRANSCRIPTION + // ---------------- + case ActionTypes.REMOVE_TRANSCRIPTION: { + const { id } = payload; + return state.filter((t) => t.id !== id); + } + + // ---------------- + // RENAME SPEAKER GLOBAL + // ---------------- + case ActionTypes.RENAME_SPEAKER_GLOBAL: { + const { transcriptionId, speakerId, newLabel } = payload; + return updateTranscription(state, transcriptionId, (t) => ({ + ...t, + speakers: t.speakers.map((s) => + s.id === speakerId + ? { ...s, label: newLabel, initials: computeInitials(newLabel) } + : s, + ), + })); + } + + // ---------------- + // REASSIGN TURN SPEAKER + // ---------------- + case ActionTypes.REASSIGN_TURN_SPEAKER: { + const { transcriptionId, turnId, newSpeakerId } = payload; + return updateTranscription(state, transcriptionId, (t) => ({ + ...t, + turns: t.turns.map((turn) => + turn.id === turnId ? { ...turn, speakerId: newSpeakerId } : turn, + ), + })); + } + + // ---------------- + // UPDATE TURN TEXT + // ---------------- + case ActionTypes.UPDATE_TURN_TEXT: { + const { transcriptionId, turnId, text } = payload; + return updateTranscription(state, transcriptionId, (t) => ({ + ...t, + turns: t.turns.map((turn) => + turn.id === turnId ? { ...turn, text } : turn, + ), + })); + } + + // ---------------- + // INSERT TURN + // ---------------- + case ActionTypes.INSERT_TURN: { + const { transcriptionId, afterTurnId, turn } = payload; + return updateTranscription(state, transcriptionId, (t) => { + if (afterTurnId === null) { + return { ...t, turns: [...t.turns, turn] }; + } + + const insertIdx = t.turns.findIndex((tu) => tu.id === afterTurnId); + if (insertIdx === -1) { + return { ...t, turns: [...t.turns, turn] }; + } + + const newTurns = [ + ...t.turns.slice(0, insertIdx + 1), + turn, + ...t.turns.slice(insertIdx + 1), + ]; + return { ...t, turns: newTurns }; + }); + } + + // ---------------- + // REMOVE TURN + // ---------------- + case ActionTypes.REMOVE_TURN: { + const { transcriptionId, turnId } = payload; + return updateTranscription(state, transcriptionId, (t) => ({ + ...t, + turns: t.turns.filter((turn) => turn.id !== turnId), + })); + } + + // ---------------- + // ADD SPEAKER + // ---------------- + case ActionTypes.ADD_SPEAKER: { + const { transcriptionId, speaker } = payload; + return updateTranscription(state, transcriptionId, (t) => ({ + ...t, + speakers: [...t.speakers, speaker], + })); + } + + // ---------------- + // ASSIGN SUGGESTED SPEAKER TO TURN + // ---------------- + case ActionTypes.ASSIGN_SUGGESTED_SPEAKER_TO_TURN: { + const { transcriptionId, turnId, suggested } = payload; + return updateTranscription(state, transcriptionId, (t) => { + const existing = t.speakers.find((s) => s.label === suggested.label); + + if (existing) { + // Speaker with same label already exists — reassign turn to it + return { + ...t, + turns: t.turns.map((turn) => + turn.id === turnId ? { ...turn, speakerId: existing.id } : turn, + ), + }; + } + + // Create a new speaker from the suggested data + const newSpeaker: Speaker = { + id: suggested.id, + label: suggested.label, + initials: suggested.initials, + color: suggested.color, + }; + + return { + ...t, + speakers: [...t.speakers, newSpeaker], + turns: t.turns.map((turn) => + turn.id === turnId ? { ...turn, speakerId: newSpeaker.id } : turn, + ), + }; + }); + } + + // ---------------- + // DEFAULT + // ---------------- + default: + return state; + } +} From 7f04675d19c9823e79352ba3c922ab4c04ec4f05 Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 17 Apr 2026 14:40:06 -0300 Subject: [PATCH 104/263] feat(voice-to-text): add FeatureCard, Switch, and SpeakerAvatar components Co-Authored-By: Claude Sonnet 4.6 --- .../src/components/feature-card/index.tsx | 85 +++++++++++++++++ src/renderer/src/components/index.ts | 6 ++ .../src/components/speaker-avatar/index.tsx | 63 +++++++++++++ src/renderer/src/components/switch/index.tsx | 92 +++++++++++++++++++ 4 files changed, 246 insertions(+) create mode 100644 src/renderer/src/components/feature-card/index.tsx create mode 100644 src/renderer/src/components/speaker-avatar/index.tsx create mode 100644 src/renderer/src/components/switch/index.tsx diff --git a/src/renderer/src/components/feature-card/index.tsx b/src/renderer/src/components/feature-card/index.tsx new file mode 100644 index 00000000..6985194c --- /dev/null +++ b/src/renderer/src/components/feature-card/index.tsx @@ -0,0 +1,85 @@ +import { type ReactNode } from "react"; + +import { styled } from "@/styles/stitches.config"; + +const IconContainer = styled("div", { + display: "flex", + alignItems: "center", + justifyContent: "center", + width: 48, + height: 48, + borderRadius: 12, + backgroundColor: "$primaryAlt", + flexShrink: 0, +}); + +const CardTitle = styled("span", { + fontFamily: "$primary", + fontWeight: "$strong", + fontSize: "$subtitleMd", + lineHeight: "$subtitleMd", + color: "$primary", +}); + +const CardDescription = styled("span", { + fontFamily: "$primary", + fontWeight: "$default", + fontSize: "$subtitleSm", + lineHeight: "$subtitleSm", + color: "$textLighter", +}); + +const StyledCard = styled("div", { + display: "flex", + flexDirection: "column", + gap: 12, + padding: 24, + width: 320, + backgroundColor: "$bgSecondary", + border: "1px solid $borderPrimary", + borderRadius: "$s", + transition: "box-shadow $transitions$s, opacity $transitions$s", + + variants: { + disabled: { + true: { + opacity: 0.5, + cursor: "not-allowed", + }, + false: { + cursor: "pointer", + "&:hover": { + boxShadow: "0 2px 8px rgba(0, 0, 0, 0.08)", + }, + }, + }, + }, + defaultVariants: { + disabled: false, + }, +}); + +interface FeatureCardProps { + icon: ReactNode; + title: string; + description: string; + onClick?: () => void; + disabled?: boolean; +} + +function FeatureCard({ icon, title, description, onClick, disabled = false }: FeatureCardProps) { + return ( + + {icon} + {title} + {description} + + ); +} + +export default FeatureCard; diff --git a/src/renderer/src/components/index.ts b/src/renderer/src/components/index.ts index 5a10397b..8f4b6a34 100644 --- a/src/renderer/src/components/index.ts +++ b/src/renderer/src/components/index.ts @@ -1,6 +1,9 @@ import Arrow from "./arrow"; import Button from "./button"; import Card from "./card"; +import FeatureCard from "./feature-card"; +import SpeakerAvatar from "./speaker-avatar"; +import Switch from "./switch"; import { Checkbox, CheckboxGroup } from "./checkbox"; import DecisionTabs from "./decision-tabs"; import FileAnnotator from "./file-annotator"; @@ -33,6 +36,9 @@ export { Arrow, Button, Card, + FeatureCard, + SpeakerAvatar, + Switch, Checkbox, CheckboxGroup, DecisionTabs, diff --git a/src/renderer/src/components/speaker-avatar/index.tsx b/src/renderer/src/components/speaker-avatar/index.tsx new file mode 100644 index 00000000..e10945c5 --- /dev/null +++ b/src/renderer/src/components/speaker-avatar/index.tsx @@ -0,0 +1,63 @@ +import { type SpeakerColor } from "@/types/transcription"; +import { styled } from "@/styles/stitches.config"; + +const AvatarRoot = styled("div", { + display: "flex", + alignItems: "center", + justifyContent: "center", + borderRadius: "50%", + flexShrink: 0, + + fontFamily: "$primary", + fontWeight: "$default", + fontSize: "$labelSm", + lineHeight: "$labelSm", + textAlign: "center", + color: "$textDefault", + + variants: { + size: { + sm: { + width: 24, + height: 24, + }, + md: { + width: 32, + height: 32, + }, + }, + color: { + primary: { + backgroundColor: "$secondary", + }, + secondary: { + backgroundColor: "$bgSecondaryAlt", + }, + warning: { + backgroundColor: "$warningSecondary", + }, + success: { + backgroundColor: "$successSecondary", + }, + }, + }, + defaultVariants: { + size: "sm", + color: "primary", + }, +}); + +interface SpeakerAvatarProps { + speaker: { initials: string; color: SpeakerColor }; + size?: "sm" | "md"; +} + +function SpeakerAvatar({ speaker, size = "sm" }: SpeakerAvatarProps) { + return ( + + {speaker.initials} + + ); +} + +export default SpeakerAvatar; diff --git a/src/renderer/src/components/switch/index.tsx b/src/renderer/src/components/switch/index.tsx new file mode 100644 index 00000000..2e9243ad --- /dev/null +++ b/src/renderer/src/components/switch/index.tsx @@ -0,0 +1,92 @@ +import { styled } from "@/styles/stitches.config"; + +const Pill = styled("div", { + position: "relative", + width: 32, + height: 19, + borderRadius: 100, + flexShrink: 0, + transition: "background-color $transitions$s", + cursor: "pointer", + + variants: { + checked: { + true: { + backgroundColor: "$secondary", + }, + false: { + backgroundColor: "$bgSecondaryAlt", + }, + }, + }, + defaultVariants: { + checked: false, + }, +}); + +const Thumb = styled("div", { + position: "absolute", + top: "50%", + transform: "translateY(-50%)", + width: 12, + height: 12, + borderRadius: "50%", + backgroundColor: "$white", + transition: "left $transitions$s", + + variants: { + checked: { + true: { + left: "calc(100% - 14px)", + }, + false: { + left: 3, + }, + }, + }, + defaultVariants: { + checked: false, + }, +}); + +const SwitchLabel = styled("label", { + fontFamily: "$primary", + fontWeight: "$default", + fontSize: "$paragraphsSm", + lineHeight: "$paragraphsSm", + color: "$textDefault", + cursor: "pointer", + userSelect: "none", +}); + +const SwitchRoot = styled("div", { + display: "flex", + flexDirection: "row", + alignItems: "center", + gap: 8, + cursor: "pointer", +}); + +interface SwitchProps { + checked: boolean; + onCheckedChange: (checked: boolean) => void; + label?: string; + id?: string; +} + +function Switch({ checked, onCheckedChange, label, id }: SwitchProps) { + const handleToggle = () => { + onCheckedChange(!checked); + }; + + return ( + + + + + {label && {label}} + + ); +} + +export default Switch; From a235a22bdd0733ad08359e42e6ed0b51d9188528 Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 17 Apr 2026 14:42:53 -0300 Subject: [PATCH 105/263] feat(voice-to-text): redesign features page and extend FeatureRouter Replace vertical button list on /login/features with a 3-column FeatureCard grid (Set de Datos, Anonimizador, Voz a Texto active; Resumen doc, PDF a Word disabled). Extend FeatureRouter to accept VOICE_TO_TEXT and update all six call sites (onboarding, preview, process, validation, finish, main layout). Co-Authored-By: Claude Sonnet 4.6 --- src/renderer/src/features/FeatureRouter.tsx | 3 +- src/renderer/src/layout/main/index.tsx | 1 + src/renderer/src/pages/finish/index.tsx | 1 + src/renderer/src/pages/login/Features.tsx | 86 ++++++++++++++------- src/renderer/src/pages/onboarding/index.tsx | 1 + src/renderer/src/pages/preview/index.tsx | 1 + src/renderer/src/pages/process/index.tsx | 1 + src/renderer/src/pages/validation/index.tsx | 1 + 8 files changed, 64 insertions(+), 31 deletions(-) diff --git a/src/renderer/src/features/FeatureRouter.tsx b/src/renderer/src/features/FeatureRouter.tsx index b0807e58..2d813ca6 100644 --- a/src/renderer/src/features/FeatureRouter.tsx +++ b/src/renderer/src/features/FeatureRouter.tsx @@ -4,6 +4,7 @@ import { useParams } from "react-router-dom"; interface ComponentsProps { [Feature.Dataset]: JSX.Element; [Feature.Anonymizer]: JSX.Element; + [Feature.VoiceToText]: JSX.Element | null; } export default function FeatureRouter( @@ -12,5 +13,5 @@ export default function FeatureRouter( const { feature } = useParams<{ feature: Feature }>(); if (!feature) return null; - return components[feature]; + return components[feature] ?? null; } diff --git a/src/renderer/src/layout/main/index.tsx b/src/renderer/src/layout/main/index.tsx index 44705e68..86b69686 100644 --- a/src/renderer/src/layout/main/index.tsx +++ b/src/renderer/src/layout/main/index.tsx @@ -36,6 +36,7 @@ export default function Main() { } ANONYMIZER={} + VOICE_TO_TEXT={} /> ); } diff --git a/src/renderer/src/pages/finish/index.tsx b/src/renderer/src/pages/finish/index.tsx index 5c4ba951..395bfcc0 100644 --- a/src/renderer/src/pages/finish/index.tsx +++ b/src/renderer/src/pages/finish/index.tsx @@ -8,6 +8,7 @@ export default function Finish() { } ANONYMIZER={} + VOICE_TO_TEXT={null} /> ); } diff --git a/src/renderer/src/pages/login/Features.tsx b/src/renderer/src/pages/login/Features.tsx index d406498b..02cc2c5e 100644 --- a/src/renderer/src/pages/login/Features.tsx +++ b/src/renderer/src/pages/login/Features.tsx @@ -1,44 +1,70 @@ -import { Button, Stack, Subtitle } from "@/components"; +import { FeatureCard, Subtitle } from "@/components"; +import { styled } from "@/styles/stitches.config"; import { Feature } from "@/types/features"; -import { ArrowBendUpLeft, Database, Detective } from "phosphor-react"; +import { Database, Detective, FileAudio, FileDoc, TextAlignLeft } from "phosphor-react"; import { useNavigate } from "react-router-dom"; +const PageWrapper = styled("div", { + display: "flex", + flexDirection: "column", + alignItems: "center", + gap: "$l", +}); + +const CardGrid = styled("div", { + display: "grid", + gridTemplateColumns: "repeat(3, 320px)", + gap: "$l", +}); + export function Features() { const navigate = useNavigate(); - const handleBack = () => { - navigate("/login"); - }; - const handleSelectFeature = (feature: Feature) => () => { navigate(`/app/${feature}/onboarding`); }; return ( - - - ¿Cual función vas a utilizar? - - - - o + + + ¡Hola! Selecciona la herramienta a utilizar - - - + + + } + title="Set de Datos" + description="Convierte documentos en una base de datos estructurada" + onClick={handleSelectFeature(Feature.Dataset)} + /> + } + title="Anonimizador" + description="Anonimiza resoluciones judiciales de manera automática y editable" + onClick={handleSelectFeature(Feature.Anonymizer)} + /> + } + title="Voz a Texto" + description="Transcribe audios a documento de texto editables" + onClick={handleSelectFeature(Feature.VoiceToText)} + /> + } + title="Resumen de documento" + description="Resumen automático de documentos" + disabled={true} + /> + } + title="PDF a Word" + description="Transforma archivos .pdf a .docx" + disabled={true} + /> + + ); } diff --git a/src/renderer/src/pages/onboarding/index.tsx b/src/renderer/src/pages/onboarding/index.tsx index b327c24f..46ea8112 100644 --- a/src/renderer/src/pages/onboarding/index.tsx +++ b/src/renderer/src/pages/onboarding/index.tsx @@ -105,6 +105,7 @@ export default function Onboarding() { supportMultipleFiles={true} /> } + VOICE_TO_TEXT={null} /> ); } diff --git a/src/renderer/src/pages/preview/index.tsx b/src/renderer/src/pages/preview/index.tsx index 20c32849..32aa9a15 100644 --- a/src/renderer/src/pages/preview/index.tsx +++ b/src/renderer/src/pages/preview/index.tsx @@ -125,6 +125,7 @@ export default function Preview() { title="1. Previsualización del archivo" /> } + VOICE_TO_TEXT={null} /> ); } diff --git a/src/renderer/src/pages/process/index.tsx b/src/renderer/src/pages/process/index.tsx index 5369e2aa..98525cbf 100644 --- a/src/renderer/src/pages/process/index.tsx +++ b/src/renderer/src/pages/process/index.tsx @@ -111,6 +111,7 @@ export default function Process() { supportMultipleFiles={false} /> } + VOICE_TO_TEXT={null} /> ); } diff --git a/src/renderer/src/pages/validation/index.tsx b/src/renderer/src/pages/validation/index.tsx index 8acf2995..761fcf80 100644 --- a/src/renderer/src/pages/validation/index.tsx +++ b/src/renderer/src/pages/validation/index.tsx @@ -7,6 +7,7 @@ export default function Validation() { } ANONYMIZER={} + VOICE_TO_TEXT={null} /> ); } From 114178f076530078c9a0fcc18d233cb7016a0bb5 Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 17 Apr 2026 14:46:46 -0300 Subject: [PATCH 106/263] feat(voice-to-text): add onboarding, preview, and process pages Create the three wizard pages for Voz a Texto: VoiceOnboarding (4-step explanation + audio file picker), VoicePreview (audio file list with per-file removal), and VoiceProcess (useTranscribe hook + overall progress bar + toast on completion). Wire all three into FeatureRouter. Co-Authored-By: Claude Sonnet 4.6 --- src/renderer/src/pages/onboarding/index.tsx | 3 +- .../src/pages/onboarding/voice/index.tsx | 71 ++++++++++ src/renderer/src/pages/preview/index.tsx | 3 +- .../src/pages/preview/voice/index.tsx | 121 ++++++++++++++++++ src/renderer/src/pages/process/index.tsx | 3 +- .../src/pages/process/voice/index.tsx | 111 ++++++++++++++++ 6 files changed, 309 insertions(+), 3 deletions(-) create mode 100644 src/renderer/src/pages/onboarding/voice/index.tsx create mode 100644 src/renderer/src/pages/preview/voice/index.tsx create mode 100644 src/renderer/src/pages/process/voice/index.tsx diff --git a/src/renderer/src/pages/onboarding/index.tsx b/src/renderer/src/pages/onboarding/index.tsx index 46ea8112..67f7379c 100644 --- a/src/renderer/src/pages/onboarding/index.tsx +++ b/src/renderer/src/pages/onboarding/index.tsx @@ -9,6 +9,7 @@ import { addFiles } from "@/reducers/file/actions"; import FeatureRouter from "@/features/FeatureRouter"; import { Card } from "./Cards"; import { Grid } from "./grid"; +import VoiceOnboarding from "./voice"; interface GenericDatasetProps { description: string; @@ -105,7 +106,7 @@ export default function Onboarding() { supportMultipleFiles={true} /> } - VOICE_TO_TEXT={null} + VOICE_TO_TEXT={} /> ); } diff --git a/src/renderer/src/pages/onboarding/voice/index.tsx b/src/renderer/src/pages/onboarding/voice/index.tsx new file mode 100644 index 00000000..649fb0e4 --- /dev/null +++ b/src/renderer/src/pages/onboarding/voice/index.tsx @@ -0,0 +1,71 @@ +import { type ChangeEventHandler, useRef } from "react"; +import { useNavigate } from "react-router-dom"; + +import { Button, HiddenInput, Stack, Text, Title } from "@/components"; +import { useFileDispatch } from "@/hooks"; +import { Footer, Section } from "@/layout/main"; +import { addFiles } from "@/reducers/file/actions"; + +import { Card } from "../Cards"; +import { Grid } from "../grid"; + +const AUDIO_ACCEPT = ".mp3,.wav,.m4a,.webm,audio/*"; + +const STEPS: [string, string, string, string] = [ + "Subí uno o más archivos de audio (.mp3, .wav, .m4a, .webm)", + "El sistema analiza el audio e identifica quién habla en cada momento", + "Revisá la transcripción, editá el texto y renombrá a los locutores", + "Descargá la transcripción en formato de texto", +]; + +export default function VoiceOnboarding() { + const inputRef = useRef(null); + const dispatch = useFileDispatch(); + const navigate = useNavigate(); + + const handleSelectFile = () => { + inputRef.current?.click(); + }; + + const handleAddedFiles: ChangeEventHandler = (e) => { + const rawFiles = e.target.files; + + if (rawFiles) { + const files = Array.from(rawFiles); + dispatch(addFiles(files)); + navigate("../preview"); + } + }; + + return ( + <> +
+ + + Cómo funciona la Transcripción de voz a texto + + + + {STEPS.map((step, index) => ( + + ))} + +
+ +
+ + Formatos válidos: .mp3, .wav, .m4a, .webm + +
+ + ); +} diff --git a/src/renderer/src/pages/preview/index.tsx b/src/renderer/src/pages/preview/index.tsx index 32aa9a15..135cba7e 100644 --- a/src/renderer/src/pages/preview/index.tsx +++ b/src/renderer/src/pages/preview/index.tsx @@ -13,6 +13,7 @@ import { } from "@/components"; import FeatureRouter from "@/features/FeatureRouter"; import { useFileDispatch, useFiles } from "@/hooks"; +import VoicePreview from "./voice"; import { Footer, Section } from "@/layout/main"; import { addFiles, @@ -125,7 +126,7 @@ export default function Preview() { title="1. Previsualización del archivo" /> } - VOICE_TO_TEXT={null} + VOICE_TO_TEXT={} /> ); } diff --git a/src/renderer/src/pages/preview/voice/index.tsx b/src/renderer/src/pages/preview/voice/index.tsx new file mode 100644 index 00000000..7de0ac2a --- /dev/null +++ b/src/renderer/src/pages/preview/voice/index.tsx @@ -0,0 +1,121 @@ +import { type ChangeEventHandler, useRef } from "react"; +import { useNavigate } from "react-router-dom"; +import { FileAudio, Trash } from "phosphor-react"; + +import { + Button, + Card, + HiddenInput, + SectionTitle, + Stack, + Subtitle, + Text, +} from "@/components"; +import { useFileDispatch, useFiles } from "@/hooks"; +import { Footer, Section } from "@/layout/main"; +import { addFiles, removeAllFiles, removeFile } from "@/reducers/file/actions"; + +const AUDIO_ACCEPT = ".mp3,.wav,.m4a,.webm,audio/*"; + +function formatFileSize(bytes: number): string { + if (bytes >= 1024 * 1024) { + return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; + } + return `${Math.round(bytes / 1024)} KB`; +} + +export default function VoicePreview() { + const inputRef = useRef(null); + const navigate = useNavigate(); + const files = useFiles(); + const dispatch = useFileDispatch(); + + const handlePrevious = () => { + dispatch(removeAllFiles()); + navigate("../onboarding"); + }; + + const handleSelectFile = () => { + inputRef.current?.click(); + }; + + const handleAddedFiles: ChangeEventHandler = (e) => { + const rawFiles = e.target.files; + + if (rawFiles) { + const fileArray = Array.from(rawFiles); + dispatch(addFiles(fileArray)); + } + }; + + const handleRemoveFile = (fileName: string) => () => { + dispatch(removeFile(fileName)); + }; + + const handleConfirmFiles = () => { + navigate("../process"); + }; + + return ( + <> +
+ + 1. Archivos de audio + + + Archivos seleccionados + + {files.map((file) => ( + + + + + + {file.data.name} + + {formatFileSize(file.data.size)} + + + + + ))} + + +
+ +
+ + Formatos válidos: .mp3, .wav, .m4a, .webm + + +
+ + ); +} diff --git a/src/renderer/src/pages/process/index.tsx b/src/renderer/src/pages/process/index.tsx index 98525cbf..166a372f 100644 --- a/src/renderer/src/pages/process/index.tsx +++ b/src/renderer/src/pages/process/index.tsx @@ -21,6 +21,7 @@ import { } from "@/reducers/file/actions"; import FeatureRouter from "@/features/FeatureRouter"; +import VoiceProcess from "./voice"; import useNotify from "./useNotify"; import { canContinue, initProcessState, replace } from "./utils"; @@ -111,7 +112,7 @@ export default function Process() { supportMultipleFiles={false} /> } - VOICE_TO_TEXT={null} + VOICE_TO_TEXT={} /> ); } diff --git a/src/renderer/src/pages/process/voice/index.tsx b/src/renderer/src/pages/process/voice/index.tsx new file mode 100644 index 00000000..090d8577 --- /dev/null +++ b/src/renderer/src/pages/process/voice/index.tsx @@ -0,0 +1,111 @@ +import { Bell } from "phosphor-react"; +import { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; + +import { + Button, + Card, + SectionTitle, + Stack, + Subtitle, + Text, + Toast, +} from "@/components"; +import { useFiles } from "@/hooks"; +import { useTranscriptionDispatch } from "@/hooks/useTranscriptions"; +import { useTranscribe } from "@/hooks/useTranscribe"; +import { Footer, Section } from "@/layout/main"; +import { Bar, BarContainer } from "@/components/file-processing/FileProcessing.styles"; +import Label from "@/components/label"; + +export default function VoiceProcess() { + const navigate = useNavigate(); + const files = useFiles(); + const transcriptionDispatch = useTranscriptionDispatch(); + + const audioFiles = files.map((f) => f.data); + + const { progress, status } = useTranscribe(audioFiles, { + dispatch: transcriptionDispatch, + }); + + const [isToastVisible, setIsToastVisible] = useState(false); + + const isCompleted = status === "completed"; + const isError = status === "error"; + const progressPercent = Math.round(progress * 100); + + useEffect(() => { + if (isCompleted && !isToastVisible) { + setIsToastVisible(true); + } + }, [isCompleted]); + + const handlePrevious = () => { + navigate("../preview"); + }; + + const handleNext = () => { + navigate("../validation"); + }; + + const hideToast = () => setIsToastVisible(false); + + return ( + <> +
+ }> + Transcripción completada + + + 2. Transcripción de audio + + + + + AymurAI está transcribiendo los archivos de audio + + Este proceso puede tardar algunos minutos. + + + + {/* Overall progress bar */} + + + + + + + + + + + +
+ +
+ + +
+ + ); +} From d59b0ba4b04965839dae0b3656d000b5bc97c49b Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 17 Apr 2026 14:48:41 -0300 Subject: [PATCH 107/263] feat(voice-to-text): add AudioPlayer component MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Self-contained audio player bottom bar with play/pause, ±5s skip, speed cycling (0.75×/1×/1.5×/2×), seek-on-click progress bar, mm:ss time display, and an imperative ref handle. Co-Authored-By: Claude Sonnet 4.6 --- .../src/components/audio-player/formatTime.ts | 7 + .../src/components/audio-player/index.tsx | 309 ++++++++++++++++++ src/renderer/src/components/index.ts | 3 + 3 files changed, 319 insertions(+) create mode 100644 src/renderer/src/components/audio-player/formatTime.ts create mode 100644 src/renderer/src/components/audio-player/index.tsx diff --git a/src/renderer/src/components/audio-player/formatTime.ts b/src/renderer/src/components/audio-player/formatTime.ts new file mode 100644 index 00000000..ef7b17a8 --- /dev/null +++ b/src/renderer/src/components/audio-player/formatTime.ts @@ -0,0 +1,7 @@ +// Converts milliseconds to "mm:ss" +export function formatTime(ms: number): string { + const totalSeconds = Math.floor(ms / 1000); + const minutes = Math.floor(totalSeconds / 60); + const seconds = totalSeconds % 60; + return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`; +} diff --git a/src/renderer/src/components/audio-player/index.tsx b/src/renderer/src/components/audio-player/index.tsx new file mode 100644 index 00000000..356511f0 --- /dev/null +++ b/src/renderer/src/components/audio-player/index.tsx @@ -0,0 +1,309 @@ +import React, { + forwardRef, + useCallback, + useImperativeHandle, + useRef, + useState, +} from "react"; +import { + ArrowClockwise, + ArrowCounterClockwise, + Pause, + Play, +} from "phosphor-react"; + +import { styled } from "@/styles"; +import { formatTime } from "./formatTime"; + +// --------------------------------------------------------------------------- +// Styled components +// --------------------------------------------------------------------------- + +const PlayerBar = styled("div", { + display: "flex", + flexDirection: "row", + alignItems: "center", + justifyContent: "space-between", + padding: "24px 48px", + height: "96px", + backgroundColor: "#FFFFFF", + borderTop: "1px solid #BCBAB8", + boxSizing: "border-box", +}); + +const Controls = styled("div", { + display: "flex", + flexDirection: "row", + alignItems: "center", + gap: "4px", + width: "156px", + flexShrink: 0, +}); + +const IconButton = styled("button", { + display: "flex", + flexDirection: "column", + alignItems: "center", + justifyContent: "center", + padding: "8px", + width: "36px", + height: "36px", + borderRadius: "6px", + border: "none", + background: "transparent", + cursor: "pointer", + position: "relative", + + "&:hover": { + backgroundColor: "#F3F3F3", + }, +}); + +const PlayButton = styled(IconButton, { + backgroundColor: "#C5CAFF", + + "&:hover": { + backgroundColor: "#C5CAFF", + opacity: 0.85, + }, +}); + +const SkipLabel = styled("span", { + fontSize: "9px", + lineHeight: 1, + position: "absolute", + bottom: "6px", + fontWeight: 600, + color: "#110041", + userSelect: "none", +}); + +const SpeedText = styled("span", { + fontSize: "11px", + fontWeight: 600, + color: "#110041", + whiteSpace: "nowrap", + userSelect: "none", +}); + +const ProgressSection = styled("div", { + display: "flex", + flexDirection: "row", + alignItems: "center", + gap: "16px", + flex: 1, + marginLeft: "24px", + marginRight: "24px", +}); + +const ProgressBar = styled("div", { + height: "8px", + backgroundColor: "#E0DDE2", + borderRadius: "9999px", + flex: 1, + cursor: "pointer", + position: "relative", + overflow: "hidden", +}); + +const ProgressFill = styled("div", { + height: "100%", + backgroundColor: "#3F479D", + borderRadius: "9999px", + position: "absolute", + left: 0, + top: 0, +}); + +const TimeDisplay = styled("span", { + fontSize: "12px", + color: "#625C68", + whiteSpace: "nowrap", + flexShrink: 0, +}); + +// --------------------------------------------------------------------------- +// Types +// --------------------------------------------------------------------------- + +interface AudioPlayerProps { + src: string; + durationMs: number; + onTimeUpdate?: (currentMs: number) => void; + onEnded?: () => void; +} + +export interface AudioPlayerHandle { + play(): void; + pause(): void; + seekTo(ms: number): void; + setPlaybackRate(rate: number): void; +} + +// --------------------------------------------------------------------------- +// Component +// --------------------------------------------------------------------------- + +const PLAYBACK_RATES = [1, 1.5, 2, 0.75]; + +const AudioPlayer = forwardRef( + function AudioPlayer({ src, durationMs, onTimeUpdate, onEnded }, ref) { + const audioRef = useRef(null); + const barRef = useRef(null); + + const [isPlaying, setIsPlaying] = useState(false); + const [currentMs, setCurrentMs] = useState(0); + const [rateIndex, setRateIndex] = useState(0); + + // Expose imperative handle + useImperativeHandle(ref, () => ({ + play() { + audioRef.current?.play(); + }, + pause() { + audioRef.current?.pause(); + }, + seekTo(ms: number) { + if (audioRef.current) { + audioRef.current.currentTime = ms / 1000; + } + }, + setPlaybackRate(rate: number) { + if (audioRef.current) { + audioRef.current.playbackRate = rate; + } + }, + })); + + // Internal handlers + const handleTimeUpdate = useCallback(() => { + if (!audioRef.current) return; + const ms = audioRef.current.currentTime * 1000; + setCurrentMs(ms); + onTimeUpdate?.(ms); + }, [onTimeUpdate]); + + const handleEnded = useCallback(() => { + setIsPlaying(false); + onEnded?.(); + }, [onEnded]); + + const togglePlay = useCallback(() => { + if (!audioRef.current) return; + if (audioRef.current.paused) { + audioRef.current.play(); + setIsPlaying(true); + } else { + audioRef.current.pause(); + setIsPlaying(false); + } + }, []); + + const rewind5s = useCallback(() => { + if (!audioRef.current) return; + audioRef.current.currentTime = Math.max( + 0, + audioRef.current.currentTime - 5, + ); + }, []); + + const forward5s = useCallback(() => { + if (!audioRef.current) return; + const duration = audioRef.current.duration || 0; + audioRef.current.currentTime = Math.min( + duration, + audioRef.current.currentTime + 5, + ); + }, []); + + const cycleSpeed = useCallback(() => { + setRateIndex((prev) => { + const nextIndex = (prev + 1) % PLAYBACK_RATES.length; + if (audioRef.current) { + audioRef.current.playbackRate = PLAYBACK_RATES[nextIndex]; + } + return nextIndex; + }); + }, []); + + const handleBarClick = useCallback( + (e: React.MouseEvent) => { + if (!barRef.current) return; + const rect = barRef.current.getBoundingClientRect(); + const clickX = e.clientX - rect.left; + const ratio = Math.max(0, Math.min(1, clickX / rect.width)); + const seekMs = ratio * durationMs; + if (audioRef.current) { + audioRef.current.currentTime = seekMs / 1000; + } + setCurrentMs(seekMs); + onTimeUpdate?.(seekMs); + }, + [durationMs, onTimeUpdate], + ); + + const fillPercent = + durationMs > 0 ? (currentMs / durationMs) * 100 : 0; + + return ( + + + ); + }, +); + +export default AudioPlayer; diff --git a/src/renderer/src/components/index.ts b/src/renderer/src/components/index.ts index 8f4b6a34..e6bb4d78 100644 --- a/src/renderer/src/components/index.ts +++ b/src/renderer/src/components/index.ts @@ -1,4 +1,5 @@ import Arrow from "./arrow"; +import AudioPlayer from "./audio-player"; import Button from "./button"; import Card from "./card"; import FeatureCard from "./feature-card"; @@ -32,8 +33,10 @@ import Toast from "./toast"; import Tooltip from "./tooltip"; import ValidationForm from "./validation-form"; +export type { AudioPlayerHandle } from "./audio-player"; export { Arrow, + AudioPlayer, Button, Card, FeatureCard, From 54f4b75dc3beaa874fccf3909c639586c4b7799d Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 17 Apr 2026 14:50:49 -0300 Subject: [PATCH 108/263] feat(voice-to-text): add TranscriptionEditor base with audio sync Implements the read-only TranscriptionEditor component with turn highlighting synced to the AudioPlayer's playback position via useActiveTurn hook. Co-Authored-By: Claude Sonnet 4.6 --- src/renderer/src/components/index.ts | 2 + .../transcription-editor/TurnBlock.tsx | 117 +++++++++++++ .../transcription-editor/formatMs.ts | 2 + .../components/transcription-editor/index.tsx | 155 ++++++++++++++++++ .../transcription-editor/useActiveTurn.ts | 21 +++ 5 files changed, 297 insertions(+) create mode 100644 src/renderer/src/components/transcription-editor/TurnBlock.tsx create mode 100644 src/renderer/src/components/transcription-editor/formatMs.ts create mode 100644 src/renderer/src/components/transcription-editor/index.tsx create mode 100644 src/renderer/src/components/transcription-editor/useActiveTurn.ts diff --git a/src/renderer/src/components/index.ts b/src/renderer/src/components/index.ts index e6bb4d78..f301bc62 100644 --- a/src/renderer/src/components/index.ts +++ b/src/renderer/src/components/index.ts @@ -1,5 +1,6 @@ import Arrow from "./arrow"; import AudioPlayer from "./audio-player"; +import TranscriptionEditor from "./transcription-editor"; import Button from "./button"; import Card from "./card"; import FeatureCard from "./feature-card"; @@ -37,6 +38,7 @@ export type { AudioPlayerHandle } from "./audio-player"; export { Arrow, AudioPlayer, + TranscriptionEditor, Button, Card, FeatureCard, diff --git a/src/renderer/src/components/transcription-editor/TurnBlock.tsx b/src/renderer/src/components/transcription-editor/TurnBlock.tsx new file mode 100644 index 00000000..7d26f8cd --- /dev/null +++ b/src/renderer/src/components/transcription-editor/TurnBlock.tsx @@ -0,0 +1,117 @@ +import { styled } from "@/styles/stitches.config"; +import SpeakerAvatar from "@/components/speaker-avatar"; +import type { Speaker, Turn } from "@/types/transcription"; +import { formatMs } from "./formatMs"; + +// --------------------------------------------------------------------------- +// Styled components +// --------------------------------------------------------------------------- + +const TurnWrap = styled("div", { + display: "flex", + flexDirection: "column", + width: "100%", + paddingLeft: "32px", + paddingRight: "32px", + boxSizing: "border-box", + transition: "border-left 150ms ease, background-color 150ms ease", + + variants: { + active: { + true: { + borderLeft: "4px solid #3F479D", + backgroundColor: "rgba(197, 202, 255, 0.15)", + paddingLeft: "28px", // compensate for the 4px border + }, + false: { + borderLeft: "4px solid transparent", + }, + }, + }, + defaultVariants: { + active: false, + }, +}); + +const TurnHeader = styled("div", { + display: "flex", + flexDirection: "row", + alignItems: "center", + gap: "8px", + cursor: "pointer", + marginBottom: "8px", + + "&:hover": { + opacity: 0.8, + }, +}); + +const SpeakerLabel = styled("span", { + fontFamily: "$primary", + fontWeight: "$strong", + fontSize: "16px", + lineHeight: "20px", + color: "#625C68", + flexShrink: 0, +}); + +const Timestamp = styled("span", { + fontFamily: "$primary", + fontWeight: "$default", + fontSize: "16px", + lineHeight: "20px", + color: "#625C68", +}); + +const TurnText = styled("p", { + fontFamily: "$primary", + fontWeight: 300, + fontSize: "16px", + lineHeight: "26px", + color: "#110041", + margin: 0, + padding: 0, +}); + +// --------------------------------------------------------------------------- +// Props & Component +// --------------------------------------------------------------------------- + +interface TurnBlockProps { + turn: Turn; + speaker: Speaker; + isActive: boolean; + isEditMode: boolean; + onSeekTo: (ms: number) => void; +} + +function TurnBlock({ + turn, + speaker, + isActive, + onSeekTo, +}: TurnBlockProps) { + const handleHeaderClick = () => { + onSeekTo(turn.startMs); + }; + + return ( + + { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + handleHeaderClick(); + } + }} + > + + {speaker.label} + {formatMs(turn.startMs)} + + {turn.text} + + ); +} + +export default TurnBlock; diff --git a/src/renderer/src/components/transcription-editor/formatMs.ts b/src/renderer/src/components/transcription-editor/formatMs.ts new file mode 100644 index 00000000..9a9ef3ee --- /dev/null +++ b/src/renderer/src/components/transcription-editor/formatMs.ts @@ -0,0 +1,2 @@ +// Formats milliseconds to "mm:ss" for display in turn headers +export { formatTime as formatMs } from "@/components/audio-player/formatTime"; diff --git a/src/renderer/src/components/transcription-editor/index.tsx b/src/renderer/src/components/transcription-editor/index.tsx new file mode 100644 index 00000000..13f6782e --- /dev/null +++ b/src/renderer/src/components/transcription-editor/index.tsx @@ -0,0 +1,155 @@ +import { useMemo, useRef, useState } from "react"; + +import AudioPlayer, { AudioPlayerHandle } from "@/components/audio-player"; +import Switch from "@/components/switch"; +import { styled } from "@/styles/stitches.config"; +import type { Transcription } from "@/types/transcription"; +import TurnBlock from "./TurnBlock"; +import { useActiveTurn } from "./useActiveTurn"; + +// --------------------------------------------------------------------------- +// Styled components +// --------------------------------------------------------------------------- + +const EditorWrap = styled("div", { + display: "flex", + flexDirection: "column", + height: "100%", + overflow: "hidden", +}); + +const EditorHeader = styled("div", { + backgroundColor: "#FFFFFF", + borderBottom: "1px solid #BCBAB8", + padding: "42px 48px 24px", + flexShrink: 0, +}); + +const Title = styled("h1", { + fontFamily: "$primary", + fontWeight: "$strong", + fontSize: "32px", + lineHeight: "38px", + color: "#110041", + margin: 0, + padding: 0, +}); + +const ToolBar = styled("div", { + display: "flex", + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + marginTop: "16px", +}); + +const SearchInput = styled("input", { + width: "711px", + maxWidth: "100%", + border: "1px solid #BCBAB8", + borderRadius: "24px", + padding: "12px 20px", + fontFamily: "$primary", + fontSize: "16px", + lineHeight: "22px", + color: "$textDefault", + backgroundColor: "#FFFFFF", + outline: "none", + boxSizing: "border-box", + + "&::placeholder": { + color: "#9F99A5", + }, + + "&:focus": { + borderColor: "#3F479D", + }, +}); + +const EditorBody = styled("div", { + flex: 1, + overflowY: "auto", + padding: "50px", + display: "flex", + flexDirection: "column", + gap: "24px", + backgroundColor: "#F6F5F7", +}); + +// --------------------------------------------------------------------------- +// Props & Component +// --------------------------------------------------------------------------- + +interface TranscriptionEditorProps { + transcription: Transcription; + isEditMode: boolean; + onEditModeChange: (val: boolean) => void; +} + +function TranscriptionEditor({ + transcription, + isEditMode, + onEditModeChange, +}: TranscriptionEditorProps) { + const [currentMs, setCurrentMs] = useState(0); + const playerRef = useRef(null); + + const speakerMap = useMemo( + () => + Object.fromEntries(transcription.speakers.map((s) => [s.id, s])), + [transcription.speakers], + ); + + const activeTurnId = useActiveTurn(transcription.turns, currentMs); + + const handleSeekTo = (ms: number) => { + playerRef.current?.seekTo(ms); + }; + + return ( + + + {transcription.title} + + + + + + + + {transcription.turns.map((turn) => { + const speaker = speakerMap[turn.speakerId]; + if (!speaker) return null; + + return ( + + ); + })} + + + setCurrentMs(ms)} + /> + + ); +} + +export default TranscriptionEditor; diff --git a/src/renderer/src/components/transcription-editor/useActiveTurn.ts b/src/renderer/src/components/transcription-editor/useActiveTurn.ts new file mode 100644 index 00000000..ffd2f565 --- /dev/null +++ b/src/renderer/src/components/transcription-editor/useActiveTurn.ts @@ -0,0 +1,21 @@ +import { useMemo } from "react"; + +import type { Turn } from "@/types/transcription"; + +/** + * Returns the id of the turn currently playing + * (whose [startMs, endMs] contains currentMs), or null if none. + */ +export function useActiveTurn( + turns: Turn[], + currentMs: number, +): string | null { + return useMemo(() => { + for (const turn of turns) { + if (currentMs >= turn.startMs && currentMs < turn.endMs) { + return turn.id; + } + } + return null; + }, [turns, currentMs]); +} From e10e7cedec8c19050ba714d3f4609acb4c0eac89 Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 17 Apr 2026 14:54:42 -0300 Subject: [PATCH 109/263] feat(voice-to-text): add edit mode, speaker dialog, suggested speakers, and search to TranscriptionEditor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TurnBlock: inline textarea editing with auto-resize, trash button for turn removal, speaker header click opens SpeakerDialog (edit mode only), turn selection highlighting, search query text highlighting with elements - SpeakerDialog: two-section modal — rename speaker globally across all turns, or reassign the current turn to an existing or newly created speaker - AddTurnButton: dashed button rendered between/after turns in edit mode to insert new turns - SuggestedSpeakersPanel: 289px sidebar panel visible in edit mode showing SUGGESTED_SPEAKERS; clicking a row dispatches assignSuggestedSpeakerToTurn for the selected turn - index.tsx: functional search with case-insensitive match counting, prev/next navigation with CaretLeft/CaretRight icons and N/M counter, smooth scroll-into-view per match; edit mode wires selectedTurnId state and shows SuggestedSpeakersPanel in a flex row layout Co-Authored-By: Claude Sonnet 4.6 --- .../transcription-editor/AddTurnButton.tsx | 65 ++++ .../transcription-editor/SpeakerDialog.tsx | 277 ++++++++++++++++++ .../SuggestedSpeakersPanel.tsx | 123 ++++++++ .../transcription-editor/TurnBlock.tsx | 237 +++++++++++++-- .../components/transcription-editor/index.tsx | 269 ++++++++++++++--- 5 files changed, 918 insertions(+), 53 deletions(-) create mode 100644 src/renderer/src/components/transcription-editor/AddTurnButton.tsx create mode 100644 src/renderer/src/components/transcription-editor/SpeakerDialog.tsx create mode 100644 src/renderer/src/components/transcription-editor/SuggestedSpeakersPanel.tsx diff --git a/src/renderer/src/components/transcription-editor/AddTurnButton.tsx b/src/renderer/src/components/transcription-editor/AddTurnButton.tsx new file mode 100644 index 00000000..4040f714 --- /dev/null +++ b/src/renderer/src/components/transcription-editor/AddTurnButton.tsx @@ -0,0 +1,65 @@ +import { styled } from "@/styles/stitches.config"; +import type { Turn } from "@/types/transcription"; +import { useTranscriptionDispatch } from "@/hooks/useTranscriptions"; +import { insertTurn } from "@/reducers/transcription/actions"; + +// --------------------------------------------------------------------------- +// Styled components +// --------------------------------------------------------------------------- + +const AddButton = styled("button", { + display: "flex", + alignItems: "center", + justifyContent: "center", + width: "100%", + padding: "8px 16px", + border: "1.5px dashed #BCBAB8", + borderRadius: "8px", + backgroundColor: "transparent", + cursor: "pointer", + color: "#9F99A5", + fontFamily: "$primary", + fontWeight: "$default", + fontSize: "13px", + lineHeight: "18px", + transition: "border-color 150ms ease, color 150ms ease", + boxSizing: "border-box", + + "&:hover": { + borderColor: "#3F479D", + color: "#3F479D", + backgroundColor: "rgba(63, 71, 157, 0.04)", + }, +}); + +// --------------------------------------------------------------------------- +// Props & Component +// --------------------------------------------------------------------------- + +interface AddTurnButtonProps { + transcriptionId: string; + afterTurn: Turn; +} + +function AddTurnButton({ transcriptionId, afterTurn }: AddTurnButtonProps) { + const dispatch = useTranscriptionDispatch(); + + const handleClick = () => { + const newTurn: Turn = { + id: crypto.randomUUID(), + speakerId: afterTurn.speakerId, + text: "", + startMs: afterTurn.endMs, + endMs: afterTurn.endMs, + }; + dispatch(insertTurn(transcriptionId, afterTurn.id, newTurn)); + }; + + return ( + + + Agregar turno + + ); +} + +export default AddTurnButton; diff --git a/src/renderer/src/components/transcription-editor/SpeakerDialog.tsx b/src/renderer/src/components/transcription-editor/SpeakerDialog.tsx new file mode 100644 index 00000000..606e386a --- /dev/null +++ b/src/renderer/src/components/transcription-editor/SpeakerDialog.tsx @@ -0,0 +1,277 @@ +import { useState } from "react"; + +import Dialog from "@/components/dialog"; +import Button from "@/components/button"; +import SpeakerAvatar from "@/components/speaker-avatar"; +import { styled } from "@/styles/stitches.config"; +import type { Speaker, SpeakerColor, Transcription, Turn } from "@/types/transcription"; +import { useTranscriptionDispatch } from "@/hooks/useTranscriptions"; +import { + addSpeaker, + reassignTurnSpeaker, + renameSpeakerGlobal, +} from "@/reducers/transcription/actions"; + +// --------------------------------------------------------------------------- +// Styled components +// --------------------------------------------------------------------------- + +const Section = styled("div", { + marginBottom: "24px", +}); + +const SectionTitle = styled("h4", { + fontFamily: "$primary", + fontWeight: 600, + fontSize: "14px", + lineHeight: "18px", + color: "#625C68", + margin: "0 0 8px 0", + textTransform: "uppercase", + letterSpacing: "0.05em", +}); + +const HelperText = styled("p", { + fontFamily: "$primary", + fontWeight: "$default", + fontSize: "12px", + lineHeight: "16px", + color: "#9F99A5", + margin: "6px 0 0 0", +}); + +const RenameRow = styled("div", { + display: "flex", + flexDirection: "row", + gap: "8px", + alignItems: "center", +}); + +const RenameInput = styled("input", { + flex: 1, + border: "1px solid #BCBAB8", + borderRadius: "8px", + padding: "10px 14px", + fontFamily: "$primary", + fontSize: "14px", + lineHeight: "20px", + color: "#110041", + outline: "none", + boxSizing: "border-box", + + "&:focus": { + borderColor: "#3F479D", + }, +}); + +const SpeakerList = styled("ul", { + listStyle: "none", + margin: 0, + padding: 0, + display: "flex", + flexDirection: "column", + gap: "4px", + maxHeight: "240px", + overflowY: "auto", +}); + +const SpeakerItem = styled("li", { + display: "flex", + flexDirection: "row", + alignItems: "center", + gap: "10px", + padding: "8px 12px", + borderRadius: "8px", + cursor: "pointer", + border: "2px solid transparent", + + "&:hover": { + backgroundColor: "rgba(63, 71, 157, 0.06)", + }, + + variants: { + selected: { + true: { + border: "2px solid #3F479D", + backgroundColor: "rgba(63, 71, 157, 0.06)", + }, + }, + }, +}); + +const SpeakerItemLabel = styled("span", { + fontFamily: "$primary", + fontWeight: "$default", + fontSize: "14px", + lineHeight: "20px", + color: "#110041", +}); + +const NewSpeakerRow = styled("div", { + display: "flex", + flexDirection: "row", + gap: "8px", + alignItems: "center", + marginTop: "8px", +}); + +const Divider = styled("div", { + height: "1px", + backgroundColor: "#BCBAB8", + margin: "16px 0", +}); + +// --------------------------------------------------------------------------- +// Color cycling for new speakers +// --------------------------------------------------------------------------- + +const SPEAKER_COLORS: SpeakerColor[] = ["primary", "secondary", "warning", "success"]; + +function pickColor(existingColors: SpeakerColor[]): SpeakerColor { + for (const color of SPEAKER_COLORS) { + if (!existingColors.includes(color)) return color; + } + return SPEAKER_COLORS[existingColors.length % SPEAKER_COLORS.length]; +} + +function getInitials(label: string): string { + const parts = label.trim().split(/\s+/); + if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase(); + return label.slice(0, 2).toUpperCase(); +} + +// --------------------------------------------------------------------------- +// Props & Component +// --------------------------------------------------------------------------- + +interface SpeakerDialogProps { + open: boolean; + onClose: () => void; + transcription: Transcription; + turn: Turn; + speaker: Speaker; +} + +function SpeakerDialog({ open, onClose, transcription, turn, speaker }: SpeakerDialogProps) { + const dispatch = useTranscriptionDispatch(); + const [renameValue, setRenameValue] = useState(speaker.label); + const [selectedSpeakerId, setSelectedSpeakerId] = useState(turn.speakerId); + const [showNewSpeaker, setShowNewSpeaker] = useState(false); + const [newSpeakerName, setNewSpeakerName] = useState(""); + + const handleRename = () => { + const trimmed = renameValue.trim(); + if (!trimmed) return; + dispatch(renameSpeakerGlobal(transcription.id, speaker.id, trimmed)); + onClose(); + }; + + const handleSelectSpeaker = (speakerId: string) => { + setSelectedSpeakerId(speakerId); + setShowNewSpeaker(false); + dispatch(reassignTurnSpeaker(transcription.id, turn.id, speakerId)); + onClose(); + }; + + const handleNewSpeakerConfirm = () => { + const trimmed = newSpeakerName.trim(); + if (!trimmed) return; + const existingColors = transcription.speakers.map((s) => s.color); + const color = pickColor(existingColors); + const newSpeaker: Speaker = { + id: crypto.randomUUID(), + label: trimmed, + initials: getInitials(trimmed), + color, + }; + dispatch(addSpeaker(transcription.id, newSpeaker)); + dispatch(reassignTurnSpeaker(transcription.id, turn.id, newSpeaker.id)); + onClose(); + }; + + return ( + + {/* Section A: Rename globally */} +
+ Renombrar globalmente + + setRenameValue(e.target.value)} + onKeyDown={(e) => { if (e.key === "Enter") handleRename(); }} + aria-label="Nuevo nombre del locutor" + /> + + + Cambia el nombre en todos los turnos +
+ + + + {/* Section B: Change this turn */} +
+ Cambiar este turno + + {transcription.speakers.map((s) => ( + handleSelectSpeaker(s.id)} + role="button" + tabIndex={0} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + handleSelectSpeaker(s.id); + } + }} + > + + {s.label} + + ))} + + {/* New speaker option */} + setShowNewSpeaker(true)} + role="button" + tabIndex={0} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + setShowNewSpeaker(true); + } + }} + > + + Nuevo locutor + + + + {showNewSpeaker && ( + + setNewSpeakerName(e.target.value)} + onKeyDown={(e) => { if (e.key === "Enter") handleNewSpeakerConfirm(); }} + autoFocus + aria-label="Nombre del nuevo locutor" + /> + + + )} +
+
+ ); +} + +export default SpeakerDialog; diff --git a/src/renderer/src/components/transcription-editor/SuggestedSpeakersPanel.tsx b/src/renderer/src/components/transcription-editor/SuggestedSpeakersPanel.tsx new file mode 100644 index 00000000..22296d98 --- /dev/null +++ b/src/renderer/src/components/transcription-editor/SuggestedSpeakersPanel.tsx @@ -0,0 +1,123 @@ +import { styled } from "@/styles/stitches.config"; +import SpeakerAvatar from "@/components/speaker-avatar"; +import type { Transcription } from "@/types/transcription"; +import type { SuggestedSpeaker } from "@/types/transcription"; +import { useTranscriptionDispatch } from "@/hooks/useTranscriptions"; +import { assignSuggestedSpeakerToTurn } from "@/reducers/transcription/actions"; +import { SUGGESTED_SPEAKERS } from "@/services/aymurai/fixtures/suggestedSpeakers"; + +// --------------------------------------------------------------------------- +// Styled components +// --------------------------------------------------------------------------- + +const PanelWrap = styled("div", { + width: "289px", + flexShrink: 0, + borderLeft: "1px solid #BCBAB8", + padding: "24px", + backgroundColor: "#FFFFFF", + overflowY: "auto", + boxSizing: "border-box", +}); + +const PanelTitle = styled("h3", { + fontFamily: "$primary", + fontWeight: "$default", + fontSize: "14px", + lineHeight: "18px", + color: "#110041", + margin: "0 0 16px 0", +}); + +const SpeakerRow = styled("div", { + display: "flex", + flexDirection: "row", + alignItems: "center", + gap: "10px", + padding: "10px 12px", + borderRadius: "8px", + cursor: "pointer", + + "&:hover": { + backgroundColor: "rgba(63, 71, 157, 0.06)", + }, + + variants: { + disabled: { + true: { + cursor: "default", + opacity: 0.4, + "&:hover": { + backgroundColor: "transparent", + }, + }, + }, + }, +}); + +const SpeakerName = styled("span", { + fontFamily: "$primary", + fontWeight: "$default", + fontSize: "14px", + lineHeight: "20px", + color: "#110041", +}); + +const EmptyHint = styled("p", { + fontFamily: "$primary", + fontWeight: "$default", + fontSize: "13px", + lineHeight: "18px", + color: "#9F99A5", + fontStyle: "italic", + margin: 0, +}); + +// --------------------------------------------------------------------------- +// Props & Component +// --------------------------------------------------------------------------- + +interface SuggestedSpeakersPanelProps { + transcription: Transcription; + selectedTurnId: string | null; +} + +function SuggestedSpeakersPanel({ transcription, selectedTurnId }: SuggestedSpeakersPanelProps) { + const dispatch = useTranscriptionDispatch(); + + const handleAssign = (suggested: SuggestedSpeaker) => { + if (!selectedTurnId) return; + dispatch(assignSuggestedSpeakerToTurn(transcription.id, selectedTurnId, suggested)); + }; + + return ( + + Speakers sugeridos + + {!selectedTurnId && ( + Seleccioná un turno para asignar un speaker sugerido. + )} + + {SUGGESTED_SPEAKERS.map((suggested) => ( + handleAssign(suggested)} + role="button" + tabIndex={selectedTurnId ? 0 : -1} + onKeyDown={(e) => { + if ((e.key === "Enter" || e.key === " ") && selectedTurnId) { + e.preventDefault(); + handleAssign(suggested); + } + }} + > + + {suggested.label} + + ))} + + ); +} + +export default SuggestedSpeakersPanel; diff --git a/src/renderer/src/components/transcription-editor/TurnBlock.tsx b/src/renderer/src/components/transcription-editor/TurnBlock.tsx index 7d26f8cd..b930119f 100644 --- a/src/renderer/src/components/transcription-editor/TurnBlock.tsx +++ b/src/renderer/src/components/transcription-editor/TurnBlock.tsx @@ -1,7 +1,13 @@ +import { useRef, useState } from "react"; + +import { Trash } from "phosphor-react"; import { styled } from "@/styles/stitches.config"; import SpeakerAvatar from "@/components/speaker-avatar"; -import type { Speaker, Turn } from "@/types/transcription"; +import type { Speaker, Transcription, Turn } from "@/types/transcription"; +import { useTranscriptionDispatch } from "@/hooks/useTranscriptions"; +import { removeTurn, updateTurnText } from "@/reducers/transcription/actions"; import { formatMs } from "./formatMs"; +import SpeakerDialog from "./SpeakerDialog"; // --------------------------------------------------------------------------- // Styled components @@ -14,7 +20,8 @@ const TurnWrap = styled("div", { paddingLeft: "32px", paddingRight: "32px", boxSizing: "border-box", - transition: "border-left 150ms ease, background-color 150ms ease", + transition: "border-left 150ms ease, background-color 150ms ease, outline 150ms ease", + position: "relative", variants: { active: { @@ -27,9 +34,17 @@ const TurnWrap = styled("div", { borderLeft: "4px solid transparent", }, }, + selected: { + true: { + outline: "2px solid #3F479D", + outlineOffset: "2px", + borderRadius: "4px", + }, + }, }, defaultVariants: { active: false, + selected: false, }, }); @@ -38,11 +53,23 @@ const TurnHeader = styled("div", { flexDirection: "row", alignItems: "center", gap: "8px", - cursor: "pointer", marginBottom: "8px", - "&:hover": { - opacity: 0.8, + variants: { + clickable: { + true: { + cursor: "pointer", + "&:hover": { + opacity: 0.8, + }, + }, + false: { + cursor: "pointer", + "&:hover": { + opacity: 0.8, + }, + }, + }, }, }); @@ -73,6 +100,79 @@ const TurnText = styled("p", { padding: 0, }); +const TurnTextarea = styled("textarea", { + fontFamily: "$primary", + fontWeight: 300, + fontSize: "16px", + lineHeight: "26px", + color: "#110041", + margin: 0, + padding: 0, + border: "1px solid transparent", + outline: "none", + resize: "none", + width: "100%", + backgroundColor: "transparent", + boxSizing: "border-box", + overflow: "hidden", + + "&:focus": { + border: "1px solid #BCBAB8", + borderRadius: "4px", + padding: "2px 4px", + backgroundColor: "#FFFFFF", + }, +}); + +const TrashButton = styled("button", { + position: "absolute", + top: "8px", + right: "8px", + display: "flex", + alignItems: "center", + justifyContent: "center", + width: "28px", + height: "28px", + border: "none", + borderRadius: "6px", + backgroundColor: "transparent", + cursor: "pointer", + color: "#9F99A5", + padding: 0, + + "&:hover": { + backgroundColor: "rgba(220, 53, 69, 0.1)", + color: "#DC3545", + }, +}); + +const HighlightMark = styled("mark", { + backgroundColor: "#FFE066", + color: "inherit", + borderRadius: "2px", +}); + +// --------------------------------------------------------------------------- +// Highlight helper +// --------------------------------------------------------------------------- + +function highlightText(text: string, query: string): React.ReactNode { + if (!query) return text; + const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const regex = new RegExp(`(${escaped})`, "gi"); + const parts = text.split(regex); + + return parts.map((part, i) => { + if (regex.test(part)) { + // Reset lastIndex after test() + regex.lastIndex = 0; + return {part}; + } + regex.lastIndex = 0; + return part; + }); +} + // --------------------------------------------------------------------------- // Props & Component // --------------------------------------------------------------------------- @@ -80,37 +180,134 @@ const TurnText = styled("p", { interface TurnBlockProps { turn: Turn; speaker: Speaker; + transcription: Transcription; isActive: boolean; isEditMode: boolean; + isSelected: boolean; + searchQuery: string; onSeekTo: (ms: number) => void; + onSelect: (turnId: string) => void; + turnRef?: (el: HTMLDivElement | null) => void; } function TurnBlock({ turn, speaker, + transcription, isActive, + isEditMode, + isSelected, + searchQuery, onSeekTo, + onSelect, + turnRef, }: TurnBlockProps) { + const dispatch = useTranscriptionDispatch(); + const [textValue, setTextValue] = useState(turn.text); + const [speakerDialogOpen, setSpeakerDialogOpen] = useState(false); + const textareaRef = useRef(null); + + // Keep local text in sync when turn.text changes externally + // (e.g. after a reducer update from another location) + const prevTurnText = useRef(turn.text); + if (prevTurnText.current !== turn.text) { + prevTurnText.current = turn.text; + setTextValue(turn.text); + } + const handleHeaderClick = () => { - onSeekTo(turn.startMs); + if (isEditMode) { + setSpeakerDialogOpen(true); + } else { + onSeekTo(turn.startMs); + } + }; + + const handleWrapClick = () => { + if (isEditMode) { + onSelect(turn.id); + } + }; + + const handleTextBlur = () => { + if (textValue !== turn.text) { + dispatch(updateTurnText(transcription.id, turn.id, textValue)); + } + }; + + const handleTextInput = (e: React.FormEvent) => { + const target = e.target as HTMLTextAreaElement; + target.style.height = "auto"; + target.style.height = `${target.scrollHeight}px`; + }; + + const handleRemove = (e: React.MouseEvent) => { + e.stopPropagation(); + dispatch(removeTurn(transcription.id, turn.id)); }; return ( - - { - if (e.key === "Enter" || e.key === " ") { - e.preventDefault(); - handleHeaderClick(); - } - }} + <> + - - {speaker.label} - {formatMs(turn.startMs)} - - {turn.text} - + {/* Edit mode: trash button */} + {isEditMode && ( + + + + )} + + { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + handleHeaderClick(); + } + }} + > + + {speaker.label} + {formatMs(turn.startMs)} + + + {isEditMode ? ( + setTextValue(e.target.value)} + onBlur={handleTextBlur} + onInput={handleTextInput} + rows={1} + aria-label="Texto del turno" + /> + ) : ( + + {searchQuery ? highlightText(turn.text, searchQuery) : turn.text} + + )} + + + {speakerDialogOpen && ( + setSpeakerDialogOpen(false)} + transcription={transcription} + turn={turn} + speaker={speaker} + /> + )} + ); } diff --git a/src/renderer/src/components/transcription-editor/index.tsx b/src/renderer/src/components/transcription-editor/index.tsx index 13f6782e..564b9627 100644 --- a/src/renderer/src/components/transcription-editor/index.tsx +++ b/src/renderer/src/components/transcription-editor/index.tsx @@ -1,10 +1,13 @@ -import { useMemo, useRef, useState } from "react"; +import { useCallback, useMemo, useRef, useState } from "react"; +import { CaretLeft, CaretRight, MagnifyingGlass } from "phosphor-react"; import AudioPlayer, { AudioPlayerHandle } from "@/components/audio-player"; import Switch from "@/components/switch"; import { styled } from "@/styles/stitches.config"; import type { Transcription } from "@/types/transcription"; import TurnBlock from "./TurnBlock"; +import AddTurnButton from "./AddTurnButton"; +import SuggestedSpeakersPanel from "./SuggestedSpeakersPanel"; import { useActiveTurn } from "./useActiveTurn"; // --------------------------------------------------------------------------- @@ -41,31 +44,87 @@ const ToolBar = styled("div", { justifyContent: "space-between", alignItems: "center", marginTop: "16px", + gap: "16px", }); -const SearchInput = styled("input", { - width: "711px", - maxWidth: "100%", +const SearchWrapper = styled("div", { + display: "flex", + flexDirection: "row", + alignItems: "center", + flex: 1, + maxWidth: "711px", border: "1px solid #BCBAB8", borderRadius: "24px", - padding: "12px 20px", + padding: "8px 16px", + backgroundColor: "#FFFFFF", + gap: "8px", + boxSizing: "border-box", + + "&:focus-within": { + borderColor: "#3F479D", + }, +}); + +const SearchInput = styled("input", { + flex: 1, + border: "none", + outline: "none", fontFamily: "$primary", fontSize: "16px", lineHeight: "22px", color: "$textDefault", - backgroundColor: "#FFFFFF", - outline: "none", - boxSizing: "border-box", + backgroundColor: "transparent", "&::placeholder": { color: "#9F99A5", }, +}); - "&:focus": { - borderColor: "#3F479D", +const SearchCounter = styled("span", { + fontFamily: "$primary", + fontSize: "13px", + lineHeight: "18px", + color: "#9F99A5", + whiteSpace: "nowrap", + flexShrink: 0, +}); + +const NavButton = styled("button", { + display: "flex", + alignItems: "center", + justifyContent: "center", + width: "24px", + height: "24px", + border: "none", + borderRadius: "4px", + backgroundColor: "transparent", + cursor: "pointer", + color: "#625C68", + padding: 0, + flexShrink: 0, + + "&:hover": { + backgroundColor: "rgba(63, 71, 157, 0.08)", + color: "#3F479D", + }, + + "&:disabled": { + opacity: 0.3, + cursor: "default", + "&:hover": { + backgroundColor: "transparent", + color: "#625C68", + }, }, }); +const EditorContent = styled("div", { + flex: 1, + display: "flex", + flexDirection: "row", + overflow: "hidden", +}); + const EditorBody = styled("div", { flex: 1, overflowY: "auto", @@ -76,6 +135,32 @@ const EditorBody = styled("div", { backgroundColor: "#F6F5F7", }); +// --------------------------------------------------------------------------- +// Search match helpers +// --------------------------------------------------------------------------- + +interface SearchMatch { + turnId: string; + index: number; // match index within the turn text +} + +function findMatches(turns: Transcription["turns"], query: string): SearchMatch[] { + if (!query) return []; + const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const regex = new RegExp(escaped, "gi"); + const matches: SearchMatch[] = []; + + for (const turn of turns) { + let match: RegExpExecArray | null; + // biome-ignore lint/suspicious/noAssignInExpressions: standard regex iteration pattern + while ((match = regex.exec(turn.text)) !== null) { + matches.push({ turnId: turn.id, index: match.index }); + } + } + + return matches; +} + // --------------------------------------------------------------------------- // Props & Component // --------------------------------------------------------------------------- @@ -94,9 +179,28 @@ function TranscriptionEditor({ const [currentMs, setCurrentMs] = useState(0); const playerRef = useRef(null); + // Search state + const [searchQuery, setSearchQuery] = useState(""); + const [matchIndex, setMatchIndex] = useState(0); + + // Edit mode state + const [selectedTurnId, setSelectedTurnId] = useState(null); + + // Ref map for turn elements (for scroll-into-view) + const turnRefsMap = useRef>(new Map()); + const setTurnRef = useCallback( + (turnId: string) => (el: HTMLDivElement | null) => { + if (el) { + turnRefsMap.current.set(turnId, el); + } else { + turnRefsMap.current.delete(turnId); + } + }, + [], + ); + const speakerMap = useMemo( - () => - Object.fromEntries(transcription.speakers.map((s) => [s.id, s])), + () => Object.fromEntries(transcription.speakers.map((s) => [s.id, s])), [transcription.speakers], ); @@ -106,16 +210,85 @@ function TranscriptionEditor({ playerRef.current?.seekTo(ms); }; + // Search matches + const matches = useMemo( + () => findMatches(transcription.turns, searchQuery), + [transcription.turns, searchQuery], + ); + + const safeMatchIndex = matches.length > 0 ? matchIndex % matches.length : 0; + + const scrollToMatch = (idx: number) => { + if (matches.length === 0) return; + const match = matches[idx % matches.length]; + const el = turnRefsMap.current.get(match.turnId); + el?.scrollIntoView({ behavior: "smooth", block: "center" }); + }; + + const handleSearchChange = (e: React.ChangeEvent) => { + setSearchQuery(e.target.value); + setMatchIndex(0); + }; + + const handlePrev = () => { + if (matches.length === 0) return; + const newIdx = (safeMatchIndex - 1 + matches.length) % matches.length; + setMatchIndex(newIdx); + scrollToMatch(newIdx); + }; + + const handleNext = () => { + if (matches.length === 0) return; + const newIdx = (safeMatchIndex + 1) % matches.length; + setMatchIndex(newIdx); + scrollToMatch(newIdx); + }; + + const handleTurnSelect = (turnId: string) => { + setSelectedTurnId((prev) => (prev === turnId ? null : turnId)); + }; + return ( {transcription.title} - + + + + {searchQuery && ( + <> + + {matches.length > 0 + ? `${safeMatchIndex + 1} / ${matches.length}` + : "0 / 0"} + + + + + + + + + )} + + - - {transcription.turns.map((turn) => { - const speaker = speakerMap[turn.speakerId]; - if (!speaker) return null; - - return ( - + + {transcription.turns.map((turn, index) => { + const speaker = speakerMap[turn.speakerId]; + if (!speaker) return null; + + return ( +
+ + + {isEditMode && index < transcription.turns.length - 1 && ( + + )} +
+ ); + })} + + {/* Add turn button after the last turn */} + {isEditMode && transcription.turns.length > 0 && ( + - ); - })} -
+ )} +
+ + {isEditMode && ( + + )} + Date: Fri, 17 Apr 2026 14:56:52 -0300 Subject: [PATCH 110/263] feat(voice-to-text): add validation and finish pages Adds VoiceValidation (TranscriptionEditor + nav footer) and VoiceFinish (summary card + .txt blob download) pages, wired into FeatureRouter. Co-Authored-By: Claude Sonnet 4.6 --- src/renderer/src/pages/finish/index.tsx | 3 +- src/renderer/src/pages/finish/voice/index.tsx | 74 +++++++++++++++++++ src/renderer/src/pages/validation/index.tsx | 3 +- .../src/pages/validation/voice/index.tsx | 40 ++++++++++ 4 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 src/renderer/src/pages/finish/voice/index.tsx create mode 100644 src/renderer/src/pages/validation/voice/index.tsx diff --git a/src/renderer/src/pages/finish/index.tsx b/src/renderer/src/pages/finish/index.tsx index 395bfcc0..80100533 100644 --- a/src/renderer/src/pages/finish/index.tsx +++ b/src/renderer/src/pages/finish/index.tsx @@ -2,13 +2,14 @@ import FeatureRouter from "@/features/FeatureRouter"; import Anonymizer from "./anonymizer"; import Dataset from "./dataset"; +import VoiceFinish from "./voice"; export default function Finish() { return ( } ANONYMIZER={} - VOICE_TO_TEXT={null} + VOICE_TO_TEXT={} /> ); } diff --git a/src/renderer/src/pages/finish/voice/index.tsx b/src/renderer/src/pages/finish/voice/index.tsx new file mode 100644 index 00000000..a39f8937 --- /dev/null +++ b/src/renderer/src/pages/finish/voice/index.tsx @@ -0,0 +1,74 @@ +import { useNavigate } from "react-router-dom"; + +import { Button, Card, SectionTitle, Stack, Subtitle, Text } from "@/components"; +import { formatTime } from "@/components/audio-player/formatTime"; +import { useTranscriptions } from "@/hooks/useTranscriptions"; +import { Footer, Section } from "@/layout/main"; + +export default function VoiceFinish() { + const navigate = useNavigate(); + const transcriptions = useTranscriptions(); + const transcription = transcriptions[0]; + + const handleDownloadTxt = () => { + if (!transcription) return; + + const lines = transcription.turns.map((turn) => { + const speaker = transcription.speakers.find((s) => s.id === turn.speakerId); + const time = formatTime(turn.startMs); + return `[${time}] ${speaker?.label ?? "Locutor"}: ${turn.text}`; + }); + + const content = lines.join("\n\n"); + const blob = new Blob([content], { type: "text/plain;charset=utf-8" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = `${transcription.title.replace(/[^a-zA-Z0-9\s]/g, "")}.txt`; + a.click(); + URL.revokeObjectURL(url); + }; + + return ( + <> +
+ 4. Finalización + {transcription ? ( + <> + + La transcripción ha sido completada y revisada. Podés descargarla + como archivo de texto. + + + Resumen de la transcripción + + + Título: {transcription.title} + + + Archivo: {transcription.audioFileName} + + + Locutores: {transcription.speakers.length} + + + Turnos: {transcription.turns.length} + + + + + ) : ( + No se encontró ninguna transcripción. + )} +
+
+ + +
+ + ); +} diff --git a/src/renderer/src/pages/validation/index.tsx b/src/renderer/src/pages/validation/index.tsx index 761fcf80..60940250 100644 --- a/src/renderer/src/pages/validation/index.tsx +++ b/src/renderer/src/pages/validation/index.tsx @@ -1,13 +1,14 @@ import FeatureRouter from "@/features/FeatureRouter"; import Anonymizer from "./anonymizer"; import Dataset from "./dataset"; +import VoiceValidation from "./voice"; export default function Validation() { return ( } ANONYMIZER={} - VOICE_TO_TEXT={null} + VOICE_TO_TEXT={} /> ); } diff --git a/src/renderer/src/pages/validation/voice/index.tsx b/src/renderer/src/pages/validation/voice/index.tsx new file mode 100644 index 00000000..d6aac141 --- /dev/null +++ b/src/renderer/src/pages/validation/voice/index.tsx @@ -0,0 +1,40 @@ +import { useState } from "react"; +import { Navigate, useNavigate } from "react-router-dom"; + +import { Button, TranscriptionEditor } from "@/components"; +import { useTranscriptions } from "@/hooks/useTranscriptions"; +import { Footer } from "@/layout/main"; + +export default function VoiceValidation() { + const navigate = useNavigate(); + const transcriptions = useTranscriptions(); + const [isEditMode, setIsEditMode] = useState(false); + + // Use the first transcription (one file at a time in voice-to-text workflow) + const transcription = transcriptions[0]; + + if (!transcription) { + // Guard: redirect back if there's no transcription (e.g. direct navigation) + return ; + } + + return ( + <> +
+ +
+
+ + +
+ + ); +} From 61e4124750f1a5004fa139b48a8d62b7bc61f121 Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 17 Apr 2026 15:28:57 -0300 Subject: [PATCH 111/263] fix: resolve biome lint issues in new voice-to-text files --- package-lock.json | 12879 ++++++++++++++++ .../src/components/audio-player/index.tsx | 19 +- .../src/components/feature-card/index.tsx | 10 +- .../src/components/speaker-avatar/index.tsx | 2 +- .../transcription-editor/AddTurnButton.tsx | 4 +- .../transcription-editor/SpeakerDialog.tsx | 40 +- .../SuggestedSpeakersPanel.tsx | 19 +- .../transcription-editor/TurnBlock.tsx | 11 +- .../components/transcription-editor/index.tsx | 11 +- .../transcription-editor/useActiveTurn.ts | 5 +- src/renderer/src/context/Transcription.tsx | 6 +- src/renderer/src/hooks/useTranscribe.ts | 5 +- src/renderer/src/pages/finish/voice/index.tsx | 19 +- .../src/pages/preview/voice/index.tsx | 2 +- .../src/pages/process/voice/index.tsx | 17 +- .../src/pages/validation/voice/index.tsx | 15 +- .../src/reducers/transcription/actions.ts | 21 +- .../src/reducers/transcription/index.ts | 5 +- .../src/services/aymurai/transcribe.ts | 4 +- src/renderer/src/types/transcription.ts | 12 +- 20 files changed, 13033 insertions(+), 73 deletions(-) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..13d6a30d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,12879 @@ +{ + "name": "aymurai", + "version": "1.24.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "aymurai", + "version": "1.24.0", + "hasInstallScript": true, + "dependencies": { + "@electron-toolkit/preload": "^3.0.2", + "@electron-toolkit/utils": "^4.0.0", + "electron-squirrel-startup": "^1.0.0" + }, + "devDependencies": { + "@biomejs/biome": "^1.9.4", + "@electron-forge/cli": "^6.0.4", + "@electron-forge/maker-deb": "^6.0.4", + "@electron-forge/maker-rpm": "^6.0.4", + "@electron-forge/maker-squirrel": "^6.0.4", + "@electron-forge/maker-zip": "^6.0.4", + "@electron-toolkit/tsconfig": "^1.0.1", + "@stitches/react": "^1.2.8", + "@tanstack/react-form": "1.11.0", + "@tanstack/react-query": "^5.81.1", + "@types/node": "20", + "@types/react": "18", + "@types/react-dom": "18", + "@types/regex-escape": "^3.4.1", + "@vitejs/plugin-react": "^4.5.0", + "axios": "^1.1.3", + "concurrently": "^7.5.0", + "cross-env": "^7.0.3", + "electron": "^21.2.0", + "electron-builder": "^26.0.12", + "electron-debug": "^3.2.0", + "electron-devtools-installer": "^3.2.1", + "electron-vite": "^3.1.0", + "exceljs": "^4.4.0", + "husky": "^8.0.0", + "lint-staged": "^13.0.3", + "markdownlint-cli": "^0.32.2", + "nodemon": "^2.0.20", + "phosphor-react": "^1.4.1", + "prettier": "^2.7.1", + "react": "18", + "react-dom": "18", + "react-router-dom": "6", + "regex-escape": "^3.4.10", + "typescript": "^5.9.2", + "vite": "^6.3.5", + "wait-on": "^6.0.1", + "zod": "^4.0.14", + "zustand": "^5.0.7" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@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/core/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/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@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.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/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/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@biomejs/biome": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.9.4.tgz", + "integrity": "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==", + "dev": true, + "hasInstallScript": true, + "license": "MIT OR Apache-2.0", + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "1.9.4", + "@biomejs/cli-darwin-x64": "1.9.4", + "@biomejs/cli-linux-arm64": "1.9.4", + "@biomejs/cli-linux-arm64-musl": "1.9.4", + "@biomejs/cli-linux-x64": "1.9.4", + "@biomejs/cli-linux-x64-musl": "1.9.4", + "@biomejs/cli-win32-arm64": "1.9.4", + "@biomejs/cli-win32-x64": "1.9.4" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz", + "integrity": "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz", + "integrity": "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.4.tgz", + "integrity": "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.4.tgz", + "integrity": "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz", + "integrity": "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz", + "integrity": "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz", + "integrity": "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz", + "integrity": "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@develar/schema-utils": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", + "integrity": "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.0", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@electron-forge/cli": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/cli/-/cli-6.4.2.tgz", + "integrity": "sha512-bM6YVTV0uUEpIL1jkpARlSm4Li26XZn+avC/lyTdpPqnd65T/oXZNkrAD+2Jb0RlgplOaM21qWm7ybtvKDGDyA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.electron-forge-cli?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "MIT", + "dependencies": { + "@electron-forge/core": "6.4.2", + "@electron-forge/shared-types": "6.4.2", + "@electron/get": "^2.0.0", + "chalk": "^4.0.0", + "commander": "^4.1.1", + "debug": "^4.3.1", + "fs-extra": "^10.0.0", + "listr2": "^5.0.3", + "semver": "^7.2.1" + }, + "bin": { + "electron-forge": "dist/electron-forge.js", + "electron-forge-vscode-nix": "script/vscode.sh", + "electron-forge-vscode-win": "script/vscode.cmd" + }, + "engines": { + "node": ">= 14.17.5" + } + }, + "node_modules/@electron-forge/core": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/core/-/core-6.4.2.tgz", + "integrity": "sha512-VtrFZ1Q7NG1ov0jJO/tUvUiYdWZ0Y31xw762is/jfpRPD6V/soOpwJJAoWoPK9TZVkTm2pkS8S5LikCMbNCLxw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.electron-forge-core?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "MIT", + "dependencies": { + "@electron-forge/core-utils": "6.4.2", + "@electron-forge/maker-base": "6.4.2", + "@electron-forge/plugin-base": "6.4.2", + "@electron-forge/publisher-base": "6.4.2", + "@electron-forge/shared-types": "6.4.2", + "@electron-forge/template-base": "6.4.2", + "@electron-forge/template-vite": "6.4.2", + "@electron-forge/template-vite-typescript": "6.4.2", + "@electron-forge/template-webpack": "6.4.2", + "@electron-forge/template-webpack-typescript": "6.4.2", + "@electron/get": "^2.0.0", + "@electron/rebuild": "^3.2.10", + "@malept/cross-spawn-promise": "^2.0.0", + "chalk": "^4.0.0", + "debug": "^4.3.1", + "electron-packager": "^17.1.2", + "fast-glob": "^3.2.7", + "filenamify": "^4.1.0", + "find-up": "^5.0.0", + "fs-extra": "^10.0.0", + "got": "^11.8.5", + "interpret": "^3.1.1", + "listr2": "^5.0.3", + "lodash": "^4.17.20", + "log-symbols": "^4.0.0", + "node-fetch": "^2.6.7", + "progress": "^2.0.3", + "rechoir": "^0.8.0", + "resolve-package": "^1.0.1", + "semver": "^7.2.1", + "source-map-support": "^0.5.13", + "sudo-prompt": "^9.1.1", + "username": "^5.1.0", + "yarn-or-npm": "^3.0.1" + }, + "engines": { + "node": ">= 14.17.5" + } + }, + "node_modules/@electron-forge/core-utils": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/core-utils/-/core-utils-6.4.2.tgz", + "integrity": "sha512-CjB3aakmRsXAMMDYc8PxNTMf4FdI29y4PErfv7eCXlL5oo3JW0VSKZIV7R8/Po0S0got85q2kmhZgCKuxL1BNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/shared-types": "6.4.2", + "@electron/rebuild": "^3.2.10", + "@malept/cross-spawn-promise": "^2.0.0", + "chalk": "^4.0.0", + "debug": "^4.3.1", + "find-up": "^5.0.0", + "fs-extra": "^10.0.0", + "log-symbols": "^4.0.0", + "semver": "^7.2.1", + "yarn-or-npm": "^3.0.1" + }, + "engines": { + "node": ">= 14.17.5" + } + }, + "node_modules/@electron-forge/maker-base": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/maker-base/-/maker-base-6.4.2.tgz", + "integrity": "sha512-zW3GH+LqDK9nxQmQEFkJPR8RqiX0lVk6a4mXll3ngujN1fPevO4ivUAWmaEVeC1dH/hXbN7s9m0S6a37MigftQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/shared-types": "6.4.2", + "fs-extra": "^10.0.0", + "which": "^2.0.2" + }, + "engines": { + "node": ">= 14.17.5" + } + }, + "node_modules/@electron-forge/maker-deb": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/maker-deb/-/maker-deb-6.4.2.tgz", + "integrity": "sha512-tlV8ffivgBP94vtYXgAeXgzeKCaRyLuWH9LT8PQW1QrYbAFpCMmuwk/zFaJkyMklImCWmDFTPYMEqdEJGd7Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/maker-base": "6.4.2", + "@electron-forge/shared-types": "6.4.2" + }, + "engines": { + "node": ">= 14.17.5" + }, + "optionalDependencies": { + "electron-installer-debian": "^3.2.0" + } + }, + "node_modules/@electron-forge/maker-rpm": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/maker-rpm/-/maker-rpm-6.4.2.tgz", + "integrity": "sha512-+hfbY5pYbAer0y07OtOzVgVBHoTRmemqqZ//T0mKJpyK2ThHKGTvyW8FFlr5jlQs5LoDCM2WHKE8oGtRhivsMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/maker-base": "6.4.2", + "@electron-forge/shared-types": "6.4.2" + }, + "engines": { + "node": ">= 14.17.5" + }, + "optionalDependencies": { + "electron-installer-redhat": "^3.2.0" + } + }, + "node_modules/@electron-forge/maker-squirrel": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/maker-squirrel/-/maker-squirrel-6.4.2.tgz", + "integrity": "sha512-ukK3RcFaBrQXUzR52PsHxfwDq5XKSnj6A1kkXiyHWqgj+HIU97prBScBb5JRtasPvYN+nDdQO2vlInsLaqcx9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/maker-base": "6.4.2", + "@electron-forge/shared-types": "6.4.2", + "fs-extra": "^10.0.0" + }, + "engines": { + "node": ">= 14.17.5" + }, + "optionalDependencies": { + "electron-winstaller": "^5.0.0" + } + }, + "node_modules/@electron-forge/maker-zip": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/maker-zip/-/maker-zip-6.4.2.tgz", + "integrity": "sha512-k2nfhhnxcYbUS7rCKCisuqEalxtH9l73+lrtfL0aQZiE/BLbDXyNckDIDOPvX0tBEg62nVzUdJonZwOhZVvAMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/maker-base": "6.4.2", + "@electron-forge/shared-types": "6.4.2", + "cross-zip": "^4.0.0", + "fs-extra": "^10.0.0", + "got": "^11.8.5" + }, + "engines": { + "node": ">= 14.17.5" + } + }, + "node_modules/@electron-forge/plugin-base": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/plugin-base/-/plugin-base-6.4.2.tgz", + "integrity": "sha512-g6AAtQ7fZ94djBmwcnWasQ8xgaNVNjgaQ00GLK0NkmQ7n0PNbsnlMDuw9vdfTiL6WaLg5nxNSYc9bFJP/rtyeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/shared-types": "6.4.2" + }, + "engines": { + "node": ">= 14.17.5" + } + }, + "node_modules/@electron-forge/publisher-base": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/publisher-base/-/publisher-base-6.4.2.tgz", + "integrity": "sha512-Tnf9O8MFzdT1gsb5EDDaQUoslt7gUuUywtsr+lT/fpBlBQbei2fvioTwvZ1Q1cmsKnld7XhRh6unfgdWLTZzgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/shared-types": "6.4.2" + }, + "engines": { + "node": ">= 14.17.5" + } + }, + "node_modules/@electron-forge/shared-types": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/shared-types/-/shared-types-6.4.2.tgz", + "integrity": "sha512-DKOUMsdTXZIq8XiqY0Hi3C+dam/JKUnvfBjwcUeyZqPdgEE1qry8xZmmjorXuLrRf1Jq8rhxYGQInSK4af0QYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron/rebuild": "^3.2.10", + "electron-packager": "^17.1.2", + "listr2": "^5.0.3" + }, + "engines": { + "node": ">= 14.17.5" + } + }, + "node_modules/@electron-forge/template-base": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/template-base/-/template-base-6.4.2.tgz", + "integrity": "sha512-vsQh+64Fr2Vxg6k8DAahWq4MAdB2F2qTig+LgIJENv8ksbzC1YIq05SBAS/g2674cdr7WdwyukMy2rgxe3rhnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/shared-types": "6.4.2", + "@malept/cross-spawn-promise": "^2.0.0", + "debug": "^4.3.1", + "fs-extra": "^10.0.0", + "username": "^5.1.0" + }, + "engines": { + "node": ">= 14.17.5" + } + }, + "node_modules/@electron-forge/template-vite": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/template-vite/-/template-vite-6.4.2.tgz", + "integrity": "sha512-NX7jHRblBmIqufMbqWgpI/VnpgF/qMSTq9ZPmDSXamBhid336MC6+DoWzDpXceQZEp0m/jpMLR04ynr8O4jGlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/shared-types": "6.4.2", + "@electron-forge/template-base": "6.4.2", + "fs-extra": "^10.0.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + } + }, + "node_modules/@electron-forge/template-vite-typescript": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/template-vite-typescript/-/template-vite-typescript-6.4.2.tgz", + "integrity": "sha512-h3pn6onvC/nLglmJuelYU82Qzrh0l6MqvbBGoT39bbDoRLIqmlhWTWppHgDJVXAGrSoH+9BEpptipeBQWirFwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/shared-types": "6.4.2", + "@electron-forge/template-base": "6.4.2", + "fs-extra": "^10.0.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + } + }, + "node_modules/@electron-forge/template-webpack": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/template-webpack/-/template-webpack-6.4.2.tgz", + "integrity": "sha512-9QYr/td4cmnGOj8UF25W6An/eI+JXj9T/b+KFybL3cQ87H1yrQOn2T84Bm5/JaB4SPdIu4FdKRjqwR7C7R0g2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/shared-types": "6.4.2", + "@electron-forge/template-base": "6.4.2", + "fs-extra": "^10.0.0" + }, + "engines": { + "node": ">= 14.17.5" + } + }, + "node_modules/@electron-forge/template-webpack-typescript": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@electron-forge/template-webpack-typescript/-/template-webpack-typescript-6.4.2.tgz", + "integrity": "sha512-MPAZQ4v6piCED7NT1LTVQf61o6Eg/laNoKbhbrFBSH1i20OUwbtV2MLj6Op292ynI9+1qdHKmFgctr6qPTCAQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/shared-types": "6.4.2", + "@electron-forge/template-base": "6.4.2", + "fs-extra": "^10.0.0" + }, + "engines": { + "node": ">= 14.17.5" + } + }, + "node_modules/@electron-toolkit/preload": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@electron-toolkit/preload/-/preload-3.0.2.tgz", + "integrity": "sha512-TWWPToXd8qPRfSXwzf5KVhpXMfONaUuRAZJHsKthKgZR/+LqX1dZVSSClQ8OTAEduvLGdecljCsoT2jSshfoUg==", + "license": "MIT", + "peerDependencies": { + "electron": ">=13.0.0" + } + }, + "node_modules/@electron-toolkit/tsconfig": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@electron-toolkit/tsconfig/-/tsconfig-1.0.1.tgz", + "integrity": "sha512-M0Mol3odspvtCuheyujLNAW7bXq7KFNYVMRtpjFa4ZfES4MuklXBC7Nli/omvc+PRKlrklgAGx3l4VakjNo8jg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/node": "*" + } + }, + "node_modules/@electron-toolkit/utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@electron-toolkit/utils/-/utils-4.0.0.tgz", + "integrity": "sha512-qXSntwEzluSzKl4z5yFNBknmPGjPa3zFhE4mp9+h0cgokY5ornAeP+CJQDBhKsL1S58aOQfcwkD3NwLZCl+64g==", + "license": "MIT", + "peerDependencies": { + "electron": ">=13.0.0" + } + }, + "node_modules/@electron/asar": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.4.1.tgz", + "integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^5.0.0", + "glob": "^7.1.6", + "minimatch": "^3.0.4" + }, + "bin": { + "asar": "bin/asar.js" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/@electron/asar/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@electron/asar/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@electron/asar/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@electron/asar/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@electron/asar/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@electron/fuses": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@electron/fuses/-/fuses-1.8.0.tgz", + "integrity": "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.1", + "fs-extra": "^9.0.1", + "minimist": "^1.2.5" + }, + "bin": { + "electron-fuses": "dist/bin.js" + } + }, + "node_modules/@electron/fuses/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/get": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", + "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/@electron/get/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@electron/get/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/get/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/@electron/get/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/@electron/node-gyp": { + "version": "10.2.0-electron.1", + "resolved": "git+ssh://git@github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2", + "integrity": "sha512-CrYo6TntjpoMO1SHjl5Pa/JoUsECNqNdB7Kx49WLQpWzPw53eEITJ2Hs9fh/ryUYDn4pxZz11StaBYBrLFJdqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^8.1.0", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.2.1", + "nopt": "^6.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "tar": "^6.2.1", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/@electron/notarize": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz", + "integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/notarize/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/osx-sign": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.3.3.tgz", + "integrity": "sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "compare-version": "^0.1.2", + "debug": "^4.3.4", + "fs-extra": "^10.0.0", + "isbinaryfile": "^4.0.8", + "minimist": "^1.2.6", + "plist": "^3.0.5" + }, + "bin": { + "electron-osx-flat": "bin/electron-osx-flat.js", + "electron-osx-sign": "bin/electron-osx-sign.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@electron/osx-sign/node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/@electron/rebuild": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.7.2.tgz", + "integrity": "sha512-19/KbIR/DAxbsCkiaGMXIdPnMCJLkcf8AvGnduJtWBs/CBwiAjY1apCqOLVxrXg+rtXFCngbXhBanWjxLUt1Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron/node-gyp": "git+https://github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2", + "@malept/cross-spawn-promise": "^2.0.0", + "chalk": "^4.0.0", + "debug": "^4.1.1", + "detect-libc": "^2.0.1", + "fs-extra": "^10.0.0", + "got": "^11.7.0", + "node-abi": "^3.45.0", + "node-api-version": "^0.2.0", + "ora": "^5.1.0", + "read-binary-file-arch": "^1.0.6", + "semver": "^7.3.5", + "tar": "^6.0.5", + "yargs": "^17.0.1" + }, + "bin": { + "electron-rebuild": "lib/cli.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/@electron/universal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-2.0.3.tgz", + "integrity": "sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron/asar": "^3.3.1", + "@malept/cross-spawn-promise": "^2.0.0", + "debug": "^4.3.1", + "dir-compare": "^4.2.0", + "fs-extra": "^11.1.1", + "minimatch": "^9.0.3", + "plist": "^3.1.0" + }, + "engines": { + "node": ">=16.4" + } + }, + "node_modules/@electron/universal/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@electron/universal/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@electron/universal/node_modules/fs-extra": { + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/universal/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@electron/windows-sign": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-1.2.2.tgz", + "integrity": "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "dependencies": { + "cross-dirname": "^0.1.0", + "debug": "^4.3.4", + "fs-extra": "^11.1.1", + "minimist": "^1.2.8", + "postject": "^1.0.0-alpha.6" + }, + "bin": { + "electron-windows-sign": "bin/electron-windows-sign.js" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/windows-sign/node_modules/fs-extra": { + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@fast-csv/format": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", + "integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isboolean": "^3.0.3", + "lodash.isequal": "^4.5.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0" + } + }, + "node_modules/@fast-csv/format/node_modules/@types/node": { + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@fast-csv/parse": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz", + "integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.groupby": "^4.6.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0", + "lodash.isundefined": "^3.0.1", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/@fast-csv/parse/node_modules/@types/node": { + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@isaacs/fs-minipass/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "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/@malept/cross-spawn-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", + "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/@malept/flatpak-bundler": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz", + "integrity": "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.0", + "lodash": "^4.17.15", + "tmp-promise": "^3.0.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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/@npmcli/agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz", + "integrity": "sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@npmcli/agent/node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, + "license": "MIT", + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@remix-run/router": { + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz", + "integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "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.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz", + "integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz", + "integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz", + "integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz", + "integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz", + "integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz", + "integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz", + "integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz", + "integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz", + "integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz", + "integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz", + "integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz", + "integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz", + "integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz", + "integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz", + "integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz", + "integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz", + "integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz", + "integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz", + "integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz", + "integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz", + "integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz", + "integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz", + "integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz", + "integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz", + "integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@stitches/react": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@stitches/react/-/react-1.2.8.tgz", + "integrity": "sha512-9g9dWI4gsSVe8bNLlb+lMkBYsnIKCZTmvqvDG+Avnn69XfmHZKiaMrx7cgTaddq7aTPPmXiTsbFcUy0xgI4+wA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": ">= 16.3.0" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tanstack/form-core": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@tanstack/form-core/-/form-core-1.11.0.tgz", + "integrity": "sha512-BaEnQ73h4S72AXdjgQowmDBJPHbAvPnWTY2xeY74O7/qfesZKbgPA7DQi5BW1qMv15BkthloJMi9Qljbf5mi7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tanstack/store": "^0.7.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.99.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.99.0.tgz", + "integrity": "sha512-3Jv3WQG0BCcH7G+7lf/bP8QyBfJOXeY+T08Rin3GZ1bshvwlbPt7NrDHMEzGdKIOmOzvIQmxjk28YEQX60k7pQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-form": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-form/-/react-form-1.11.0.tgz", + "integrity": "sha512-jTsTVvRaTLWwdhCAKG0mfrH+/43wudGujwDiRRT09VYxWJeJNFoXqepXW26lY0iuq11a0+A/0lmr2TfVqPanfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tanstack/form-core": "1.11.0", + "@tanstack/react-store": "^0.7.0", + "decode-formdata": "^0.9.0", + "devalue": "^5.1.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-start": "^1.112.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "vinxi": "^0.5.0" + }, + "peerDependenciesMeta": { + "@tanstack/react-start": { + "optional": true + }, + "vinxi": { + "optional": true + } + } + }, + "node_modules/@tanstack/react-form/node_modules/@tanstack/react-store": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.7.7.tgz", + "integrity": "sha512-qqT0ufegFRDGSof9D/VqaZgjNgp4tRPHZIJq2+QIHkMUtHjaJ0lYrrXjeIUJvjnTbgPfSD1XgOMEt0lmANn6Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tanstack/store": "0.7.7", + "use-sync-external-store": "^1.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.99.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.99.0.tgz", + "integrity": "sha512-OY2bCqPemT1LlqJ8Y2CUau4KELnIhhG9Ol3ZndPbdnB095pRbPo1cHuXTndg8iIwtoHTgwZjyaDnQ0xD0mYwAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.99.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@tanstack/store": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.7.7.tgz", + "integrity": "sha512-xa6pTan1bcaqYDS9BDpSiS63qa6EoDkPN9RsRaxHuDdVDNntzq3xNwR5YKTU/V3SkSyC9T4YVOPh2zRQN0nhIQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "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/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz", + "integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/plist": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.5.tgz", + "integrity": "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*", + "xmlbuilder": ">=11.0.1" + } + }, + "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.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", + "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", + "dev": true, + "license": "MIT", + "peer": true, + "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/@types/regex-escape": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@types/regex-escape/-/regex-escape-3.4.1.tgz", + "integrity": "sha512-aQihdLwAzyST0/LTidv76ZKtltWbea61FprvpMHbqUToUpdZrSYUqPb3ToojMW2a29JfoJXBxtO6K5py4o8uwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/verror": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.11.tgz", + "integrity": "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "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/@xmldom/xmldom": { + "version": "0.8.12", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.12.tgz", + "integrity": "sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/7zip-bin": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.2.0.tgz", + "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/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/app-builder-bin": { + "version": "5.0.0-alpha.12", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-5.0.0-alpha.12.tgz", + "integrity": "sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/app-builder-lib": { + "version": "26.8.1", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-26.8.1.tgz", + "integrity": "sha512-p0Im/Dx5C4tmz8QEE1Yn4MkuPC8PrnlRneMhWJj7BBXQfNTJUshM/bp3lusdEsDbvvfJZpXWnYesgSLvwtM2Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@develar/schema-utils": "~2.6.5", + "@electron/asar": "3.4.1", + "@electron/fuses": "^1.8.0", + "@electron/get": "^3.0.0", + "@electron/notarize": "2.5.0", + "@electron/osx-sign": "1.3.3", + "@electron/rebuild": "^4.0.3", + "@electron/universal": "2.0.3", + "@malept/flatpak-bundler": "^0.4.0", + "@types/fs-extra": "9.0.13", + "async-exit-hook": "^2.0.1", + "builder-util": "26.8.1", + "builder-util-runtime": "9.5.1", + "chromium-pickle-js": "^0.2.0", + "ci-info": "4.3.1", + "debug": "^4.3.4", + "dotenv": "^16.4.5", + "dotenv-expand": "^11.0.6", + "ejs": "^3.1.8", + "electron-publish": "26.8.1", + "fs-extra": "^10.1.0", + "hosted-git-info": "^4.1.0", + "isbinaryfile": "^5.0.0", + "jiti": "^2.4.2", + "js-yaml": "^4.1.0", + "json5": "^2.2.3", + "lazy-val": "^1.0.5", + "minimatch": "^10.0.3", + "plist": "3.1.0", + "proper-lockfile": "^4.1.2", + "resedit": "^1.7.0", + "semver": "~7.7.3", + "tar": "^7.5.7", + "temp-file": "^3.4.0", + "tiny-async-pool": "1.3.0", + "which": "^5.0.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "dmg-builder": "26.8.1", + "electron-builder-squirrel-windows": "26.8.1" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-3.1.0.tgz", + "integrity": "sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=14" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get/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/app-builder-lib/node_modules/@electron/rebuild": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-4.0.3.tgz", + "integrity": "sha512-u9vpTHRMkOYCs/1FLiSVAFZ7FbjsXK+bQuzviJZa+lG7BHZl1nz52/IcGvwa3sk80/fc3llutBkbCq10Vh8WQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@malept/cross-spawn-promise": "^2.0.0", + "debug": "^4.1.1", + "detect-libc": "^2.0.1", + "got": "^11.7.0", + "graceful-fs": "^4.2.11", + "node-abi": "^4.2.0", + "node-api-version": "^0.2.1", + "node-gyp": "^11.2.0", + "ora": "^5.1.0", + "read-binary-file-arch": "^1.0.6", + "semver": "^7.3.5", + "tar": "^7.5.6", + "yargs": "^17.0.1" + }, + "bin": { + "electron-rebuild": "lib/cli.js" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/app-builder-lib/node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/app-builder-lib/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/app-builder-lib/node_modules/isexe": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/app-builder-lib/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/app-builder-lib/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/app-builder-lib/node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/app-builder-lib/node_modules/node-abi": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.28.0.tgz", + "integrity": "sha512-Qfp5XZL1cJDOabOT8H5gnqMTmM4NjvYzHp4I/Kt/Sl76OVkOBBHRFlPspGV0hYvMoqQsypFjT/Yp7Km0beXW9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.6.3" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/app-builder-lib/node_modules/tar": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.13.tgz", + "integrity": "sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/app-builder-lib/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/app-builder-lib/node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/app-builder-lib/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/archiver": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", + "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.4", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/archiver-utils/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/archiver-utils/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver-utils/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/author-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/author-regex/-/author-regex-1.0.0.tgz", + "integrity": "sha512-KbWgR8wOYRAPekEmMXrYYdc7BRyhn2Ftk7KWfMUnQ43hFdojWEFRxhhRUm3/OFEdPa1r0KAvTTg9YQK57xTe0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/axios": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", + "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/baseline-browser-mapping": { + "version": "2.10.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.19.tgz", + "integrity": "sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "dev": true, + "license": "Unlicense", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" + } + }, + "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/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT", + "optional": true + }, + "node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "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.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "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", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "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": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", + "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "dev": true, + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/builder-util": { + "version": "26.8.1", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.8.1.tgz", + "integrity": "sha512-pm1lTYbGyc90DHgCDO7eo8Rl4EqKLciayNbZqGziqnH9jrlKe8ZANGdityLZU+pJh16dfzjAx2xQq9McuIPEtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/debug": "^4.1.6", + "7zip-bin": "~5.2.0", + "app-builder-bin": "5.0.0-alpha.12", + "builder-util-runtime": "9.5.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.6", + "debug": "^4.3.4", + "fs-extra": "^10.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "js-yaml": "^4.1.0", + "sanitize-filename": "^1.6.3", + "source-map-support": "^0.5.19", + "stat-mode": "^1.0.0", + "temp-file": "^3.4.0", + "tiny-async-pool": "1.3.0" + } + }, + "node_modules/builder-util-runtime": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.5.1.tgz", + "integrity": "sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001788", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", + "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==", + "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/chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "dev": true, + "license": "MIT/X11", + "dependencies": { + "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/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/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/chromium-pickle-js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", + "integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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/compare-version": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", + "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/compress-commons": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", + "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concurrently": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.6.0.tgz", + "integrity": "sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "date-fns": "^2.29.1", + "lodash": "^4.17.21", + "rxjs": "^7.0.0", + "shell-quote": "^1.7.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^17.3.1" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "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/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "^5.1.0" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", + "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cross-dirname": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz", + "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn-windows-exe": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/cross-spawn-windows-exe/-/cross-spawn-windows-exe-1.2.0.tgz", + "integrity": "sha512-mkLtJJcYbDCxEG7Js6eUnUNndWjyUZwJ3H7bErmmtOYU/Zb99DyUkpamuIZE0b3bhmJyZ7D90uS6f+CGxRRjOw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-cross-spawn-windows-exe?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "dependencies": { + "@malept/cross-spawn-promise": "^1.1.0", + "is-wsl": "^2.2.0", + "which": "^2.0.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cross-spawn-windows-exe/node_modules/@malept/cross-spawn-promise": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", + "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cross-zip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cross-zip/-/cross-zip-4.0.1.tgz", + "integrity": "sha512-n63i0lZ0rvQ6FXiGQ+/JFCKAUyPFhLQYJIqKaa+tSJtfKeULF/IDNDAbdnSIxgS4NTuw2b0+lj8LzfITuq+ZxQ==", + "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", + "engines": { + "node": ">=12.10" + } + }, + "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/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/dayjs": { + "version": "1.11.20", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz", + "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==", + "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==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-formdata": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/decode-formdata/-/decode-formdata-0.9.0.tgz", + "integrity": "sha512-q5uwOjR3Um5YD+ZWPOF/1sGHVW9A5rCrRwITQChRXlmPkxDFBqCm4jNTIVdGHNH9OnR+V9MoZVgRhsFb+ARbUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "optional": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "license": "MIT", + "optional": true + }, + "node_modules/devalue": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.7.1.tgz", + "integrity": "sha512-MUbZ586EgQqdRnC4yDrlod3BEdyvE4TapGYHMW2CiaW+KkkFmWEFqBUaLltEZCGi0iFXCEjRF0OjF0DV2QHjOA==", + "dev": true, + "license": "MIT" + }, + "node_modules/dir-compare": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz", + "integrity": "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.5", + "p-limit": "^3.1.0 " + } + }, + "node_modules/dir-compare/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/dir-compare/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/dir-compare/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dmg-builder": { + "version": "26.8.1", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.8.1.tgz", + "integrity": "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "app-builder-lib": "26.8.1", + "builder-util": "26.8.1", + "fs-extra": "^10.1.0", + "iconv-lite": "^0.6.2", + "js-yaml": "^4.1.0" + }, + "optionalDependencies": { + "dmg-license": "^1.0.11" + } + }, + "node_modules/dmg-license": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", + "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "@types/plist": "^3.0.1", + "@types/verror": "^1.10.3", + "ajv": "^6.10.0", + "crc": "^3.8.0", + "iconv-corefoundation": "^1.1.7", + "plist": "^3.0.4", + "smart-buffer": "^4.0.2", + "verror": "^1.10.0" + }, + "bin": { + "dmg-license": "bin/dmg-license.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", + "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/duplexer3": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", + "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", + "license": "BSD-3-Clause" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron": { + "version": "21.4.4", + "resolved": "https://registry.npmjs.org/electron/-/electron-21.4.4.tgz", + "integrity": "sha512-N5O7y7Gtt7mDgkJLkW49ETiT8M3myZ9tNIEvGTKhpBduX4WdgMj6c3hYeYBD6XW7SvbRkWEQaTl25RNday8Xpw==", + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@electron/get": "^1.14.1", + "@types/node": "^16.11.26", + "extract-zip": "^2.0.1" + }, + "bin": { + "electron": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + } + }, + "node_modules/electron-builder": { + "version": "26.8.1", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-26.8.1.tgz", + "integrity": "sha512-uWhx1r74NGpCagG0ULs/P9Nqv2nsoo+7eo4fLUOB8L8MdWltq9odW/uuLXMFCDGnPafknYLZgjNX0ZIFRzOQAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "26.8.1", + "builder-util": "26.8.1", + "builder-util-runtime": "9.5.1", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "dmg-builder": "26.8.1", + "fs-extra": "^10.1.0", + "lazy-val": "^1.0.5", + "simple-update-notifier": "2.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "electron-builder": "cli.js", + "install-app-deps": "install-app-deps.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/electron-builder-squirrel-windows": { + "version": "26.8.1", + "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.8.1.tgz", + "integrity": "sha512-o288fIdgPLHA76eDrFADHPoo7VyGkDCYbLV1GzndaMSAVBoZrGvM9m2IehdcVMzdAZJ2eV9bgyissQXHv5tGzA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "app-builder-lib": "26.8.1", + "builder-util": "26.8.1", + "electron-winstaller": "5.4.0" + } + }, + "node_modules/electron-debug": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/electron-debug/-/electron-debug-3.2.0.tgz", + "integrity": "sha512-7xZh+LfUvJ52M9rn6N+tPuDw6oRAjxUj9SoxAZfJ0hVCXhZCsdkrSt7TgXOiWiEOBgEV8qwUIO/ScxllsPS7ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "electron-is-dev": "^1.1.0", + "electron-localshortcut": "^3.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/electron-devtools-installer": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/electron-devtools-installer/-/electron-devtools-installer-3.2.1.tgz", + "integrity": "sha512-FaCi+oDCOBTw0gJUsuw5dXW32b2Ekh5jO8lI1NRCQigo3azh2VogsIi0eelMVrP1+LkN/bewyH3Xoo1USjO0eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "rimraf": "^3.0.2", + "semver": "^7.2.1", + "tslib": "^2.1.0", + "unzip-crx-3": "^0.2.0" + } + }, + "node_modules/electron-installer-common": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/electron-installer-common/-/electron-installer-common-0.10.4.tgz", + "integrity": "sha512-8gMNPXfAqUE5CfXg8RL0vXpLE9HAaPkgLXVoHE3BMUzogMWenf4LmwQ27BdCUrEhkjrKl+igs2IHJibclR3z3Q==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@electron/asar": "^3.2.5", + "@malept/cross-spawn-promise": "^1.0.0", + "debug": "^4.1.1", + "fs-extra": "^9.0.0", + "glob": "^7.1.4", + "lodash": "^4.17.15", + "parse-author": "^2.0.0", + "semver": "^7.1.1", + "tmp-promise": "^3.0.2" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "url": "https://github.com/electron-userland/electron-installer-common?sponsor=1" + }, + "optionalDependencies": { + "@types/fs-extra": "^9.0.1" + } + }, + "node_modules/electron-installer-common/node_modules/@malept/cross-spawn-promise": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", + "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/electron-installer-common/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/electron-installer-common/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/electron-installer-common/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-installer-common/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/electron-installer-common/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/electron-installer-debian": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/electron-installer-debian/-/electron-installer-debian-3.2.0.tgz", + "integrity": "sha512-58ZrlJ1HQY80VucsEIG9tQ//HrTlG6sfofA3nRGr6TmkX661uJyu4cMPPh6kXW+aHdq/7+q25KyQhDrXvRL7jw==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin", + "linux" + ], + "dependencies": { + "@malept/cross-spawn-promise": "^1.0.0", + "debug": "^4.1.1", + "electron-installer-common": "^0.10.2", + "fs-extra": "^9.0.0", + "get-folder-size": "^2.0.1", + "lodash": "^4.17.4", + "word-wrap": "^1.2.3", + "yargs": "^16.0.2" + }, + "bin": { + "electron-installer-debian": "src/cli.js" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-installer-debian/node_modules/@malept/cross-spawn-promise": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", + "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/electron-installer-debian/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/electron-installer-debian/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-installer-debian/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-installer-debian/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-installer-redhat": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/electron-installer-redhat/-/electron-installer-redhat-3.4.0.tgz", + "integrity": "sha512-gEISr3U32Sgtj+fjxUAlSDo3wyGGq6OBx7rF5UdpIgbnpUvMN4W5uYb0ThpnAZ42VEJh/3aODQXHbFS4f5J3Iw==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin", + "linux" + ], + "dependencies": { + "@malept/cross-spawn-promise": "^1.0.0", + "debug": "^4.1.1", + "electron-installer-common": "^0.10.2", + "fs-extra": "^9.0.0", + "lodash": "^4.17.15", + "word-wrap": "^1.2.3", + "yargs": "^16.0.2" + }, + "bin": { + "electron-installer-redhat": "src/cli.js" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-installer-redhat/node_modules/@malept/cross-spawn-promise": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", + "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/electron-installer-redhat/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/electron-installer-redhat/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-installer-redhat/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-installer-redhat/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-is-accelerator": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/electron-is-accelerator/-/electron-is-accelerator-0.1.2.tgz", + "integrity": "sha512-fLGSAjXZtdn1sbtZxx52+krefmtNuVwnJCV2gNiVt735/ARUboMl8jnNC9fZEqQdlAv2ZrETfmBUsoQci5evJA==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-is-dev": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.2.0.tgz", + "integrity": "sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-localshortcut": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/electron-localshortcut/-/electron-localshortcut-3.2.1.tgz", + "integrity": "sha512-DWvhKv36GsdXKnaFFhEiK8kZZA+24/yFLgtTwJJHc7AFgDjNRIBJZ/jq62Y/dWv9E4ypYwrVWN2bVrCYw1uv7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.0.1", + "electron-is-accelerator": "^0.1.0", + "keyboardevent-from-electron-accelerator": "^2.0.0", + "keyboardevents-areequal": "^0.2.1" + } + }, + "node_modules/electron-packager": { + "version": "17.1.2", + "resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-17.1.2.tgz", + "integrity": "sha512-XofXdikjYI7MVBcnXeoOvRR+yFFFHOLs3J7PF5KYQweigtgLshcH4W660PsvHr4lYZ03JBpLyEcUB8DzHZ+BNw==", + "deprecated": "Please use @electron/packager moving forward. There is no API change, just a package name change", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@electron/asar": "^3.2.1", + "@electron/get": "^2.0.0", + "@electron/notarize": "^1.2.3", + "@electron/osx-sign": "^1.0.5", + "@electron/universal": "^1.3.2", + "cross-spawn-windows-exe": "^1.2.0", + "debug": "^4.0.1", + "extract-zip": "^2.0.0", + "filenamify": "^4.1.0", + "fs-extra": "^11.1.0", + "galactus": "^1.0.0", + "get-package-info": "^1.0.0", + "junk": "^3.1.0", + "parse-author": "^2.0.0", + "plist": "^3.0.0", + "rcedit": "^3.0.1", + "resolve": "^1.1.6", + "semver": "^7.1.3", + "yargs-parser": "^21.1.1" + }, + "bin": { + "electron-packager": "bin/electron-packager.js" + }, + "engines": { + "node": ">= 14.17.5" + }, + "funding": { + "url": "https://github.com/electron/electron-packager?sponsor=1" + } + }, + "node_modules/electron-packager/node_modules/@electron/notarize": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-1.2.4.tgz", + "integrity": "sha512-W5GQhJEosFNafewnS28d3bpQ37/s91CDWqxVchHfmv2dQSTWpOzNlUVQwYzC1ay5bChRV/A9BTL68yj0Pa+TSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-packager/node_modules/@electron/notarize/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-packager/node_modules/@electron/universal": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-1.5.1.tgz", + "integrity": "sha512-kbgXxyEauPJiQQUNG2VgUeyfQNFk6hBF11ISN2PNI6agUgPl55pv4eQmaqHzTAzchBvqZ2tQuRVaPStGf0mxGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron/asar": "^3.2.1", + "@malept/cross-spawn-promise": "^1.1.0", + "debug": "^4.3.1", + "dir-compare": "^3.0.0", + "fs-extra": "^9.0.1", + "minimatch": "^3.0.4", + "plist": "^3.0.4" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/electron-packager/node_modules/@electron/universal/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-packager/node_modules/@malept/cross-spawn-promise": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", + "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/electron-packager/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-packager/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/electron-packager/node_modules/dir-compare": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-3.3.0.tgz", + "integrity": "sha512-J7/et3WlGUCxjdnD3HAAzQ6nsnc0WL6DD7WcwJb7c39iH1+AWfg+9OqzJNaI6PkBwBvm1mhZNL9iY/nRiZXlPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal": "^1.0.0", + "minimatch": "^3.0.4" + } + }, + "node_modules/electron-packager/node_modules/fs-extra": { + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/electron-packager/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/electron-publish": { + "version": "26.8.1", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-26.8.1.tgz", + "integrity": "sha512-q+jrSTIh/Cv4eGZa7oVR+grEJo/FoLMYBAnSL5GCtqwUpr1T+VgKB/dn1pnzxIxqD8S/jP1yilT9VrwCqINR4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/fs-extra": "^9.0.11", + "builder-util": "26.8.1", + "builder-util-runtime": "9.5.1", + "chalk": "^4.1.2", + "form-data": "^4.0.5", + "fs-extra": "^10.1.0", + "lazy-val": "^1.0.5", + "mime": "^2.5.2" + } + }, + "node_modules/electron-squirrel-startup": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/electron-squirrel-startup/-/electron-squirrel-startup-1.0.1.tgz", + "integrity": "sha512-sTfFIHGku+7PsHLJ7v0dRcZNkALrV+YEozINTW8X1nM//e5O3L+rfYuvSW00lmGHnYmUjARZulD8F2V8ISI9RA==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^2.2.0" + } + }, + "node_modules/electron-squirrel-startup/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/electron-squirrel-startup/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.340", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.340.tgz", + "integrity": "sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==", + "dev": true, + "license": "ISC" + }, + "node_modules/electron-vite": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/electron-vite/-/electron-vite-3.1.0.tgz", + "integrity": "sha512-M7aAzaRvSl5VO+6KN4neJCYLHLpF/iWo5ztchI/+wMxIieDZQqpbCYfaEHHHPH6eupEzfvZdLYdPdmvGqoVe0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.26.10", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "cac": "^6.7.14", + "esbuild": "^0.25.1", + "magic-string": "^0.30.17", + "picocolors": "^1.1.1" + }, + "bin": { + "electron-vite": "bin/electron-vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@swc/core": "^1.0.0", + "vite": "^4.0.0 || ^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + } + } + }, + "node_modules/electron-winstaller": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.4.0.tgz", + "integrity": "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@electron/asar": "^3.2.1", + "debug": "^4.1.1", + "fs-extra": "^7.0.1", + "lodash": "^4.17.21", + "temp": "^0.9.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "@electron/windows-sign": "^1.1.2" + } + }, + "node_modules/electron-winstaller/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/electron-winstaller/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-winstaller/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/electron/node_modules/@electron/get": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.14.1.tgz", + "integrity": "sha512-BrZYyL/6m0ZXz/lDxy/nlVhQz+WF+iPS6qXolEU8atw7h6v1aYkjwJZ63m+bJMBTxDE66X+r2tPS4a/8C82sZw==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^9.6.0", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=8.6" + }, + "optionalDependencies": { + "global-agent": "^3.0.0", + "global-tunnel-ng": "^2.7.1" + } + }, + "node_modules/electron/node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/electron/node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "license": "MIT", + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/electron/node_modules/@types/node": { + "version": "16.18.126", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.126.tgz", + "integrity": "sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==", + "license": "MIT" + }, + "node_modules/electron/node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/electron/node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/electron/node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "license": "MIT" + }, + "node_modules/electron/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/electron/node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/electron/node_modules/got/node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/electron/node_modules/got/node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron/node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", + "license": "MIT" + }, + "node_modules/electron/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron/node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/electron/node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/electron/node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/electron/node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "license": "MIT", + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/electron/node_modules/responselike/node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/electron/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "license": "MIT", + "optional": true + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/exceljs": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz", + "integrity": "sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver": "^5.0.0", + "dayjs": "^1.8.34", + "fast-csv": "^4.3.1", + "jszip": "^3.10.1", + "readable-stream": "^3.6.0", + "saxes": "^5.0.1", + "tmp": "^0.2.0", + "unzipper": "^0.10.11", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extsprintf": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", + "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "optional": true + }, + "node_modules/fast-csv": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz", + "integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fast-csv/format": "4.3.5", + "@fast-csv/parse": "4.3.6" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.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-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/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/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flora-colossus": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flora-colossus/-/flora-colossus-2.0.0.tgz", + "integrity": "sha512-dz4HxH6pOvbUzZpZ/yXhafjbR2I8cenK5xL0KtBFb7U2ADsR+OwXifnxZjij/pZWF775uSCMzWVd+jDik2H2IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "fs-extra": "^10.1.0" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "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/fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fstream/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fstream/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/fstream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fstream/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/fstream/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/fstream/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "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/galactus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/galactus/-/galactus-1.0.0.tgz", + "integrity": "sha512-R1fam6D4CyKQGNlvJne4dkNF+PvUUl7TAJInvTGa9fti9qAv95quQz29GXapA4d8Ec266mJJxFVh82M4GIIGDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "flora-colossus": "^2.0.0", + "fs-extra": "^10.1.0" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/gar": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/gar/-/gar-1.0.4.tgz", + "integrity": "sha512-w4n9cPWyP7aHxKxYHFQMegj7WIAsL/YX/C4Bs5Rr8s1H9M1rNtRWRsw+ovYMkXDQ5S4ZbYHsHAPmevPjPgw44w==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-folder-size": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/get-folder-size/-/get-folder-size-2.0.1.tgz", + "integrity": "sha512-+CEb+GDCM7tkOS2wdMKTn9vU7DgnKUTuDlehkNJKNSovdCOVxs14OfKCk4cvSaR3za4gj+OBdl9opPN9xrJ0zA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "gar": "^1.0.4", + "tiny-each-async": "2.0.3" + }, + "bin": { + "get-folder-size": "bin/get-folder-size" + } + }, + "node_modules/get-installed-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/get-installed-path/-/get-installed-path-2.1.1.tgz", + "integrity": "sha512-Qkn9eq6tW5/q9BDVdMpB8tOHljX9OSP0jRC5TRNVA4qRc839t4g8KQaR8t0Uv0EFVL0MlyG7m/ofjEgAROtYsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-modules": "1.0.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-info": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-package-info/-/get-package-info-1.0.0.tgz", + "integrity": "sha512-SCbprXGAPdIhKAXiG+Mk6yeoFH61JlYunqdFQFHDtLjJlDjFf6x07dsS8acO+xWt52jpdVo49AlVDnUVK1sDNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "^3.1.1", + "debug": "^2.2.0", + "lodash.get": "^4.0.0", + "read-pkg-up": "^2.0.0" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/get-package-info/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/get-package-info/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/global-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/global-tunnel-ng": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz", + "integrity": "sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "encodeurl": "^1.0.2", + "lodash": "^4.17.10", + "npm-conf": "^1.1.3", + "tunnel": "^0.0.6" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/husky": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-corefoundation": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", + "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "cli-truncate": "^2.1.0", + "node-addon-api": "^1.6.3" + }, + "engines": { + "node": "^8.11.2 || >=10" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true, + "license": "ISC" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ip-address": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "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.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isbinaryfile": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.7.tgz", + "integrity": "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/joi": { + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC", + "optional": true + }, + "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/jsonc-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz", + "integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/junk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz", + "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/keyboardevent-from-electron-accelerator": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/keyboardevent-from-electron-accelerator/-/keyboardevent-from-electron-accelerator-2.0.0.tgz", + "integrity": "sha512-iQcmNA0M4ETMNi0kG/q0h/43wZk7rMeKYrXP7sqKIJbHkTU8Koowgzv+ieR/vWJbOwxx5nDC3UnudZ0aLSu4VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyboardevents-areequal": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/keyboardevents-areequal/-/keyboardevents-areequal-0.2.2.tgz", + "integrity": "sha512-Nv+Kr33T0mEjxR500q+I6IWisOQ0lK1GGOncV0kWE6n4KFmpcu7RUX5/2B0EUtX51Cb0HjZ9VJsSY3u4cBa0kw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lazy-val": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", + "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/linkify-it": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz", + "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/lint-staged": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.3.0.tgz", + "integrity": "sha512-mPRtrYnipYYv1FEE134ufbWpeggNTo+O/UPzngoaKzbzHAthvR55am+8GfHTnqNRQVRRrYQLGW9ZyUoD7DsBHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "5.3.0", + "commander": "11.0.0", + "debug": "4.3.4", + "execa": "7.2.0", + "lilconfig": "2.1.0", + "listr2": "6.6.1", + "micromatch": "4.0.5", + "pidtree": "0.6.0", + "string-argv": "0.3.2", + "yaml": "2.3.1" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/ansi-escapes": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", + "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^1.0.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/commander": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", + "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/lint-staged/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/lint-staged/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lint-staged/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/listr2": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-6.6.1.tgz", + "integrity": "sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^3.1.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^5.0.1", + "rfdc": "^1.3.0", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/lint-staged/node_modules/log-update": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", + "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^5.0.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^5.0.0", + "strip-ansi": "^7.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/lint-staged/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lint-staged/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lint-staged/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/yaml": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", + "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 14" + } + }, + "node_modules/listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/listr2": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-5.0.8.tgz", + "integrity": "sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.19", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.8.0", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha512-3p6ZOGNbiX4CdvEd1VcE6yi78UrGNpjHO33noGwHCnT/o2fyllJDepsm8+mFFv/DvtwFHht5HIHSyOy5a+ChVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.groupby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", + "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isnil": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", + "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isundefined": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", + "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "license": "ISC", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/make-fetch-happen/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-defer": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/markdown-it": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz", + "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "~3.0.1", + "linkify-it": "^4.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdownlint": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.26.2.tgz", + "integrity": "sha512-2Am42YX2Ex5SQhRq35HxYWDfz1NLEOZWWN25nqd2h3AHRKsGRE+Qg1gt1++exW792eXTrR4jCNHfShfWk9Nz8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "markdown-it": "13.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/markdownlint-cli": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.32.2.tgz", + "integrity": "sha512-xmJT1rGueUgT4yGNwk6D0oqQr90UJ7nMyakXtqjgswAkEhYYqjHew9RY8wDbOmh2R270IWjuKSeZzHDEGPAUkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "~9.4.0", + "get-stdin": "~9.0.0", + "glob": "~8.0.3", + "ignore": "~5.2.0", + "js-yaml": "^4.1.0", + "jsonc-parser": "~3.1.0", + "markdownlint": "~0.26.2", + "markdownlint-rule-helpers": "~0.17.2", + "minimatch": "~5.1.0", + "run-con": "~1.2.11" + }, + "bin": { + "markdownlint": "markdownlint.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/markdownlint-cli/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/markdownlint-cli/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/markdownlint-cli/node_modules/commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/markdownlint-cli/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/markdownlint-cli/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/markdownlint-rule-helpers": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/markdownlint-rule-helpers/-/markdownlint-rule-helpers-0.17.2.tgz", + "integrity": "sha512-XaeoW2NYSlWxMCZM2B3H7YTG6nlaLfkEZWMBhr4hSPlq9MuY2sy83+Xr89jXOqZMZYjvi5nBCGoFh7hHoPKZmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "license": "MIT", + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/mem/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "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/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.7.tgz", + "integrity": "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "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/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-abi": { + "version": "3.89.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.89.0.tgz", + "integrity": "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-api-version": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.1.tgz", + "integrity": "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp": { + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-11.5.0.tgz", + "integrity": "sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^14.0.3", + "nopt": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "tar": "^7.4.3", + "tinyglobby": "^0.2.12", + "which": "^5.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/@npmcli/fs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-4.0.0.tgz", + "integrity": "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/abbrev": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", + "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-gyp/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/node-gyp/node_modules/cacache": { + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", + "integrity": "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^4.0.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^12.0.0", + "tar": "^7.4.3", + "unique-filename": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/node-gyp/node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/node-gyp/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/node-gyp/node_modules/make-fetch-happen": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", + "integrity": "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/agent": "^3.0.0", + "cacache": "^19.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^4.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "ssri": "^12.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/node-gyp/node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/node-gyp/node_modules/minipass-fetch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-4.0.1.tgz", + "integrity": "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^3.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/node-gyp/node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/node-gyp/node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-gyp/node_modules/nopt": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^3.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/node-gyp/node_modules/proc-log": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", + "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/ssri": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", + "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/tar": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.13.tgz", + "integrity": "sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-gyp/node_modules/unique-filename": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-4.0.0.tgz", + "integrity": "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/unique-slug": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-5.0.0.tgz", + "integrity": "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/node-releases": { + "version": "2.0.37", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", + "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nodemon/node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/nodemon/node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "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/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "license": "MIT", + "optional": true, + "dependencies": { + "config-chain": "^1.1.11", + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-conf/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/parse-author": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-author/-/parse-author-2.0.0.tgz", + "integrity": "sha512-yx5DfvkN8JsHL2xk2Os9oTia467qnvRgey4ahSm2X8epehBLx/gWLcy5KI+Y36ful5DzGbCS6RazqZGgy1gHNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "author-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pe-library": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/pe-library/-/pe-library-0.4.1.tgz", + "integrity": "sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jet2jet" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, + "node_modules/phosphor-react": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/phosphor-react/-/phosphor-react-1.4.1.tgz", + "integrity": "sha512-gO5j7U0xZrdglTAYDYPACU4xDOFBTJmptrrB/GeR+tHhCZF3nUMyGmV/0hnloKjuTrOmpSFlbfOY78H39rgjUQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16" + } + }, + "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/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "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/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/plist": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", + "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/postcss": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "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.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postject": { + "version": "1.0.0-alpha.6", + "resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz", + "integrity": "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "commander": "^9.4.0" + }, + "bin": { + "postject": "dist/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/postject/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/proc-log": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "license": "ISC", + "optional": true + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rcedit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/rcedit/-/rcedit-3.1.0.tgz", + "integrity": "sha512-WRlRdY1qZbu1L11DklT07KuHfRk42l0NFFJdaExELEu4fEQ982bP5Z6OWGPj/wLLIuKRQDCxZJGAwoFsxhZhNA==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn-windows-exe": "^1.1.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "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/react-router": { + "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.3.tgz", + "integrity": "sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.3.tgz", + "integrity": "sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.2", + "react-router": "6.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/read-binary-file-arch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", + "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "bin": { + "read-binary-file-arch": "cli.js" + } + }, + "node_modules/read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha512-eFIBOPW7FGjzBuk3hdXEuNSiTZS/xEMlH49HxMyzb0hyPfu4EhVjT2DH32K1hSSmVq4sebAWnZuuY5auISUTGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha512-1orxQfbWGUiTn9XsPlChs6rLie/AV9jwZTGmu2NZw/CUDJQchXJFYE0Fq5j7+n558T1JhDWLdhyd1Zj+wLY//w==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "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/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/regex-escape": { + "version": "3.4.11", + "resolved": "https://registry.npmjs.org/regex-escape/-/regex-escape-3.4.11.tgz", + "integrity": "sha512-051l4Hl/0HoJwTvNztrWVjoxLiseSfCrDgWqwR1cnGM/nyQSeIjmvti5zZ7HzOmsXDPaJ2k0iFxQ6/WNpJD5wQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resedit": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/resedit/-/resedit-1.7.2.tgz", + "integrity": "sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pe-library": "^0.4.1" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jet2jet" + } + }, + "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/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-package": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-package/-/resolve-package-1.0.1.tgz", + "integrity": "sha512-rzB7NnQpOkPHBWFPP3prUMqOP6yg3HkRGgcvR+lDyvyHoY3fZLFLYDkPXh78SPVBAE6VTCk/V+j8we4djg6o4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-installed-path": "^2.0.3" + }, + "engines": { + "node": ">=4", + "npm": ">=2" + } + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "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/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/rollup": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", + "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.1", + "@rollup/rollup-android-arm64": "4.60.1", + "@rollup/rollup-darwin-arm64": "4.60.1", + "@rollup/rollup-darwin-x64": "4.60.1", + "@rollup/rollup-freebsd-arm64": "4.60.1", + "@rollup/rollup-freebsd-x64": "4.60.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", + "@rollup/rollup-linux-arm-musleabihf": "4.60.1", + "@rollup/rollup-linux-arm64-gnu": "4.60.1", + "@rollup/rollup-linux-arm64-musl": "4.60.1", + "@rollup/rollup-linux-loong64-gnu": "4.60.1", + "@rollup/rollup-linux-loong64-musl": "4.60.1", + "@rollup/rollup-linux-ppc64-gnu": "4.60.1", + "@rollup/rollup-linux-ppc64-musl": "4.60.1", + "@rollup/rollup-linux-riscv64-gnu": "4.60.1", + "@rollup/rollup-linux-riscv64-musl": "4.60.1", + "@rollup/rollup-linux-s390x-gnu": "4.60.1", + "@rollup/rollup-linux-x64-gnu": "4.60.1", + "@rollup/rollup-linux-x64-musl": "4.60.1", + "@rollup/rollup-openbsd-x64": "4.60.1", + "@rollup/rollup-openharmony-arm64": "4.60.1", + "@rollup/rollup-win32-arm64-msvc": "4.60.1", + "@rollup/rollup-win32-ia32-msvc": "4.60.1", + "@rollup/rollup-win32-x64-gnu": "4.60.1", + "@rollup/rollup-win32-x64-msvc": "4.60.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-con": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.2.12.tgz", + "integrity": "sha512-5257ILMYIF4RztL9uoZ7V9Q97zHtNHn5bN3NobeAnzB1P3ASLgg8qocM2u+R18ttp+VEM78N2LK8XcNVtnSRrg==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~3.0.0", + "minimist": "^1.2.8", + "strip-json-comments": "~3.1.1" + }, + "bin": { + "run-con": "cli.js" + } + }, + "node_modules/run-con/node_modules/ini": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", + "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sanitize-filename": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.4.tgz", + "integrity": "sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg==", + "dev": true, + "license": "WTFPL OR ISC", + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "license": "MIT", + "optional": true + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "license": "MIT", + "optional": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-error/node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "license": "(MIT OR CC0-1.0)", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "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/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spawn-command": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", + "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", + "dev": true + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/stat-mode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", + "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-outer/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/sudo-prompt": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/sudo-prompt/-/sudo-prompt-9.2.1.tgz", + "integrity": "sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT" + }, + "node_modules/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/temp": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", + "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mkdirp": "^0.5.1", + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/temp-file": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", + "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-exit-hook": "^2.0.1", + "fs-extra": "^10.0.0" + } + }, + "node_modules/temp/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/temp/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/temp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/temp/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/temp/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/temp/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tiny-async-pool": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz", + "integrity": "sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^5.5.0" + } + }, + "node_modules/tiny-async-pool/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tiny-each-async": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tiny-each-async/-/tiny-each-async-2.0.3.tgz", + "integrity": "sha512-5ROII7nElnAirvFn8g7H7MtpfV1daMcyfTGQwsn/x2VtyV+VPiO5CjReCJtWLvoKTDEDmZocf3cNPraiMnBXLA==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "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.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tmp": "^0.2.0" + } + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", + "dev": true, + "license": "MIT/X11", + "engines": { + "node": "*" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/trim-repeated/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unzip-crx-3": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/unzip-crx-3/-/unzip-crx-3-0.2.0.tgz", + "integrity": "sha512-0+JiUq/z7faJ6oifVB5nSwt589v1KCduqIJupNVDoWSXZtWDmjDGO3RAEOvwJ07w90aoXoP4enKsR7ecMrJtWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "jszip": "^3.1.0", + "mkdirp": "^0.5.1", + "yaku": "^0.16.6" + } + }, + "node_modules/unzip-crx-3/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/unzipper": { + "version": "0.10.14", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", + "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "node_modules/unzipper/node_modules/bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/unzipper/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/unzipper/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/unzipper/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", + "license": "MIT", + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/username": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/username/-/username-5.1.0.tgz", + "integrity": "sha512-PCKbdWw85JsYMvmCv5GH3kXmM66rCd9m1hBEDutPNv94b/pqCMT4NtcKyeWYvLFiE8b+ha1Jdl8XAaUdPn5QTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^1.0.0", + "mem": "^4.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/username/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/username/node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/username/node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/username/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/username/node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/username/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/username/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/username/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/username/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/username/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/utf8-byte-length": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", + "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "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/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/verror": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", + "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/vite": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.2.tgz", + "integrity": "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.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 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/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/vite/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/wait-on": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", + "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "axios": "^0.25.0", + "joi": "^17.6.0", + "lodash": "^4.17.21", + "minimist": "^1.2.5", + "rxjs": "^7.5.4" + }, + "bin": { + "wait-on": "bin/wait-on" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/wait-on/node_modules/axios": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", + "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.14.7" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaku": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/yaku/-/yaku-0.16.7.tgz", + "integrity": "sha512-Syu3IB3rZvKvYk7yTiyl1bo/jiEFaaStrgv1V2TIJTqYPStSMQVO8EQjg/z+DRzLq/4LIIharNT3iH1hylEIRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yarn-or-npm": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/yarn-or-npm/-/yarn-or-npm-3.0.1.tgz", + "integrity": "sha512-fTiQP6WbDAh5QZAVdbMQkecZoahnbOjClTQhzv74WX5h2Uaidj1isf9FDes11TKtsZ0/ZVfZsqZ+O3x6aLERHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^6.0.5", + "pkg-dir": "^4.2.0" + }, + "bin": { + "yarn-or-npm": "bin/index.js", + "yon": "bin/index.js" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/yarn-or-npm/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/yarn-or-npm/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/yarn-or-npm/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/yarn-or-npm/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yarn-or-npm/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yarn-or-npm/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zip-stream": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", + "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver-utils": "^3.0.4", + "compress-commons": "^4.1.2", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/archiver-utils": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", + "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^7.2.3", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/zip-stream/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/zip-stream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/zip-stream/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zustand": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.12.tgz", + "integrity": "sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + } + } +} diff --git a/src/renderer/src/components/audio-player/index.tsx b/src/renderer/src/components/audio-player/index.tsx index 356511f0..d80682c9 100644 --- a/src/renderer/src/components/audio-player/index.tsx +++ b/src/renderer/src/components/audio-player/index.tsx @@ -1,16 +1,17 @@ -import React, { - forwardRef, - useCallback, - useImperativeHandle, - useRef, - useState, -} from "react"; import { ArrowClockwise, ArrowCounterClockwise, Pause, Play, } from "phosphor-react"; +import type React from "react"; +import { + forwardRef, + useCallback, + useImperativeHandle, + useRef, + useState, +} from "react"; import { styled } from "@/styles"; import { formatTime } from "./formatTime"; @@ -242,11 +243,11 @@ const AudioPlayer = forwardRef( [durationMs, onTimeUpdate], ); - const fillPercent = - durationMs > 0 ? (currentMs / durationMs) * 100 : 0; + const fillPercent = durationMs > 0 ? (currentMs / durationMs) * 100 : 0; return ( + {/* biome-ignore lint/a11y/useMediaCaption: programmatic audio player, captions not applicable */}
- - + + + +
); diff --git a/src/renderer/src/components/finish/finish-main-content.tsx b/src/renderer/src/components/finish/finish-main-content.tsx index 79a1f13d..96511c5c 100644 --- a/src/renderer/src/components/finish/finish-main-content.tsx +++ b/src/renderer/src/components/finish/finish-main-content.tsx @@ -25,10 +25,12 @@ export default function FinishMainContent({
- {t("finish.subtitle")} - - {children} - + + {t("finish.subtitle")} + + {children} + + From 7c1db9562b067f49ffa21e3607019200bbd7696f Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 19 Apr 2026 22:26:52 -0300 Subject: [PATCH 114/263] add checked variant to button --- src/renderer/src/components/ui/button.tsx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/renderer/src/components/ui/button.tsx b/src/renderer/src/components/ui/button.tsx index 5e00321d..49c991be 100644 --- a/src/renderer/src/components/ui/button.tsx +++ b/src/renderer/src/components/ui/button.tsx @@ -1,4 +1,4 @@ -import { type RecipeVariantProps, css, cva } from "@/styled/css"; +import { type RecipeVariantProps, css, cva, cx } from "@/styled/css"; import { CircleNotch } from "phosphor-react"; import type { ButtonHTMLAttributes } from "react"; @@ -8,7 +8,6 @@ const button = cva({ flexDir: "row", gap: "1", // 4px justifyContent: "center", - alignSelf: "stretch", alignItems: "center", transitionProperty: "[background-color, color, box-shadow]", @@ -105,10 +104,18 @@ const button = cva({ }, "icon-sm": { height: "9", width: "9", padding: "2", rounded: "md" }, }, + checked: { + true: { + bg: "action.pressed !important", + color: "text.onbutton-alternative !important", + }, + false: {}, + }, }, defaultVariants: { size: "md", variant: "primary", + checked: false, }, }); @@ -123,12 +130,14 @@ function Button({ isLoading, disabled, children, + className, + checked, ...props }: ButtonProps) { return ( + + ); +} + + +export default Toast; diff --git a/src/renderer/src/features/showToast.tsx b/src/renderer/src/features/showToast.tsx new file mode 100644 index 00000000..711c50b2 --- /dev/null +++ b/src/renderer/src/features/showToast.tsx @@ -0,0 +1,6 @@ +import Toast, { type ToastVariant } from "@/components/ui/toast"; +import { toast } from "react-hot-toast"; + +export function showToast(message: string, variant: ToastVariant = "info") { + toast.custom((t) => ); +} From 03954d74ede9e374a1918db30c3de79f93c6d853 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 19 Apr 2026 23:12:50 -0300 Subject: [PATCH 118/263] create callout from toast, and then apply a11y to toast --- src/renderer/src/components/ui/callout.tsx | 67 ++++++++++++++++++++++ src/renderer/src/components/ui/toast.tsx | 65 +++++---------------- 2 files changed, 81 insertions(+), 51 deletions(-) create mode 100644 src/renderer/src/components/ui/callout.tsx diff --git a/src/renderer/src/components/ui/callout.tsx b/src/renderer/src/components/ui/callout.tsx new file mode 100644 index 00000000..e58655d6 --- /dev/null +++ b/src/renderer/src/components/ui/callout.tsx @@ -0,0 +1,67 @@ +import { cva, cx } from "@/styled/css"; +import { Bell, X } from "phosphor-react"; +import type { HTMLAttributes } from "react"; + +const calloutRecipe = cva({ + base: { + display: "flex", + flexDir: "row", + alignItems: "center", + gap: "3", + px: "4", + py: "3", + rounded: "lg", + borderWidth: "[1px]", + borderStyle: "solid", + width: "[360px]", + textStyle: "paragraph.sm.default", + color: "text.default", + }, + variants: { + variant: { + error: { + bg: "system.error-secondary", + borderColor: "system.error", + }, + warning: { + bg: "system.warning-secondary", + borderColor: "system.warning", + }, + success: { + bg: "system.success-secondary", + borderColor: "system.success", + }, + info: { + bg: "system.info-secondary", + borderColor: "[#BCBAB8]", + }, + }, + }, + defaultVariants: { + variant: "info", + }, +}); + +export type CalloutVariant = "error" | "warning" | "success" | "info"; + +interface CalloutProps extends HTMLAttributes { + message: string; + variant?: CalloutVariant; + onDismiss?: () => void; +} + +function Callout({ message, variant = "info", onDismiss, className, ...props }: CalloutProps) { + return ( +
+
+ ); +} + +export default Callout; diff --git a/src/renderer/src/components/ui/toast.tsx b/src/renderer/src/components/ui/toast.tsx index d3804bb4..60687555 100644 --- a/src/renderer/src/components/ui/toast.tsx +++ b/src/renderer/src/components/ui/toast.tsx @@ -1,48 +1,7 @@ -import { cva, cx } from "@/styled/css"; -import { Bell, X } from "phosphor-react"; import { type Toast as HotToast, toast } from "react-hot-toast"; +import Callout, { type CalloutVariant } from "./callout"; -const toastRecipe = cva({ - base: { - display: "flex", - flexDir: "row", - alignItems: "center", - gap: "3", - px: "4", - py: "3", - rounded: "lg", - borderWidth: "[1px]", - borderStyle: "solid", - width: "[360px]", - textStyle: "paragraph.sm.default", - color: "text.default", - }, - variants: { - variant: { - error: { - bg: "system.error-secondary", - borderColor: "system.error", - }, - warning: { - bg: "system.warning-secondary", - borderColor: "system.warning", - }, - success: { - bg: "system.success-secondary", - borderColor: "system.success", - }, - info: { - bg: "system.info-secondary", - borderColor: "[#BCBAB8]", - }, - }, - }, - defaultVariants: { - variant: "info", - }, -}); - -export type ToastVariant = "error" | "warning" | "success" | "info"; +export type ToastVariant = CalloutVariant; interface ToastProps { t: HotToast; @@ -50,17 +9,21 @@ interface ToastProps { variant?: ToastVariant; } +const ASSERTIVE_VARIANTS: ToastVariant[] = ["error", "warning"]; + function Toast({ t, message, variant = "info" }: ToastProps) { + const isAssertive = ASSERTIVE_VARIANTS.includes(variant); + return ( -
- - {message} - -
+ toast.dismiss(t.id)} + role={isAssertive ? "alert" : "status"} + aria-live={isAssertive ? "assertive" : "polite"} + aria-atomic="true" + /> ); } - export default Toast; From 3a9a5cc654be482c8fc2795ef687dd340d51c7e4 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 19 Apr 2026 23:13:22 -0300 Subject: [PATCH 119/263] remove old component implementations --- .../src/components/card-old/index.tsx | 20 ----- .../onboarding-card/OnboardingCard.styles.ts | 48 ---------- .../src/components/onboarding-card/index.tsx | 25 ------ src/renderer/src/layout/main-old/index.ts | 87 ------------------- 4 files changed, 180 deletions(-) delete mode 100644 src/renderer/src/components/card-old/index.tsx delete mode 100644 src/renderer/src/components/onboarding-card/OnboardingCard.styles.ts delete mode 100644 src/renderer/src/components/onboarding-card/index.tsx delete mode 100644 src/renderer/src/layout/main-old/index.ts diff --git a/src/renderer/src/components/card-old/index.tsx b/src/renderer/src/components/card-old/index.tsx deleted file mode 100644 index 87a81176..00000000 --- a/src/renderer/src/components/card-old/index.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { styled } from "@/styles"; - -/** - * @deprecated - */ -const Card = styled("div", { - display: "flex", - flexDirection: "column", - alignItems: "flex-start", - gap: "$xl", - - p: "$xl", - - bg: "$bgSecondary", - b: "1px solid $borderPrimary", - borderRadius: "$xxs", - boxShadow: "0px 4px 20px rgba(0, 0, 0, 0.05)", -}); - -export default Card; diff --git a/src/renderer/src/components/onboarding-card/OnboardingCard.styles.ts b/src/renderer/src/components/onboarding-card/OnboardingCard.styles.ts deleted file mode 100644 index 57ab1c5f..00000000 --- a/src/renderer/src/components/onboarding-card/OnboardingCard.styles.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Card as BaseCard } from "@/components"; -import { styled } from "@/styles"; - -/** - * Styled card, containing step, image and description - */ -export const StyledCard = styled(BaseCard, { - justifyContent: "center", - alignItems: "center", - textAlign: "center", - gap: "$m", - - position: "relative", - - px: "$m", - pt: "$l", - pb: "$xl", - maxWidth: 200, - "@md": { - pt: "$xxl", - maxWidth: 160, - }, - "@lg": { - pt: "$l", - maxWidth: 200, - }, -}); - -/** - * Step indicator on Onboarding cards - */ -export const Step = styled("span", { - bg: "$actionDefaultAlt", - color: "$textOnButtonAlternative", - - position: "absolute", - top: "$m", - - borderRadius: "100%", - width: 36, - height: 36, - mb: "-$m", - - alignSelf: "end", - display: "flex", - justifyContent: "center", - alignItems: "center", -}); diff --git a/src/renderer/src/components/onboarding-card/index.tsx b/src/renderer/src/components/onboarding-card/index.tsx deleted file mode 100644 index 190fae3c..00000000 --- a/src/renderer/src/components/onboarding-card/index.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Text } from "@/components"; - -import * as S from "./OnboardingCard.styles"; - -interface Props { - step: number; - text: string; -} -/** - * @param step Current step, used to refer to an image on `/public` - * @param text Text used to describe current step - */ -export function OnboardingCard({ step = 1, text }: Props) { - return ( - - {step} - {`Step - {text} - - ); -} diff --git a/src/renderer/src/layout/main-old/index.ts b/src/renderer/src/layout/main-old/index.ts deleted file mode 100644 index 4fe431ab..00000000 --- a/src/renderer/src/layout/main-old/index.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { styled } from "@/styles"; - -/** - * @deprecated - */ -export const Layout = styled("main", { - height: "100vh", - - display: "flex", - flexDirection: "column", -}); - -/** - * @deprecated - */ -export const Header = styled("header", { - display: "flex", - flexDirection: "row", - justifyContent: "space-between", - alignItems: "center", - - zIndex: 2, - px: "$xl", - py: "$l", - gap: 10, - - bg: "$white", - bb: "1px solid $borderPrimary", - - "@xl": { - px: 150, - }, -}); - -/** - * @deprecated - */ -export const Section = styled("section", { - px: 40, - py: "$xxl", - flex: 1, - - display: "flex", - flexDirection: "column", - gap: "$m", - - bg: "$bgPrimary", - "@xl": { - px: 150, - }, - variants: { - spacing: { - none: { gap: 0 }, - xxs: { gap: "$xxs" }, - xs: { gap: "$xs" }, - s: { gap: "$s" }, - m: { gap: "$m" }, - l: { gap: "$l" }, - xl: { gap: "$xl" }, - xxl: { gap: "$xxl" }, - }, - }, - defaultVariants: { - spacing: "m", - }, -}); - -/** - * @deprecated - */ -export const Footer = styled("nav", { - display: "flex", - flexDirection: "row", - justifyContent: "flex-end", - alignItems: "center", - gap: "$m", - - zIndex: 1, - - py: "$l", - px: 100, - height: 100, - - bt: "1px solid $borderPrimary", - - bg: "$bgSecondary", -}); From c28fdcd0cad12ff437d4f2556a5c6613d9254659 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 20 Apr 2026 00:30:44 -0300 Subject: [PATCH 120/263] fix title in process copy etxt --- src/renderer/src/constants/i18n/locales/es/dataset.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/src/constants/i18n/locales/es/dataset.ts b/src/renderer/src/constants/i18n/locales/es/dataset.ts index 6364809f..de2dc4a9 100644 --- a/src/renderer/src/constants/i18n/locales/es/dataset.ts +++ b/src/renderer/src/constants/i18n/locales/es/dataset.ts @@ -26,7 +26,7 @@ const dataset = { }, }, process: { - sectionTitle: "2. Procesamiento de los archivos", + sectionTitle: "2. Extracción de datos", processingTitle: "AymurAI está extrayendo los datos de los archivos", processingSubtitle: "Este proceso puede tardar algunos minutos.", finishText: "Se finalizó el análisis de tus documentos.", From 1cfba9c400ae6650025ae7120874bbb3ccb5b46a Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 20 Apr 2026 00:31:04 -0300 Subject: [PATCH 121/263] adjust callout styling --- src/renderer/src/components/index.ts | 7 --- src/renderer/src/components/ui/callout.tsx | 50 +++++++++++++++++----- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/renderer/src/components/index.ts b/src/renderer/src/components/index.ts index 83aa71cc..1ba0ac0b 100644 --- a/src/renderer/src/components/index.ts +++ b/src/renderer/src/components/index.ts @@ -1,5 +1,4 @@ export { default as Arrow } from "./arrow"; -export { default as Card } from "./card-old"; export { Checkbox, CheckboxGroup } from "./checkbox"; export { default as DecisionTabs } from "./decision-tabs"; export { default as FileAnnotator } from "./file-annotator"; @@ -7,11 +6,8 @@ export { default as FileCheck } from "./file-check"; export { default as FilePreview } from "./file-preview"; export { default as FileProcessing } from "./file-processing"; export { default as FileStepper } from "./file-stepper"; -export { FinishAnonymizer } from "./finish-anonymizer"; -export { FinishDataset } from "./finish-dataset"; export { default as Grid } from "./grid"; export { default as Label } from "./label"; -export { OnboardingCard } from "./onboarding-card"; export { OnboardingGrid } from "./onboarding-grid"; export { default as ProfileInfo } from "./profile-info"; export { Radio, RadioGroup } from "./radio"; @@ -20,13 +16,10 @@ export { default as Select } from "./select"; export { default as Spinner } from "./spinner"; export { default as Stack } from "./stack"; export { default as Subtitle } from "./subtitle"; -export { default as Suggestion } from "./suggestion"; export { Tab, TabName } from "./tabs"; export { default as Text } from "./text"; export { default as ThemeProvider } from "./theme-provider"; export { default as Title } from "./title"; -export { default as Toast } from "./toast"; -export { default as Tooltip } from "./tooltip-old"; export { default as Button } from "./ui/button"; export { default as Input } from "./uncontrolled-input"; export { ValidateDataset } from "./validate-dataset"; diff --git a/src/renderer/src/components/ui/callout.tsx b/src/renderer/src/components/ui/callout.tsx index e58655d6..e91d3917 100644 --- a/src/renderer/src/components/ui/callout.tsx +++ b/src/renderer/src/components/ui/callout.tsx @@ -1,19 +1,24 @@ import { cva, cx } from "@/styled/css"; +import { hstack } from "@/styled/patterns"; import { Bell, X } from "phosphor-react"; import type { HTMLAttributes } from "react"; const calloutRecipe = cva({ base: { - display: "flex", - flexDir: "row", - alignItems: "center", - gap: "3", + ...hstack.raw({ + alignItems: "center", + gap: "3", + }), + px: "4", py: "3", - rounded: "lg", + + rounded: "sm", borderWidth: "[1px]", borderStyle: "solid", - width: "[360px]", + + width: "full", + textStyle: "paragraph.sm.default", color: "text.default", }, @@ -33,12 +38,18 @@ const calloutRecipe = cva({ }, info: { bg: "system.info-secondary", - borderColor: "[#BCBAB8]", + borderColor: "system.info", + }, + }, + noBorder: { + true: { + borderWidth: "0", }, }, }, defaultVariants: { variant: "info", + noBorder: false, }, }); @@ -47,16 +58,33 @@ export type CalloutVariant = "error" | "warning" | "success" | "info"; interface CalloutProps extends HTMLAttributes { message: string; variant?: CalloutVariant; + noBorder?: boolean; onDismiss?: () => void; } -function Callout({ message, variant = "info", onDismiss, className, ...props }: CalloutProps) { +function Callout({ + message, + variant = "info", + noBorder = false, + onDismiss, + className, + ...props +}: CalloutProps) { return ( -
-
); } -function changeExtension(name: string) { +function triggerDownload(blob: Blob, fileName: string) { + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + link.download = fileName; + link.click(); + URL.revokeObjectURL(url); +} + +function changeExtension(name: string, ext = "odt") { const parts = name.split("."); parts.pop(); - return `${[...parts].join(".")}_anonimizado.odt`; + return `${parts.join(".")}_anonimizado.${ext}`; } diff --git a/src/renderer/src/services/aymurai/queries.ts b/src/renderer/src/services/aymurai/queries.ts index a3a91631..d8a4b883 100644 --- a/src/renderer/src/services/aymurai/queries.ts +++ b/src/renderer/src/services/aymurai/queries.ts @@ -1,7 +1,7 @@ import { disambiguateSchema } from "@/schema/disambiguate"; import type { PredictLabel, Workflows } from "@/types/aymurai"; import type { DocFile, Paragraph } from "@/types/file"; -import { queryOptions } from "@tanstack/react-query"; +import { mutationOptions, queryOptions } from "@tanstack/react-query"; import api from "../api"; import predict from "./predict"; @@ -68,7 +68,7 @@ export const anonymize = (file: DocFile) => return response.data; }, - select: (data) => URL.createObjectURL(data), + // select: (data) => URL.createObjectURL(data), }); export const disambiguate = (file: DocFile) => @@ -116,3 +116,25 @@ export const disambiguate = (file: DocFile) => }); }, }); + +export const odtToPdf = () => + mutationOptions({ + mutationFn: async (file: Blob) => { + const formData = new FormData(); + formData.append("file", file, "document.odt"); + + const response = await api.post( + "/convert/odt/pdf", + formData, + { + headers: { + "Content-Type": "multipart/form-data", + Accept: "application/octet-stream", + }, + responseType: "blob", + }, + ); + + return response.data; + }, + }); From 6edd7101b39f3644ef03db173341fd2f136a9811 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 25 Apr 2026 18:13:04 -0300 Subject: [PATCH 145/263] update tanstack react query version --- package.json | 2 +- pnpm-lock.yaml | 88 +++++++++++++++++++++++++++----------------------- 2 files changed, 49 insertions(+), 41 deletions(-) diff --git a/package.json b/package.json index a18094db..df8d99c2 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "@radix-ui/react-tooltip": "^1.2.8", "@stitches/react": "^1.2.8", "@tanstack/react-form": "1.11.0", - "@tanstack/react-query": "^5.81.1", + "@tanstack/react-query": "^5.100.5", "@tanstack/react-router": "^1.139.12", "@tanstack/react-router-devtools": "^1.139.12", "@tanstack/router-plugin": "^1.139.12", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 46f12ce8..a23cf505 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -64,8 +64,8 @@ importers: specifier: 1.11.0 version: 1.11.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-query': - specifier: ^5.81.1 - version: 5.81.1(react@19.2.4) + specifier: ^5.100.5 + version: 5.100.5(react@19.2.4) '@tanstack/react-router': specifier: ^1.139.12 version: 1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -1466,8 +1466,8 @@ packages: resolution: {integrity: sha512-l6wcxwDBeh/7Dhles23U1O8lp9kNJmAb2yNjekR6olZwCRNAVA8TCXlVCrueELyFlYZqvQkh0ofxnzG62A1Kkg==} engines: {node: '>=12'} - '@tanstack/query-core@5.81.1': - resolution: {integrity: sha512-MAaygDGHHQlfVPYNT+1ZbnY5KsPhFbffDgdQ0YPVhJQyvLby3btnF0oVk9ZEpKEGfl3hEK7YDnNNFT//iX+s0w==} + '@tanstack/query-core@5.100.5': + resolution: {integrity: sha512-t20KrhKkf0HXzqQkPbJ5erhFesup68BAbwFgYmTrS7bxMF7O5MdmL8jUkik4thsG7Hg00fblz30h6yF1d5TxGg==} '@tanstack/react-form@1.11.0': resolution: {integrity: sha512-jTsTVvRaTLWwdhCAKG0mfrH+/43wudGujwDiRRT09VYxWJeJNFoXqepXW26lY0iuq11a0+A/0lmr2TfVqPanfg==} @@ -1481,8 +1481,8 @@ packages: vinxi: optional: true - '@tanstack/react-query@5.81.1': - resolution: {integrity: sha512-N78EEOq/Y5tqXvbGSE+LaRXU8oqlRU4w/D2Di8VwZrNL/tdvKhD+h5HCJr77MC0nUcil0nnzQpi+nu77t3/Xtg==} + '@tanstack/react-query@5.100.5': + resolution: {integrity: sha512-aNwj1mi2v2bQ9IxkyR1grLOUkv3BYWoykHy9KDyLNbjC3tsahbOHJibK+Wjtr1wRhG59/AvJhiJG5OlthaCgJA==} peerDependencies: react: ^18 || ^19 @@ -1869,6 +1869,9 @@ packages: brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -2499,8 +2502,8 @@ packages: resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} engines: {node: '>=0.10.0'} - exponential-backoff@3.1.2: - resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} express-rate-limit@7.5.1: resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} @@ -2941,8 +2944,8 @@ packages: resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==} engines: {node: '>=10.13.0'} - ip-address@9.0.5: - resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} engines: {node: '>= 12'} ipaddr.js@1.9.1: @@ -3061,9 +3064,6 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - jsbn@1.1.0: - resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} - jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -3456,6 +3456,10 @@ packages: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -3471,8 +3475,8 @@ packages: resolution: {integrity: sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - minipass-flush@1.0.5: - resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} + minipass-flush@1.0.7: + resolution: {integrity: sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==} engines: {node: '>= 8'} minipass-pipeline@1.2.4: @@ -4304,8 +4308,8 @@ packages: resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} engines: {node: '>= 10'} - socks@2.8.4: - resolution: {integrity: sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==} + socks@2.8.7: + resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} solid-js@1.9.10: @@ -5501,7 +5505,7 @@ snapshots: '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': dependencies: env-paths: 2.2.1 - exponential-backoff: 3.1.2 + exponential-backoff: 3.1.3 glob: 8.1.0 graceful-fs: 4.2.11 make-fetch-happen: 10.2.1 @@ -6507,7 +6511,7 @@ snapshots: '@tanstack/history@1.139.0': {} - '@tanstack/query-core@5.81.1': {} + '@tanstack/query-core@5.100.5': {} '@tanstack/react-form@1.11.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: @@ -6519,9 +6523,9 @@ snapshots: transitivePeerDependencies: - react-dom - '@tanstack/react-query@5.81.1(react@19.2.4)': + '@tanstack/react-query@5.100.5(react@19.2.4)': dependencies: - '@tanstack/query-core': 5.81.1 + '@tanstack/query-core': 5.100.5 react: 19.2.4 '@tanstack/react-router-devtools@1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(lightningcss@1.30.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(tsx@4.20.6)': @@ -6811,7 +6815,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.3 + debug: 4.4.1 transitivePeerDependencies: - supports-color @@ -7053,6 +7057,10 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@2.1.0: + dependencies: + balanced-match: 1.0.2 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -7136,7 +7144,7 @@ snapshots: lru-cache: 7.18.3 minipass: 3.3.6 minipass-collect: 1.0.2 - minipass-flush: 1.0.5 + minipass-flush: 1.0.7 minipass-pipeline: 1.2.4 mkdirp: 1.0.4 p-map: 4.0.0 @@ -7830,7 +7838,7 @@ snapshots: dependencies: homedir-polyfill: 1.0.3 - exponential-backoff@3.1.2: {} + exponential-backoff@3.1.3: {} express-rate-limit@7.5.1(express@5.2.1): dependencies: @@ -8159,7 +8167,7 @@ snapshots: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 5.1.6 + minimatch: 5.1.9 once: 1.4.0 global-agent@3.0.0: @@ -8267,7 +8275,7 @@ snapshots: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.4.3 + debug: 4.4.1 transitivePeerDependencies: - supports-color @@ -8286,7 +8294,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.3 + debug: 4.4.1 transitivePeerDependencies: - supports-color @@ -8352,10 +8360,7 @@ snapshots: interpret@3.1.1: {} - ip-address@9.0.5: - dependencies: - jsbn: 1.1.0 - sprintf-js: 1.1.3 + ip-address@10.1.0: {} ipaddr.js@1.9.1: {} @@ -8446,8 +8451,6 @@ snapshots: dependencies: argparse: 2.0.1 - jsbn@1.1.0: {} - jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -8709,7 +8712,7 @@ snapshots: minipass: 3.3.6 minipass-collect: 1.0.2 minipass-fetch: 2.1.2 - minipass-flush: 1.0.5 + minipass-flush: 1.0.7 minipass-pipeline: 1.2.4 negotiator: 0.6.4 promise-retry: 2.0.1 @@ -8819,6 +8822,10 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimatch@5.1.9: + dependencies: + brace-expansion: 2.1.0 + minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 @@ -8837,7 +8844,7 @@ snapshots: optionalDependencies: encoding: 0.1.13 - minipass-flush@1.0.5: + minipass-flush@1.0.7: dependencies: minipass: 3.3.6 @@ -9639,14 +9646,14 @@ snapshots: socks-proxy-agent@7.0.0: dependencies: agent-base: 6.0.2 - debug: 4.4.3 - socks: 2.8.4 + debug: 4.4.1 + socks: 2.8.7 transitivePeerDependencies: - supports-color - socks@2.8.4: + socks@2.8.7: dependencies: - ip-address: 9.0.5 + ip-address: 10.1.0 smart-buffer: 4.2.0 solid-js@1.9.10: @@ -9682,7 +9689,8 @@ snapshots: spdx-license-ids@3.0.21: {} - sprintf-js@1.1.3: {} + sprintf-js@1.1.3: + optional: true ssri@9.0.1: dependencies: From c2c21c21c80051f8850b7374b4d62fcf6d17f6cb Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 25 Apr 2026 18:13:45 -0300 Subject: [PATCH 146/263] add className to SectionTitle --- src/renderer/src/layout/section-title.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/layout/section-title.tsx b/src/renderer/src/layout/section-title.tsx index 59e269ad..26731e61 100644 --- a/src/renderer/src/layout/section-title.tsx +++ b/src/renderer/src/layout/section-title.tsx @@ -2,7 +2,12 @@ import { styled } from "@/styled/jsx"; interface SectionTitleProps { children: React.ReactNode; + className?: string; } -export function SectionTitle({ children }: SectionTitleProps) { - return {children}; +export function SectionTitle({ children, className }: SectionTitleProps) { + return ( + + {children} + + ); } From af457c85df3a7742ee809a2f0dcb25485255f989 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 25 Apr 2026 18:15:13 -0300 Subject: [PATCH 147/263] improve accessibility on host page --- src/renderer/src/components/home/choose-host.tsx | 11 +++++++++-- src/renderer/src/components/layout/main-content.tsx | 4 +--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/renderer/src/components/home/choose-host.tsx b/src/renderer/src/components/home/choose-host.tsx index d17234ee..a98490b8 100644 --- a/src/renderer/src/components/home/choose-host.tsx +++ b/src/renderer/src/components/home/choose-host.tsx @@ -27,8 +27,15 @@ export default function ChooseHost({ onRemoteClick }: ChooseHostProps) { alt="Logotipo AymurAI" width={180} /> - +

{t("home.host.optionLocal")} -

+

{t("home.host.optionOr")}

- - ); -} - -function RouteComponent() { - const { feature } = useParams({ - from: "/app/$feature/process", - }); - - if (feature === FeatureFlowEnum.Dataset) - return ( - - ); - - return ( - + ); } diff --git a/src/renderer/src/routes/app.$feature/validation.tsx b/src/renderer/src/routes/app.$feature/validation.tsx index 0ae183a6..4eb52eb2 100644 --- a/src/renderer/src/routes/app.$feature/validation.tsx +++ b/src/renderer/src/routes/app.$feature/validation.tsx @@ -1,84 +1,68 @@ -import { Button, FileAnnotator, Grid, ValidateDataset } from "@/components"; -import FeaturesMenu from "@/components/features-menu"; -import HowItWorksModal from "@/components/how-it-works-modal"; +import { Button, FileAnnotator, ValidateDataset } from "@/components"; import Stepper from "@/components/home/stepper"; +import Footer from "@/components/layout/footer"; import Header from "@/components/layout/header"; +import RequireFile from "@/features/RequireFile"; import { useFiles } from "@/hooks"; -import { Footer } from "@/layout/main-old"; -import { useTutorialSeen } from "@/store/useLocal"; -import { HStack } from "@/styled/jsx"; -import { FeatureFlowEnum, featureName } from "@/types/features"; +import { Grid } from "@/styled/jsx"; +import { FeatureFlowEnum, featureNamespace } from "@/types/features"; import { createFileRoute, useNavigate, useParams, } from "@tanstack/react-router"; +import { useTranslation } from "react-i18next"; export const Route = createFileRoute("/app/$feature/validation")({ - component: ValidationRoute, + component: RouteComponent, }); -function ValidateAnonymizer() { +function RouteComponent() { const { feature } = useParams({ from: "/app/$feature/validation", }); - const file = useFiles()[0]!; + const navigate = useNavigate(); + const { t } = useTranslation(featureNamespace[feature]); + + const file = useFiles()[0]!; const handleContinue = () => navigate({ to: "/app/$feature/finish", params: { feature } }); - return ( - <> - - - - -
- -
- - ); -} - -function ValidationRoute() { - const { feature } = Route.useParams(); - const tutorialSeen = useTutorialSeen(feature); + if (feature === FeatureFlowEnum.Anonymizer) + return ( + +
} + feature={feature} + /> + + + +
+ +
+ + ); return ( - <> +
- ) : undefined - } - right={ - - {tutorialSeen && } - - - } + title={t("title")} + center={} + feature={feature} /> - {feature === FeatureFlowEnum.Dataset ? ( - - ) : ( - - )} - + + ); } From 5493cdee80e20cd0bef93c0fde7f78fe24600494 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sat, 25 Apr 2026 18:34:24 -0300 Subject: [PATCH 149/263] finish mark and tag annotation feature --- .../src/components/anonymizer/mark/index.tsx | 188 +++++++++++------- .../anonymizer/mark/suggestion-label.tsx | 31 +++ .../src/components/anonymizer/mark/tagger.tsx | 81 -------- .../components/file/annotation-popover.tsx | 9 +- .../file/search-annotation/index.tsx | 46 ++++- .../file/search-annotation/search-tagger.tsx | 22 +- .../components/file/tag-annotation/index.tsx | 141 +++++++++++++ .../file/tag-annotation/remove-dialog.tsx | 37 ++++ .../tag-annotation}/replace-dialog.tsx | 10 +- .../file/tag-annotation/tag-tagger.tsx | 87 ++++++++ .../mark => file}/tagger-button.tsx | 0 11 files changed, 473 insertions(+), 179 deletions(-) create mode 100644 src/renderer/src/components/anonymizer/mark/suggestion-label.tsx delete mode 100644 src/renderer/src/components/anonymizer/mark/tagger.tsx create mode 100644 src/renderer/src/components/file/tag-annotation/index.tsx create mode 100644 src/renderer/src/components/file/tag-annotation/remove-dialog.tsx rename src/renderer/src/components/{anonymizer/mark => file/tag-annotation}/replace-dialog.tsx (74%) create mode 100644 src/renderer/src/components/file/tag-annotation/tag-tagger.tsx rename src/renderer/src/components/{anonymizer/mark => file}/tagger-button.tsx (100%) diff --git a/src/renderer/src/components/anonymizer/mark/index.tsx b/src/renderer/src/components/anonymizer/mark/index.tsx index 6e2bb019..20137a3a 100644 --- a/src/renderer/src/components/anonymizer/mark/index.tsx +++ b/src/renderer/src/components/anonymizer/mark/index.tsx @@ -8,10 +8,16 @@ import { PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; -import Suggestion from "@/components/ui/suggestion"; import { useAnnotation } from "@/context/Annotation"; import { css, cva } from "@/styled/css"; +import type { + AllLabels, + AllLabelsWithSufix, + AnonymizerLabels, +} from "@/types/aymurai"; import { useRef, useState } from "react"; +import ReplaceDialog from "./replace-dialog"; +import SuggestionLabel from "./suggestion-label"; import Tagger from "./tagger"; const triggerReset = css({ @@ -46,20 +52,31 @@ const search = cva({ interface MarkProps { children: string; isAnnotable: boolean; - isSearch: boolean; annotation: Annotation; } -export default function Mark({ - children, - isAnnotable, - isSearch, - annotation, -}: MarkProps) { +export default function Mark({ children, isAnnotable, annotation }: MarkProps) { const [open, setOpen] = useState(false); + const [replaceAllOpen, setReplaceAllOpen] = useState(false); + const [selectedLabel, setSelectedLabel] = useState< + AnonymizerLabels | undefined + >( + annotation.type === "tag" + ? (annotation.tag as AnonymizerLabels | undefined) + : undefined, + ); + const [suffix, setSuffix] = useState(""); const closeTimer = useRef>(null); const isFocusInside = useRef(false); - const { add, addBySearch, remove } = useAnnotation(); + const { add, addBySearch, updateLabel, updateByText, createAnnotationData } = + useAnnotation(); + + const resolvedLabel: AllLabels | AllLabelsWithSufix | undefined = + selectedLabel + ? suffix + ? (`${selectedLabel}_${suffix}` as AllLabelsWithSufix) + : selectedLabel + : undefined; function scheduleClose() { closeTimer.current = setTimeout(() => { @@ -82,80 +99,109 @@ export default function Mark({ }; } - const renderAnnotation = isSearch ? ( - {children} + const isTag = annotation.type === "tag"; + + const renderAnnotation = isTag ? ( + + {children} + ) : ( - {children} + {children} ); - if (!isAnnotable) return annotation; + if (!isAnnotable) return renderAnnotation; return ( - - { - cancelClose(); - setOpen(true); - }} - onMouseLeave={scheduleClose} - > - {renderAnnotation} - - { - isFocusInside.current = true; - }} - onBlur={(e) => { - if (!e.currentTarget.contains(e.relatedTarget)) { - isFocusInside.current = false; - scheduleClose(); - } - }} - > - + + { + cancelClose(); + setOpen(true); + }} + onMouseLeave={scheduleClose} + > + {renderAnnotation} + + { + isFocusInside.current = true; + }} + onBlur={(e) => { + if (!e.currentTarget.contains(e.relatedTarget)) { + isFocusInside.current = false; + scheduleClose(); + } + }} + > + + + + {resolvedLabel && ( + setReplaceAllOpen(open)} + onConfirm={handleConfirmReplaceAll} /> - - + )} + ); - function createAnnotationData(annotation: LabelAnnotation) { - const { start, end, paragraphId, tag } = annotation; - if (!tag) return null; - return { - text: children, - start_char: start, - end_char: end, - paragraphId: paragraphId, - attrs: { - aymurai_label: tag, - aymurai_label_subclass: null, - aymurai_alt_text: null, - aymurai_alt_start_char: start, - aymurai_alt_end_char: end, - }, - }; + function handleAddOne() { + const annotationData = createAnnotationData( + annotation as LabelAnnotation, + resolvedLabel, + ); + if (annotationData) add(annotationData); + } + function handleAddAll() { + if (!resolvedLabel) return; + addBySearch(children, resolvedLabel); } - function handleAdd() { - const annotationData = createAnnotationData(annotation as LabelAnnotation); - if (annotationData) add(annotationData); + function handleReplaceOne() { + if (!resolvedLabel) return; + const annotationData = createAnnotationData( + children, + annotation as LabelAnnotation, + ); + if (annotationData) updateLabel(annotationData, resolvedLabel); } - function handleAddBySearch() { - if (annotation.type === "search" && annotation.tag) - addBySearch(children, annotation.tag); + + function handleReplaceAll() { + if (!resolvedLabel) return; + setReplaceAllOpen(true); } - function handleReplace() {} + function handleConfirmReplaceAll() { + if (!resolvedLabel) return; - function handleReplaceAll() {} + const annotationData = createAnnotationData( + children, + annotation as LabelAnnotation, + ); + if (annotationData) updateByText(annotationData, resolvedLabel); + setReplaceAllOpen(false); + } } diff --git a/src/renderer/src/components/anonymizer/mark/suggestion-label.tsx b/src/renderer/src/components/anonymizer/mark/suggestion-label.tsx new file mode 100644 index 00000000..1c83b9fa --- /dev/null +++ b/src/renderer/src/components/anonymizer/mark/suggestion-label.tsx @@ -0,0 +1,31 @@ +import Suggestion from "@/components/ui/suggestion"; +import { HStack, styled } from "@/styled/jsx"; +import type { AllLabels } from "@/types/aymurai"; + +interface SuggestionLabelProps { + isClickable?: boolean; + children: string; + label: AllLabels; +} +export default function SuggestionLabel({ + isClickable = false, + label, + children, +}: SuggestionLabelProps) { + return ( + + + {children} + + {label} + + + + ); +} diff --git a/src/renderer/src/components/anonymizer/mark/tagger.tsx b/src/renderer/src/components/anonymizer/mark/tagger.tsx deleted file mode 100644 index e5624a0e..00000000 --- a/src/renderer/src/components/anonymizer/mark/tagger.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import Input from "@/components/ui/input"; -import Select from "@/components/ui/select"; -import { sva } from "@/styled/css"; -import { styled } from "@/styled/jsx"; -import { hstack } from "@/styled/patterns"; -import { type AnonymizerLabels, anonymizerLabels } from "@/types/aymurai"; -import TaggerButton from "./tagger-button"; - -const IMG_SIZE = 24; - -const tagger = sva({ - slots: ["container", "button", "divider"], - base: { - container: { - ...hstack.raw({ alignItems: "center", gap: "1" }), - p: "2", - bg: "action.alt-default", - rounded: "md", - }, - button: { - cursor: "pointer", - }, - divider: { - alignSelf: "stretch", - width: "[1px]", - bg: "[#5960B0]", - - my: "1", - }, - }, -}); - -interface MarkTaggerProps { - label?: AnonymizerLabels; - suffix?: number; - onAddOne: () => void; - onAddAll: () => void; -} -export default function MarkTagger({ - label, - suffix, - onAddAll, - onAddOne, -}: MarkTaggerProps) { - const classes = tagger(); - return ( -
- {(label === undefined || suffix === undefined) && ( - <> - - -
- - )} - - - Añadir uno - -
- - Añadir todas - -
- ); -} diff --git a/src/renderer/src/components/file/annotation-popover.tsx b/src/renderer/src/components/file/annotation-popover.tsx index fc549dac..82da4f9b 100644 --- a/src/renderer/src/components/file/annotation-popover.tsx +++ b/src/renderer/src/components/file/annotation-popover.tsx @@ -4,7 +4,11 @@ import { PopoverTrigger, } from "@/components/ui/popover"; import { css } from "@/styled/css"; -import type { ComponentPropsWithoutRef, FocusEventHandler, ReactNode } from "react"; +import type { + ComponentPropsWithoutRef, + FocusEventHandler, + ReactNode, +} from "react"; import { useRef, useState } from "react"; const triggerReset = css({ @@ -39,6 +43,7 @@ export default function AnnotationPopover({ const isFocusInside = useRef(false); const scheduleClose = () => { + cancelClose(); closeTimer.current = setTimeout(() => { if (!isFocusInside.current) setOpen(false); }, 100); @@ -71,6 +76,8 @@ export default function AnnotationPopover({ side="top" sideOffset={8} showArrow={false} + onOpenAutoFocus={(e) => e.preventDefault()} + onCloseAutoFocus={(e) => e.preventDefault()} onMouseEnter={cancelClose} onMouseLeave={scheduleClose} onFocus={() => { diff --git a/src/renderer/src/components/file/search-annotation/index.tsx b/src/renderer/src/components/file/search-annotation/index.tsx index bdc61597..731ebd51 100644 --- a/src/renderer/src/components/file/search-annotation/index.tsx +++ b/src/renderer/src/components/file/search-annotation/index.tsx @@ -4,14 +4,23 @@ import type { } from "@/components/file-annotator/types"; import AnnotationPopover from "@/components/file/annotation-popover"; import { useAnnotation } from "@/context/Annotation"; +import { showToast } from "@/features/showToast"; import { cva } from "@/styled/css"; -import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; +import type { + AllLabels, + AllLabelsWithSufix, + AnonymizerLabels, +} from "@/types/aymurai"; +import { Check } from "phosphor-react"; import SearchTagger from "./search-tagger"; const search = cva({ base: { bg: "[#FCFC02]", + fontFamily: '["Times New Roman", Times, serif]', + fontWeight: "bold", textStyle: "label.md.default", + m: "0", }, variants: { clickable: { @@ -25,18 +34,26 @@ const search = cva({ }); interface SearchAnnotationProps { - annotateTo: AllLabels | AllLabelsWithSufix | undefined; children: string; annotation: Annotation; } export default function SearchAnnotation({ - annotateTo, children, annotation, }: SearchAnnotationProps) { - const { add, addBySearch, createAnnotationData } = useAnnotation(); + if (annotation.type !== "search") + throw new Error( + `Annotation of type "search" expected but got: ${annotation.type}`, + ); - const isAnnotable = !!annotateTo; + const { add, addBySearch, createAnnotationData, label, suffix, isAnnotable } = + useAnnotation(); + + const annotateTo: AllLabels | AllLabelsWithSufix | null = label + ? suffix + ? `${label}_${suffix}` + : label + : null; if (!isAnnotable) return {children}; @@ -45,9 +62,12 @@ export default function SearchAnnotation({ {children}} content={ + // TODO: IMPLEMENT SUFFIX HERE + // TODO: FIX TYPING HERE @@ -59,12 +79,20 @@ export default function SearchAnnotation({ const annotationData = createAnnotationData( children, annotation as LabelAnnotation, - annotateTo, + annotateTo ?? undefined, ); - if (annotationData) add(annotationData); + if (annotationData) { + add(annotationData); + showToast("Se agregó la etiqueta en esta ocurrencia.", "success", Check); + } } function handleAddAll() { if (!annotateTo) return; addBySearch(children, annotateTo); + showToast( + "Se agregó la etiqueta en todas las ocurrencias.", + "success", + Check, + ); } } diff --git a/src/renderer/src/components/file/search-annotation/search-tagger.tsx b/src/renderer/src/components/file/search-annotation/search-tagger.tsx index fc69d40d..d2df101e 100644 --- a/src/renderer/src/components/file/search-annotation/search-tagger.tsx +++ b/src/renderer/src/components/file/search-annotation/search-tagger.tsx @@ -14,9 +14,9 @@ const tagger = sva({ base: { container: { ...hstack.raw({ alignItems: "center", gap: "1" }), - p: "2", + p: "1", bg: "action.alt-default", - rounded: "md", + rounded: "lg", }, button: { cursor: "pointer", @@ -32,34 +32,34 @@ const tagger = sva({ }); interface MarkTaggerProps { - initialLabel?: AnonymizerLabels; - initialSuffix?: string; - onLabelChange?: (label: AnonymizerLabels) => void; - onSuffixChange?: (suffix: string) => void; + initialLabel: AnonymizerLabels; + initialSuffix: string; onAddOne: () => void; onAddAll: () => void; } export default function SearchTagger({ initialLabel, initialSuffix, - onLabelChange, - onSuffixChange, onAddOne, onAddAll, }: MarkTaggerProps) { const classes = tagger(); - const [label, setLabel] = useState(initialLabel); + const [label, setLabel] = useState( + initialLabel, + ); const [suffix, setSuffix] = useState(initialSuffix ?? ""); function handleLabelChange(newLabel: AnonymizerLabels) { setLabel(newLabel); - onLabelChange?.(newLabel); + // TODO: figure out what to do with these + // onLabelChange?.(newLabel); } function handleSuffixChange(newSuffix: string) { setSuffix(newSuffix); - onSuffixChange?.(newSuffix); + // TODO: figure out what to do with these + // onSuffixChange?.(newSuffix); } return ( diff --git a/src/renderer/src/components/file/tag-annotation/index.tsx b/src/renderer/src/components/file/tag-annotation/index.tsx new file mode 100644 index 00000000..409c8b19 --- /dev/null +++ b/src/renderer/src/components/file/tag-annotation/index.tsx @@ -0,0 +1,141 @@ +import SuggestionLabel from "@/components/anonymizer/mark/suggestion-label"; +import type { + Annotation, + LabelAnnotation, +} from "@/components/file-annotator/types"; +import { useAnnotation } from "@/context/Annotation"; +import { showToast } from "@/features/showToast"; +import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; +import { Check } from "phosphor-react"; +import { useState } from "react"; +import AnnotationPopover from "../annotation-popover"; +import RemoveDialog from "./remove-dialog"; +import ReplaceDialog from "./replace-dialog"; +import TagTagger from "./tag-tagger"; + +interface TagAnnotationProps { + children: string; + annotation: Annotation; +} +export default function TagAnnotation({ + children, + annotation, +}: TagAnnotationProps) { + if (annotation.type !== "tag") + throw new Error( + `Annotation of type "tag" expected but got: ${annotation.type}`, + ); + + const { + updateLabel, + remove, + removeByText, + updateByText, + label, + suffix, + isAnnotable, + } = useAnnotation(); + const [replaceAllOpen, setReplaceAllOpen] = useState(false); + const [removeAllOpen, setRemoveAllOpen] = useState(false); + const tag = annotation.tag ?? "DESCONOCIDO"; + + const annotateTo: AllLabels | AllLabelsWithSufix | null = label + ? suffix + ? `${label}_${suffix}` + : label + : null; + + const { start, end, paragraphId } = annotation as LabelAnnotation; + const annotationData = annotation.tag + ? { + text: children, + start_char: start, + end_char: end, + paragraphId, + attrs: { + aymurai_label: annotation.tag, + aymurai_label_subclass: null, + aymurai_alt_text: null, + aymurai_alt_start_char: start, + aymurai_alt_end_char: end, + }, + } + : null; + + if (!isAnnotable) + return {children}; + + return ( + <> + + {children} + + } + content={ + + } + /> + + + + ); + + function handleReplaceOne() { + if (!annotationData || !annotateTo) return; + updateLabel(annotationData, annotateTo); + showToast("Se reemplazó la etiqueta en esta ocurrencia.", "success", Check); + } + + function handleReplaceAll() { + setReplaceAllOpen(true); + } + + function confirmReplaceAll() { + if (!annotationData || !annotateTo) return; + updateByText(annotationData, annotateTo); + setReplaceAllOpen(false); + showToast( + "Se reemplazó la etiqueta en todas las ocurrencias.", + "success", + Check, + ); + } + + function handleRemoveOne() { + if (!annotationData) return; + remove(annotationData); + showToast("Se eliminó la etiqueta en esta ocurrencia.", "success", Check); + } + + function handleRemoveAll() { + setRemoveAllOpen(true); + } + + function confirmRemoveAll() { + if (!annotationData) return; + removeByText(annotationData); + setRemoveAllOpen(false); + showToast( + "Se eliminaron todas las etiquetas de este texto.", + "success", + Check, + ); + } +} diff --git a/src/renderer/src/components/file/tag-annotation/remove-dialog.tsx b/src/renderer/src/components/file/tag-annotation/remove-dialog.tsx new file mode 100644 index 00000000..36a23d89 --- /dev/null +++ b/src/renderer/src/components/file/tag-annotation/remove-dialog.tsx @@ -0,0 +1,37 @@ +import Button from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogFooter, + DialogTitle, +} from "@/components/ui/dialog"; +import { Stack } from "@/styled/jsx"; + +interface RemoveDialogProps { + isOpen: boolean; + label: string; + onClose: (open: boolean) => void; + onConfirm: () => void; +} +export default function RemoveDialog({ + isOpen, + onClose, + onConfirm, + label, +}: RemoveDialogProps) { + return ( + + + Eliminar todas las ocurrencias + + ¿Deseas eliminar todas las ocurrencias con la etiqueta{" "} + {label}? + + + + + + + + ); +} diff --git a/src/renderer/src/components/anonymizer/mark/replace-dialog.tsx b/src/renderer/src/components/file/tag-annotation/replace-dialog.tsx similarity index 74% rename from src/renderer/src/components/anonymizer/mark/replace-dialog.tsx rename to src/renderer/src/components/file/tag-annotation/replace-dialog.tsx index 0b60c4d1..422e60ff 100644 --- a/src/renderer/src/components/anonymizer/mark/replace-dialog.tsx +++ b/src/renderer/src/components/file/tag-annotation/replace-dialog.tsx @@ -4,14 +4,12 @@ import { DialogContent, DialogFooter, DialogTitle, - DialogTrigger, } from "@/components/ui/dialog"; import { Stack } from "@/styled/jsx"; -import type { AnonymizerLabels } from "@/types/aymurai"; interface ReplaceDialogProps { isOpen: boolean; - label: AnonymizerLabels; + label: string; onClose: (open: boolean) => void; onConfirm: () => void; } @@ -23,11 +21,11 @@ export default function ReplaceDialog({ }: ReplaceDialogProps) { return ( - hola - Reemplazar + Reemplazar todas las ocurrencias - ¿Deseas eliminar todas las etiquetas {label}? + ¿Deseas reemplazar todas las ocurrencias con la etiqueta{" "} + {label}? diff --git a/src/renderer/src/components/file/tag-annotation/tag-tagger.tsx b/src/renderer/src/components/file/tag-annotation/tag-tagger.tsx new file mode 100644 index 00000000..47d78848 --- /dev/null +++ b/src/renderer/src/components/file/tag-annotation/tag-tagger.tsx @@ -0,0 +1,87 @@ +import { sva } from "@/styled/css"; +import { hstack } from "@/styled/patterns"; +import TaggerButton from "../tagger-button"; + +const IMG_SIZE = 24; + +const tagger = sva({ + slots: ["container", "button", "divider"], + base: { + container: { + ...hstack.raw({ alignItems: "center", gap: "1" }), + p: "1", + bg: "action.alt-default", + rounded: "lg", + }, + button: { + cursor: "pointer", + }, + divider: { + alignSelf: "stretch", + width: "[1px]", + bg: "[#5960B0]", + + my: "1", + }, + }, +}); + +interface MarkTaggerProps { + onRemove: () => void; + onRemoveAll: () => void; + onReplaceOne: () => void; + onReplaceAll: () => void; +} +export default function TagTagger({ + onRemove, + onRemoveAll, + onReplaceAll, + onReplaceOne, +}: MarkTaggerProps) { + const classes = tagger(); + return ( +
+ + Reemplazar una + +
+ + Reemplazar todas + +
+ + Removar una + +
+ + Removar todas + +
+ ); +} diff --git a/src/renderer/src/components/anonymizer/mark/tagger-button.tsx b/src/renderer/src/components/file/tagger-button.tsx similarity index 100% rename from src/renderer/src/components/anonymizer/mark/tagger-button.tsx rename to src/renderer/src/components/file/tagger-button.tsx From aa2ce6a1f996d43673eef233d3b56c9ad44d8ec4 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 26 Apr 2026 20:39:29 -0300 Subject: [PATCH 150/263] adjust styles on callout --- src/renderer/src/components/ui/callout.tsx | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/renderer/src/components/ui/callout.tsx b/src/renderer/src/components/ui/callout.tsx index c7ab0281..d215abe2 100644 --- a/src/renderer/src/components/ui/callout.tsx +++ b/src/renderer/src/components/ui/callout.tsx @@ -1,7 +1,8 @@ import { cva, cx } from "@/styled/css"; +import { styled } from "@/styled/jsx"; import { hstack } from "@/styled/patterns"; -import { Bell, X } from "phosphor-react"; import type { Icon } from "phosphor-react"; +import { Bell, X } from "phosphor-react"; import type { HTMLAttributes } from "react"; const calloutRecipe = cva({ @@ -21,25 +22,28 @@ const calloutRecipe = cva({ width: "full", textStyle: "paragraph.sm.default", - color: "text.default", }, variants: { variant: { error: { bg: "system.error-secondary", borderColor: "system.error", + color: "system.error", }, warning: { bg: "system.warning-secondary", borderColor: "system.warning", + color: "system.warning", }, success: { bg: "system.success-secondary", borderColor: "system.success", + color: "system.success", }, info: { bg: "system.info-secondary", borderColor: "system.info", + color: "text.default", }, }, noBorder: { @@ -74,22 +78,26 @@ function Callout({ ...props }: CalloutProps) { return ( -
+
); From 55a67bf85a51905c5849eaeee081bde87f03250a Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 26 Apr 2026 20:40:07 -0300 Subject: [PATCH 151/263] fix select viewport and add scroll --- src/renderer/src/components/ui/select.tsx | 25 +++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/components/ui/select.tsx b/src/renderer/src/components/ui/select.tsx index 5fe8b434..f02c2dc9 100644 --- a/src/renderer/src/components/ui/select.tsx +++ b/src/renderer/src/components/ui/select.tsx @@ -1,5 +1,5 @@ import * as RadixSelect from "@radix-ui/react-select"; -import { CaretDown, Check } from "phosphor-react"; +import { CaretDown, CaretUp, Check } from "phosphor-react"; import { type Ref, useId, useImperativeHandle } from "react"; import Suggestion from "@/components/ui/suggestion"; @@ -57,8 +57,10 @@ const select = sva({ "value", "caret", "content", + "viewport", "item", "itemIndicator", + "scrollButton", ], base: { container: { ...stack.raw({ gap: "1" }), width: "full" }, @@ -119,6 +121,19 @@ const select = sva({ zIndex: "10", minWidth: "[var(--radix-select-trigger-width)]", }, + viewport: { + maxHeight: "[400px]", + overflowY: "auto", + }, + scrollButton: { + display: "flex", + alignItems: "center", + justifyContent: "center", + py: "1", + color: "text.lighter", + cursor: "default", + bg: "white", + }, item: { display: "flex", alignItems: "center", @@ -254,7 +269,10 @@ export default function Select({ position="popper" sideOffset={4} > - + + + + {orderedOptions.map(({ id, text }) => ( @@ -264,6 +282,9 @@ export default function Select({ ))} + + + From ca56bb635a1ec31206435a76275de5dbaeb5593a Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 26 Apr 2026 20:40:22 -0300 Subject: [PATCH 152/263] add size variant to suggestion and adjust display --- src/renderer/src/components/ui/suggestion.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/renderer/src/components/ui/suggestion.tsx b/src/renderer/src/components/ui/suggestion.tsx index a9196801..d41aa5a4 100644 --- a/src/renderer/src/components/ui/suggestion.tsx +++ b/src/renderer/src/components/ui/suggestion.tsx @@ -4,15 +4,21 @@ const Suggestion = styled("mark", { base: { bg: "bg.primary-alternative", textStyle: "label.md.default", + display: "inline-flex", }, variants: { clickable: { true: { cursor: "pointer" }, false: { cursor: "unset" }, }, + rounded: { + true: { rounded: "md" }, + false: { rounded: "[0px]" }, + }, }, defaultVariants: { clickable: false, + rounded: false, }, }); From d1649e5de5beec252143870a6c8a33407ca31a13 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 26 Apr 2026 20:42:14 -0300 Subject: [PATCH 153/263] add max width to toast and remove instad of dismiss it --- src/renderer/src/components/ui/toast.tsx | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/renderer/src/components/ui/toast.tsx b/src/renderer/src/components/ui/toast.tsx index b9d83125..48f935a3 100644 --- a/src/renderer/src/components/ui/toast.tsx +++ b/src/renderer/src/components/ui/toast.tsx @@ -1,5 +1,5 @@ -import { type Toast as HotToast, toast } from "react-hot-toast"; import type { Icon } from "phosphor-react"; +import { type Toast as HotToast, toast } from "react-hot-toast"; import Callout, { type CalloutVariant } from "./callout"; export type ToastVariant = CalloutVariant; @@ -17,15 +17,18 @@ function Toast({ t, message, variant = "info", icon }: ToastProps) { const isAssertive = ASSERTIVE_VARIANTS.includes(variant); return ( - toast.dismiss(t.id)} - role={isAssertive ? "alert" : "status"} - aria-live={isAssertive ? "assertive" : "polite"} - aria-atomic="true" - /> +
+ toast.remove(t.id)} + role={isAssertive ? "alert" : "status"} + aria-live={isAssertive ? "assertive" : "polite"} + aria-atomic="true" + noBorder + /> +
); } From 6b21903e9d71d22106a4ccd6943e2ebb358d0c98 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 26 Apr 2026 20:42:36 -0300 Subject: [PATCH 154/263] move createAnnotationData, tag and suffix to context --- src/renderer/src/context/Annotation/index.tsx | 47 ++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/context/Annotation/index.tsx b/src/renderer/src/context/Annotation/index.tsx index 46175a23..ad5ff922 100644 --- a/src/renderer/src/context/Annotation/index.tsx +++ b/src/renderer/src/context/Annotation/index.tsx @@ -1,3 +1,4 @@ +import type { LabelAnnotation } from "@/components/file-annotator/types"; import { useFileDispatch } from "@/hooks"; import { appendPrediction, @@ -23,6 +24,8 @@ import { interface AnnotationContextValues { isAnnotable: boolean; + label: AllLabels | null; + suffix: number | null; add: (prediction: PredictLabel) => void; remove: (prediction: PredictLabel) => void; removeByText: (prediction: PredictLabel) => void; @@ -42,6 +45,8 @@ interface AnnotationContextValues { */ export const AnnotationContext = createContext({ isAnnotable: false, + label: null, + suffix: null, add: () => {}, remove: () => {}, removeByText: () => {}, @@ -55,14 +60,21 @@ interface Props { children?: ReactNode; file: DocFile; isAnnotable?: boolean; - searchTag: AllLabels | AllLabelsWithSufix | null; + label: AllLabels | null; + suffix: number | null; } export default function AnnotationProvider({ children, file, isAnnotable = false, - searchTag, + label, + suffix, }: Props) { + const searchTag: AllLabels | AllLabelsWithSufix | null = label + ? suffix + ? `${label}_${suffix}` + : label + : null; const dispatch = useFileDispatch(); const add = useCallback( @@ -169,6 +181,8 @@ export default function AnnotationProvider({ { remove, removeByText, isAnnotable, + label, + suffix, updateLabel, updateByText, addBySearch, } = useContext(AnnotationContext); + const createAnnotationData = ( + text: string, + annotation: LabelAnnotation, + labelOverride?: AllLabels | AllLabelsWithSufix, + ) => { + const { start, end, paragraphId, tag } = annotation; + const resolvedTag = labelOverride ?? tag; + if (!resolvedTag) return null; + return { + text, + start_char: start, + end_char: end, + paragraphId: paragraphId, + attrs: { + aymurai_label: resolvedTag, + aymurai_label_subclass: null, + aymurai_alt_text: null, + aymurai_alt_start_char: start, + aymurai_alt_end_char: end, + canonical_entity_id: crypto.randomUUID(), + }, + } satisfies PredictLabel; + }; + return { add, remove, removeByText, isAnnotable, + label, + suffix, updateLabel, updateByText, addBySearch, + createAnnotationData, }; }; From cae3b90799ad41805e21b7d1ebd02b0c9f27c405 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 26 Apr 2026 20:48:29 -0300 Subject: [PATCH 155/263] disambiguate hook --- src/renderer/src/hooks/useDisambiguate.ts | 72 +++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/renderer/src/hooks/useDisambiguate.ts diff --git a/src/renderer/src/hooks/useDisambiguate.ts b/src/renderer/src/hooks/useDisambiguate.ts new file mode 100644 index 00000000..454c7b85 --- /dev/null +++ b/src/renderer/src/hooks/useDisambiguate.ts @@ -0,0 +1,72 @@ +import { useEffect, useRef } from "react"; + +import { useFileDispatch } from "@/hooks"; +import { addPredictions, removePredictions } from "@/reducers/file/actions"; +import { disambiguate } from "@/services/aymurai/queries"; +import type { DocFile } from "@/types/file"; +import { useQueries } from "@tanstack/react-query"; + +import type { PredictStatus } from "./usePredict"; + +type FileDisambiguate = { status: PredictStatus }; + +/** + * Runs disambiguation for each file **after all its predictions have arrived**. + * When `enabled` is false (e.g. datapublic flow) every file resolves to + * `"completed"` immediately and no requests are made. + * + * Aligned index-wise with `files`: `queries[i]` corresponds to `files[i]`. + */ +export function useDisambiguate( + files: DocFile[], + predictStatuses: Record, + enabled: boolean, +): Record { + const dispatch = useFileDispatch(); + // Track which files have already had their disambiguated predictions dispatched + const dispatchedRef = useRef(new Set()); + + const queries = useQueries({ + queries: files.map((file) => ({ + ...disambiguate(file), + // Fire only when this step is enabled and predict is fully done + enabled: + enabled && predictStatuses[file.data.name]?.status === "completed", + })), + }); + + // Dispatch disambiguated predictions exactly once per file on success + useEffect(() => { + queries.forEach((query, i) => { + const fileName = files[i].data.name; + if (!query.isSuccess || dispatchedRef.current.has(fileName)) return; + + dispatchedRef.current.add(fileName); + // Replace raw predictions with the disambiguated ones + dispatch(removePredictions(fileName)); + dispatch(addPredictions(fileName, query.data)); + }); + }); + + const result: Record = {}; + + files.forEach((file, i) => { + const fileName = file.data.name; + const query = queries[i]; + const predictDone = predictStatuses[fileName]?.status === "completed"; + + result[fileName] = { + status: !enabled + ? "completed" // this step is skipped for non-anonymizer flows + : !predictDone + ? "processing" // still waiting on predict + : query.isError + ? "error" + : query.isSuccess + ? "completed" + : "processing", + }; + }); + + return result; +} From 770175436c52e8860becb65928e73527558bd856 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 26 Apr 2026 20:48:45 -0300 Subject: [PATCH 156/263] adjust spacing on dataset validation --- .../src/components/validate-dataset/index.tsx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/renderer/src/components/validate-dataset/index.tsx b/src/renderer/src/components/validate-dataset/index.tsx index 7e1ddeff..e5068cf6 100644 --- a/src/renderer/src/components/validate-dataset/index.tsx +++ b/src/renderer/src/components/validate-dataset/index.tsx @@ -6,7 +6,7 @@ import { useFileDispatch, useFiles } from "@/hooks"; import { SectionTitle } from "@/layout/section-title"; import { validate } from "@/reducers/file/actions"; import { css } from "@/styled/css"; -import { HStack } from "@/styled/jsx"; +import { HStack, Stack } from "@/styled/jsx"; import { isFileValidated, isValidationCompleted } from "@/utils/file"; import { useNavigate, useParams } from "@tanstack/react-router"; import MainContent from "../layout/main-content"; @@ -73,17 +73,17 @@ export function ValidateDataset() { file={selectedFile} isAnnotable={false} /> - - - 3. Validación de datos - - + + + + 3. Validación de datos + + +
From 63c4d73117870a4c9369f5f3d8803d7f9acf7041 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Sun, 26 Apr 2026 20:49:01 -0300 Subject: [PATCH 157/263] move suggestion label and add mark props --- .../{anonymizer/mark => file}/suggestion-label.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) rename src/renderer/src/components/{anonymizer/mark => file}/suggestion-label.tsx (75%) diff --git a/src/renderer/src/components/anonymizer/mark/suggestion-label.tsx b/src/renderer/src/components/file/suggestion-label.tsx similarity index 75% rename from src/renderer/src/components/anonymizer/mark/suggestion-label.tsx rename to src/renderer/src/components/file/suggestion-label.tsx index 1c83b9fa..685f883b 100644 --- a/src/renderer/src/components/anonymizer/mark/suggestion-label.tsx +++ b/src/renderer/src/components/file/suggestion-label.tsx @@ -1,8 +1,10 @@ import Suggestion from "@/components/ui/suggestion"; import { HStack, styled } from "@/styled/jsx"; import type { AllLabels } from "@/types/aymurai"; +import type { ComponentPropsWithoutRef } from "react"; -interface SuggestionLabelProps { +interface SuggestionLabelProps + extends Omit, "translate" | "color"> { isClickable?: boolean; children: string; label: AllLabels; @@ -11,9 +13,10 @@ export default function SuggestionLabel({ isClickable = false, label, children, + ...props }: SuggestionLabelProps) { return ( - + {children} Date: Mon, 27 Apr 2026 01:14:45 -0300 Subject: [PATCH 158/263] store label manager config in local storage --- .../anonymizer/label-manager/config-tab.tsx | 33 ++++++++++++------- src/renderer/src/constants/excluded-tags.ts | 8 +++++ src/renderer/src/store/useLocal.ts | 17 ++++++++++ 3 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 src/renderer/src/constants/excluded-tags.ts diff --git a/src/renderer/src/components/anonymizer/label-manager/config-tab.tsx b/src/renderer/src/components/anonymizer/label-manager/config-tab.tsx index 055da784..69417d5c 100644 --- a/src/renderer/src/components/anonymizer/label-manager/config-tab.tsx +++ b/src/renderer/src/components/anonymizer/label-manager/config-tab.tsx @@ -1,10 +1,15 @@ import { HStack, Stack, styled } from "@/styled/jsx"; -import { anonymizerLabels } from "@/types/aymurai"; +import { type AnonymizerLabels, anonymizerLabels } from "@/types/aymurai"; import { useState } from "react"; import Button from "@/components/ui/button"; import Input from "@/components/ui/input"; import BaseSwitch from "@/components/ui/switch"; +import { EXCLUDED_TAGS } from "@/constants/excluded-tags"; +import { + useExcludedTagsConfig, + useExcludedTagsConfigActions, +} from "@/store/useLocal"; import { Label } from "./label"; import LabelManagerSection from "./section"; @@ -24,29 +29,35 @@ function Switch({ name, value, onToggle }: ToggleProps) { ); } -const initialToggles = Object.fromEntries( - anonymizerLabels.map((label) => [label.id, true]), -); - export default function LabelConfigTab() { - const [toggles, setToggles] = - useState>(initialToggles); - const [excludedWords, setExcludedWords] = useState([]); + const { tags: storedTags, words: storedWords } = useExcludedTagsConfig(); + const { setTags, setWords } = useExcludedTagsConfigActions(); + + const [toggles, setToggles] = useState>( + storedTags ?? EXCLUDED_TAGS, + ); + const [excludedWords, setExcludedWords] = useState(storedWords); const [inputValue, setInputValue] = useState(""); function handleToggle(id: string, value: boolean) { - setToggles((prev) => ({ ...prev, [id]: value })); + const next = { ...toggles, [id]: value }; + setToggles(next); + setTags(next as Record); } function handleAddWord() { const trimmed = inputValue.trim(); if (!trimmed || excludedWords.includes(trimmed)) return; - setExcludedWords((prev) => [...prev, trimmed]); + const next = [...excludedWords, trimmed]; + setExcludedWords(next); + setWords(next); setInputValue(""); } function handleRemoveWord(word: string) { - setExcludedWords((prev) => prev.filter((w) => w !== word)); + const next = excludedWords.filter((w) => w !== word); + setExcludedWords(next); + setWords(next); } return ( diff --git a/src/renderer/src/constants/excluded-tags.ts b/src/renderer/src/constants/excluded-tags.ts new file mode 100644 index 00000000..3d423f8c --- /dev/null +++ b/src/renderer/src/constants/excluded-tags.ts @@ -0,0 +1,8 @@ +import { type AnonymizerLabels, anonymizerLabels } from "@/types/aymurai"; + +const entries = anonymizerLabels.map((label) => [label.id, true] as const); + +export const EXCLUDED_TAGS = Object.fromEntries(entries) as Record< + AnonymizerLabels, + boolean +>; diff --git a/src/renderer/src/store/useLocal.ts b/src/renderer/src/store/useLocal.ts index f78bbca5..09a3da1a 100644 --- a/src/renderer/src/store/useLocal.ts +++ b/src/renderer/src/store/useLocal.ts @@ -1,5 +1,6 @@ import { create } from "zustand"; import { devtools, persist } from "zustand/middleware"; +import type { AnonymizerLabels } from "../types/aymurai"; import { FeatureFlowEnum } from "../types/features"; type TutorialsSeen = Record; @@ -11,6 +12,10 @@ interface LocalStorageStore { tutorialsSeen: TutorialsSeen; hasSeenTutorial: (feature: FeatureFlowEnum) => boolean; setTutorialSeen: (feature: FeatureFlowEnum) => void; + excludedTags: Record | null; + setExcludedTags: (tags: Record) => void; + excludedWords: string[]; + setExcludedWords: (words: string[]) => void; } const useLocalStore = create()( @@ -30,6 +35,10 @@ const useLocalStore = create()( set((state) => ({ tutorialsSeen: { ...state.tutorialsSeen, [feature]: true }, })), + excludedTags: null, + setExcludedTags: (tags) => set({ excludedTags: tags }), + excludedWords: [], + setExcludedWords: (words) => set({ excludedWords: words }), }), { name: "local-storage", @@ -55,3 +64,11 @@ export const useTutorialSeen = (feature: FeatureFlowEnum) => useLocalStore((state) => state.tutorialsSeen[feature]); export const useSetTutorialSeen = () => useLocalStore((state) => state.setTutorialSeen); + +export const useExcludedTagsConfig = () => + useLocalStore((s) => ({ tags: s.excludedTags, words: s.excludedWords })); +export const useExcludedTagsConfigActions = () => + useLocalStore((s) => ({ + setTags: s.setExcludedTags, + setWords: s.setExcludedWords, + })); From 0f08b9c85dd4cfff03a12fad37608fc5429b2569 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 01:16:28 -0300 Subject: [PATCH 159/263] add more anonymizer copy locale texts --- src/renderer/src/constants/i18n/locales/es/anonymizer.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/renderer/src/constants/i18n/locales/es/anonymizer.ts b/src/renderer/src/constants/i18n/locales/es/anonymizer.ts index 6d22c04f..0d2651de 100644 --- a/src/renderer/src/constants/i18n/locales/es/anonymizer.ts +++ b/src/renderer/src/constants/i18n/locales/es/anonymizer.ts @@ -31,6 +31,12 @@ const anonymizer = { processingSubtitle: "Este proceso puede tardar algunos minutos.", finishText: "Se finalizó el análisis del documento.", }, + validation: { + toastSingleSuccess: + 'Se aplicó con éxito una etiqueta de "{{label}}" en una ocurrencia.', + toastAllSuccess: + 'Se aplicó con éxito una etiqueta de "{{label}}" en todas las ocurrencias.', + }, result: { sectionTitle: "" }, finish: { sectionTitle: "4. Finalización", @@ -38,7 +44,8 @@ const anonymizer = { "Los datos encontrados por AymurAI y posteriormente validados ya han sido anonimizados correctamente.", subtitle: "Archivo procesado", restart: "Cargar un nuevo documento", - viewResult: "Descargar documento", + viewResult: "Descargar ODT", + viewResultPDF: "Descargar PDF", }, }; From 52230ee4f1a2ecff5155d22f2f422c4397e10a9b Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 01:39:29 -0300 Subject: [PATCH 160/263] add metadata to search and tag annotations --- .../file/search-annotation/index.tsx | 19 +++++++++++++++++-- .../components/file/tag-annotation/index.tsx | 17 ++++++++++++++--- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/renderer/src/components/file/search-annotation/index.tsx b/src/renderer/src/components/file/search-annotation/index.tsx index 731ebd51..6d30f2ae 100644 --- a/src/renderer/src/components/file/search-annotation/index.tsx +++ b/src/renderer/src/components/file/search-annotation/index.tsx @@ -1,6 +1,7 @@ import type { Annotation, LabelAnnotation, + Metadata, } from "@/components/file-annotator/types"; import AnnotationPopover from "@/components/file/annotation-popover"; import { useAnnotation } from "@/context/Annotation"; @@ -55,12 +56,26 @@ export default function SearchAnnotation({ : label : null; + const metadata: Metadata = { + "data-start": annotation.start, + "data-end": annotation.end, + "data-tag": annotation.tag, + }; + if (!isAnnotable) - return {children}; + return ( + + {children} + + ); return ( {children}} + trigger={ + + {children} + + } content={ // TODO: IMPLEMENT SUFFIX HERE // TODO: FIX TYPING HERE diff --git a/src/renderer/src/components/file/tag-annotation/index.tsx b/src/renderer/src/components/file/tag-annotation/index.tsx index 409c8b19..ffbdd4f0 100644 --- a/src/renderer/src/components/file/tag-annotation/index.tsx +++ b/src/renderer/src/components/file/tag-annotation/index.tsx @@ -1,7 +1,7 @@ -import SuggestionLabel from "@/components/anonymizer/mark/suggestion-label"; import type { Annotation, LabelAnnotation, + Metadata, } from "@/components/file-annotator/types"; import { useAnnotation } from "@/context/Annotation"; import { showToast } from "@/features/showToast"; @@ -9,6 +9,7 @@ import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; import { Check } from "phosphor-react"; import { useState } from "react"; import AnnotationPopover from "../annotation-popover"; +import SuggestionLabel from "../suggestion-label"; import RemoveDialog from "./remove-dialog"; import ReplaceDialog from "./replace-dialog"; import TagTagger from "./tag-tagger"; @@ -62,14 +63,24 @@ export default function TagAnnotation({ } : null; + const metadata: Metadata = { + "data-start": annotation.start, + "data-end": annotation.end, + "data-tag": annotation.tag, + }; + if (!isAnnotable) - return {children}; + return ( + + {children} + + ); return ( <> + {children} } From cad8faaa0574bb5c15939254b1a07d31eb2e7190 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 02:02:12 -0300 Subject: [PATCH 161/263] simplify annotation components --- .../src/components/anonymizer/mark/index.tsx | 207 ------------------ .../index.tsx} | 28 +-- .../tagger-button.tsx | 24 +- .../file/annotation-popover/tagger.tsx | 116 ++++++++++ .../index.tsx => search-annotation.tsx} | 30 +-- .../file/search-annotation/search-tagger.tsx | 106 --------- .../components/file/tag-annotation/index.tsx | 45 ++-- .../file/tag-annotation/tag-tagger.tsx | 87 -------- 8 files changed, 174 insertions(+), 469 deletions(-) delete mode 100644 src/renderer/src/components/anonymizer/mark/index.tsx rename src/renderer/src/components/file/{annotation-popover.tsx => annotation-popover/index.tsx} (81%) rename src/renderer/src/components/file/{ => annotation-popover}/tagger-button.tsx (70%) create mode 100644 src/renderer/src/components/file/annotation-popover/tagger.tsx rename src/renderer/src/components/file/{search-annotation/index.tsx => search-annotation.tsx} (74%) delete mode 100644 src/renderer/src/components/file/search-annotation/search-tagger.tsx delete mode 100644 src/renderer/src/components/file/tag-annotation/tag-tagger.tsx diff --git a/src/renderer/src/components/anonymizer/mark/index.tsx b/src/renderer/src/components/anonymizer/mark/index.tsx deleted file mode 100644 index 20137a3a..00000000 --- a/src/renderer/src/components/anonymizer/mark/index.tsx +++ /dev/null @@ -1,207 +0,0 @@ -import type { - Annotation, - LabelAnnotation, - Metadata, -} from "@/components/file-annotator/types"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; -import { useAnnotation } from "@/context/Annotation"; -import { css, cva } from "@/styled/css"; -import type { - AllLabels, - AllLabelsWithSufix, - AnonymizerLabels, -} from "@/types/aymurai"; -import { useRef, useState } from "react"; -import ReplaceDialog from "./replace-dialog"; -import SuggestionLabel from "./suggestion-label"; -import Tagger from "./tagger"; - -const triggerReset = css({ - appearance: "none", - bg: "transparent", - border: "[none]", - padding: "0", - cursor: "default", - "&:focus-visible": { - outline: "[2px solid token(colors.action.hover)]", - outlineOffset: "[2px]", - borderRadius: "sm", - }, -}); - -const search = cva({ - base: { - bg: "[#FCFC02]", - textStyle: "label.md.default", - }, - variants: { - clickable: { - true: { cursor: "pointer" }, - false: { cursor: "unset" }, - }, - }, - defaultVariants: { - clickable: false, - }, -}); - -interface MarkProps { - children: string; - isAnnotable: boolean; - annotation: Annotation; -} -export default function Mark({ children, isAnnotable, annotation }: MarkProps) { - const [open, setOpen] = useState(false); - const [replaceAllOpen, setReplaceAllOpen] = useState(false); - const [selectedLabel, setSelectedLabel] = useState< - AnonymizerLabels | undefined - >( - annotation.type === "tag" - ? (annotation.tag as AnonymizerLabels | undefined) - : undefined, - ); - const [suffix, setSuffix] = useState(""); - const closeTimer = useRef>(null); - const isFocusInside = useRef(false); - - const { add, addBySearch, updateLabel, updateByText, createAnnotationData } = - useAnnotation(); - - const resolvedLabel: AllLabels | AllLabelsWithSufix | undefined = - selectedLabel - ? suffix - ? (`${selectedLabel}_${suffix}` as AllLabelsWithSufix) - : selectedLabel - : undefined; - - function scheduleClose() { - closeTimer.current = setTimeout(() => { - if (!isFocusInside.current) setOpen(false); - }, 100); - } - - function cancelClose() { - if (closeTimer.current) clearTimeout(closeTimer.current); - } - - let metadata: Metadata = { - "data-start": annotation.start, - "data-end": annotation.end, - }; - if (annotation.type !== "text") { - metadata = { - ...metadata, - "data-tag": annotation.tag, - }; - } - - const isTag = annotation.type === "tag"; - - const renderAnnotation = isTag ? ( - - {children} - - ) : ( - {children} - ); - - if (!isAnnotable) return renderAnnotation; - - return ( - <> - - { - cancelClose(); - setOpen(true); - }} - onMouseLeave={scheduleClose} - > - {renderAnnotation} - - { - isFocusInside.current = true; - }} - onBlur={(e) => { - if (!e.currentTarget.contains(e.relatedTarget)) { - isFocusInside.current = false; - scheduleClose(); - } - }} - > - - - - {resolvedLabel && ( - setReplaceAllOpen(open)} - onConfirm={handleConfirmReplaceAll} - /> - )} - - ); - - function handleAddOne() { - const annotationData = createAnnotationData( - annotation as LabelAnnotation, - resolvedLabel, - ); - if (annotationData) add(annotationData); - } - function handleAddAll() { - if (!resolvedLabel) return; - addBySearch(children, resolvedLabel); - } - - function handleReplaceOne() { - if (!resolvedLabel) return; - const annotationData = createAnnotationData( - children, - annotation as LabelAnnotation, - ); - if (annotationData) updateLabel(annotationData, resolvedLabel); - } - - function handleReplaceAll() { - if (!resolvedLabel) return; - setReplaceAllOpen(true); - } - - function handleConfirmReplaceAll() { - if (!resolvedLabel) return; - - const annotationData = createAnnotationData( - children, - annotation as LabelAnnotation, - ); - if (annotationData) updateByText(annotationData, resolvedLabel); - setReplaceAllOpen(false); - } -} diff --git a/src/renderer/src/components/file/annotation-popover.tsx b/src/renderer/src/components/file/annotation-popover/index.tsx similarity index 81% rename from src/renderer/src/components/file/annotation-popover.tsx rename to src/renderer/src/components/file/annotation-popover/index.tsx index 82da4f9b..7a3eeba9 100644 --- a/src/renderer/src/components/file/annotation-popover.tsx +++ b/src/renderer/src/components/file/annotation-popover/index.tsx @@ -4,12 +4,10 @@ import { PopoverTrigger, } from "@/components/ui/popover"; import { css } from "@/styled/css"; -import type { - ComponentPropsWithoutRef, - FocusEventHandler, - ReactNode, -} from "react"; +import type { AllLabels } from "@/types/aymurai"; +import type { FocusEventHandler, ReactNode } from "react"; import { useRef, useState } from "react"; +import Tagger from "./tagger"; const triggerReset = css({ appearance: "none", @@ -25,18 +23,15 @@ const triggerReset = css({ }); interface AnnotationPopoverProps { - trigger: ReactNode; - content: ReactNode; - contentProps?: Omit< - ComponentPropsWithoutRef, - "children" - >; + children: ReactNode; + onClickOne: (label: AllLabels, suffix: number | null) => void; + onClickAll: (label: AllLabels, suffix: number | null) => void; } export default function AnnotationPopover({ - trigger, - content, - contentProps, + children, + onClickAll, + onClickOne, }: AnnotationPopoverProps) { const [open, setOpen] = useState(false); const closeTimer = useRef>(null); @@ -70,7 +65,7 @@ export default function AnnotationPopover({ }} onMouseLeave={scheduleClose} > - {trigger} + {children} - {content} + ); diff --git a/src/renderer/src/components/file/tagger-button.tsx b/src/renderer/src/components/file/annotation-popover/tagger-button.tsx similarity index 70% rename from src/renderer/src/components/file/tagger-button.tsx rename to src/renderer/src/components/file/annotation-popover/tagger-button.tsx index a2aecad6..9c0f1810 100644 --- a/src/renderer/src/components/file/tagger-button.tsx +++ b/src/renderer/src/components/file/annotation-popover/tagger-button.tsx @@ -26,24 +26,44 @@ const button = sva({ rounded: "sm", }, }, + variants: { + disabled: { + true: { + button: { + cursor: "not-allowed", + _hover: { + bg: "transparent", + }, + }, + }, + }, + }, }); interface TaggerButtonProps { tooltip: string; children: React.ReactNode; onClick: () => void; + disabled?: boolean; } export default function TaggerButton({ children, tooltip, onClick, + disabled = false, }: TaggerButtonProps) { - const classes = button(); + const classes = button({ disabled }); return ( - diff --git a/src/renderer/src/components/file/annotation-popover/tagger.tsx b/src/renderer/src/components/file/annotation-popover/tagger.tsx new file mode 100644 index 00000000..cbfd7c59 --- /dev/null +++ b/src/renderer/src/components/file/annotation-popover/tagger.tsx @@ -0,0 +1,116 @@ +import type React from "react"; +import { useState } from "react"; + +import { sva } from "@/styled/css"; +import { styled } from "@/styled/jsx"; +import { hstack } from "@/styled/patterns"; + +import Input from "@/components/ui/input"; +import Select, { type SelectOption } from "@/components/ui/select"; +import { useAnnotation } from "@/context/Annotation"; +import { type AllLabels, anonymizerLabels } from "@/types/aymurai"; + +import TaggerButton from "./tagger-button"; + +const IMG_SIZE = 24; + +const tagger = sva({ + slots: ["container", "button", "divider"], + base: { + container: { + ...hstack.raw({ alignItems: "center", gap: "1" }), + p: "1", + bg: "action.alt-default", + rounded: "lg", + }, + button: { + cursor: "pointer", + }, + divider: { + alignSelf: "stretch", + width: "[1px]", + bg: "[#5960B0]", + + my: "1", + }, + }, +}); + +interface MarkTaggerProps { + onClickOne: (label: AllLabels, suffix: number | null) => void; + onClickAll: (label: AllLabels, suffix: number | null) => void; +} +export default function Tagger({ onClickAll, onClickOne }: MarkTaggerProps) { + const { label: initialLabel, suffix: initialSuffix } = useAnnotation(); + + const [label, setLabel] = useState(initialLabel); + const [suffix, setSuffix] = useState(initialSuffix); + + const handleClickOne = () => { + if (!label) return; + onClickOne(label, suffix); + }; + const handleClickAll = () => { + if (!label) return; + onClickAll(label, suffix); + }; + + const handleLabelChange = (value: SelectOption) => { + setLabel(value.id as AllLabels); + }; + const handleSuffixChange: React.ChangeEventHandler = ( + e, + ) => { + const n = Number(e.target.value); + if (Number.isNaN(n)) throw new Error("Tried to input a non-numeric value!"); + setSuffix(n); + }; + + const classes = tagger(); + return ( +
+ + +
+ + Afectar una ocurrencia + +
+ + Afectar todas las ocurrencias + +
+ ); +} diff --git a/src/renderer/src/components/file/search-annotation/index.tsx b/src/renderer/src/components/file/search-annotation.tsx similarity index 74% rename from src/renderer/src/components/file/search-annotation/index.tsx rename to src/renderer/src/components/file/search-annotation.tsx index 6d30f2ae..be78c8f6 100644 --- a/src/renderer/src/components/file/search-annotation/index.tsx +++ b/src/renderer/src/components/file/search-annotation.tsx @@ -7,13 +7,8 @@ import AnnotationPopover from "@/components/file/annotation-popover"; import { useAnnotation } from "@/context/Annotation"; import { showToast } from "@/features/showToast"; import { cva } from "@/styled/css"; -import type { - AllLabels, - AllLabelsWithSufix, - AnonymizerLabels, -} from "@/types/aymurai"; +import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; import { Check } from "phosphor-react"; -import SearchTagger from "./search-tagger"; const search = cva({ base: { @@ -70,24 +65,11 @@ export default function SearchAnnotation({ ); return ( - - {children} - - } - content={ - // TODO: IMPLEMENT SUFFIX HERE - // TODO: FIX TYPING HERE - - } - /> + + + {children} + + ); function handleAddOne() { diff --git a/src/renderer/src/components/file/search-annotation/search-tagger.tsx b/src/renderer/src/components/file/search-annotation/search-tagger.tsx deleted file mode 100644 index d2df101e..00000000 --- a/src/renderer/src/components/file/search-annotation/search-tagger.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import Input from "@/components/ui/input"; -import Select from "@/components/ui/select"; -import { sva } from "@/styled/css"; -import { styled } from "@/styled/jsx"; -import { hstack } from "@/styled/patterns"; -import { type AnonymizerLabels, anonymizerLabels } from "@/types/aymurai"; -import { useState } from "react"; -import TaggerButton from "../tagger-button"; - -const IMG_SIZE = 24; - -const tagger = sva({ - slots: ["container", "button", "divider"], - base: { - container: { - ...hstack.raw({ alignItems: "center", gap: "1" }), - p: "1", - bg: "action.alt-default", - rounded: "lg", - }, - button: { - cursor: "pointer", - }, - divider: { - alignSelf: "stretch", - width: "[1px]", - bg: "[#5960B0]", - - my: "1", - }, - }, -}); - -interface MarkTaggerProps { - initialLabel: AnonymizerLabels; - initialSuffix: string; - onAddOne: () => void; - onAddAll: () => void; -} -export default function SearchTagger({ - initialLabel, - initialSuffix, - onAddOne, - onAddAll, -}: MarkTaggerProps) { - const classes = tagger(); - - const [label, setLabel] = useState( - initialLabel, - ); - const [suffix, setSuffix] = useState(initialSuffix ?? ""); - - function handleLabelChange(newLabel: AnonymizerLabels) { - setLabel(newLabel); - // TODO: figure out what to do with these - // onLabelChange?.(newLabel); - } - - function handleSuffixChange(newSuffix: string) { - setSuffix(newSuffix); - // TODO: figure out what to do with these - // onSuffixChange?.(newSuffix); - } - - return ( -
- handleSuffixChange(e.target.value)} - type="number" - min="1" - /> - -
- - Añadir uno - -
- - Añadir todas - -
- ); -} diff --git a/src/renderer/src/components/file/tag-annotation/index.tsx b/src/renderer/src/components/file/tag-annotation/index.tsx index ffbdd4f0..d7a36d11 100644 --- a/src/renderer/src/components/file/tag-annotation/index.tsx +++ b/src/renderer/src/components/file/tag-annotation/index.tsx @@ -1,3 +1,6 @@ +import { Check } from "phosphor-react"; +import { useState } from "react"; + import type { Annotation, LabelAnnotation, @@ -6,13 +9,11 @@ import type { import { useAnnotation } from "@/context/Annotation"; import { showToast } from "@/features/showToast"; import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; -import { Check } from "phosphor-react"; -import { useState } from "react"; + import AnnotationPopover from "../annotation-popover"; import SuggestionLabel from "../suggestion-label"; import RemoveDialog from "./remove-dialog"; import ReplaceDialog from "./replace-dialog"; -import TagTagger from "./tag-tagger"; interface TagAnnotationProps { children: string; @@ -29,7 +30,6 @@ export default function TagAnnotation({ const { updateLabel, - remove, removeByText, updateByText, label, @@ -79,20 +79,13 @@ export default function TagAnnotation({ return ( <> - {children} - - } - content={ - - } - /> + onClickOne={handleReplaceOne} + onClickAll={handleReplaceAll} + > + + {children} + + void; - onRemoveAll: () => void; - onReplaceOne: () => void; - onReplaceAll: () => void; -} -export default function TagTagger({ - onRemove, - onRemoveAll, - onReplaceAll, - onReplaceOne, -}: MarkTaggerProps) { - const classes = tagger(); - return ( -
- - Reemplazar una - -
- - Reemplazar todas - -
- - Removar una - -
- - Removar todas - -
- ); -} From a7e91cecec9f908ab51e02ea485bc747ed368e05 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:23:52 -0300 Subject: [PATCH 162/263] add remove dialog to label manager's entity tab --- .../anonymizer/label-manager/entity-tab.tsx | 62 ++++++++++++++----- .../anonymizer/label-manager/label.tsx | 2 +- .../label-manager/remove-dialog.tsx | 36 +++++++++++ 3 files changed, 84 insertions(+), 16 deletions(-) create mode 100644 src/renderer/src/components/anonymizer/label-manager/remove-dialog.tsx diff --git a/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx b/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx index d084bce4..413df27e 100644 --- a/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx +++ b/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx @@ -1,14 +1,14 @@ -import { Trash, XCircle } from "phosphor-react"; -import { useMemo, useState } from "react"; - -import Select from "@/components/select"; import Button from "@/components/ui/button"; import { useFiles } from "@/hooks"; import { css } from "@/styled/css"; import { HStack, Stack, styled } from "@/styled/jsx"; import { anonymizerLabels } from "@/types/aymurai"; +import { Trash, XCircle } from "phosphor-react"; +import { useMemo, useState } from "react"; +import Select from "@/components/ui/select"; import { Label } from "./label"; +import RemoveDialog from "./remove-dialog"; import LabelManagerSection from "./section"; // ─── Category config ──────────────────────────────────────────────────────── @@ -145,6 +145,12 @@ export default function LabelEntityTab({ Record >({}); + const [pendingRemoval, setPendingRemoval] = useState< + | { kind: "derived"; canonicalId: string; label: string } + | { kind: "manual"; category: string; groupId: string; label: string } + | null + >(null); + // Derive groups from predictions, merging by canonical_entity_id const derivedGroups = useMemo(() => { const result: Record = Object.fromEntries( @@ -157,7 +163,8 @@ export default function LabelEntityTab({ const { canonical_entity_id, aymurai_label } = pred.attrs; if (!canonical_entity_id) continue; - const category = labelToCategory[aymurai_label]; + const baseLabel = aymurai_label.replace(/_\d+$/, ""); + const category = labelToCategory[baseLabel]; if (!category) continue; if (byCanonicalId.has(canonical_entity_id)) { @@ -168,7 +175,7 @@ export default function LabelEntityTab({ } else { const group: DerivedGroup = { canonicalId: canonical_entity_id, - labelId: aymurai_label, + labelId: baseLabel, values: [pred.text], }; byCanonicalId.set(canonical_entity_id, group); @@ -180,9 +187,15 @@ export default function LabelEntityTab({ return result; }, [files]); - const removeDerivedGroup = (canonicalId: string) => { - setRemovedDerivedIds((prev) => [...prev, canonicalId]); - onDerivedGroupRemove?.(canonicalId); + const confirmRemoval = () => { + if (!pendingRemoval) return; + if (pendingRemoval.kind === "derived") { + setRemovedDerivedIds((prev) => [...prev, pendingRemoval.canonicalId]); + onDerivedGroupRemove?.(pendingRemoval.canonicalId); + } else { + removeManualGroup(pendingRemoval.category, pendingRemoval.groupId); + } + setPendingRemoval(null); }; const removeDerivedValue = (canonicalId: string, value: string) => { @@ -247,6 +260,13 @@ export default function LabelEntityTab({ }; return ( + <> + { if (!open) setPendingRemoval(null); }} + onConfirm={confirmRemoval} + /> {categories.map((category, i) => { const { labelIds, placeholder } = categoryConfig[category]; @@ -279,16 +299,20 @@ export default function LabelEntityTab({ - setManualGroupLabel(category, group.id, opt?.id) + setManualGroupLabel(category, group.id, opt.id) } /> + + + +
+ ); +} From 5655eac5fded8e56b56c3f7744ccafb4a0e31e3b Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:24:11 -0300 Subject: [PATCH 163/263] smaller fixes on file annotation components --- .../file/annotation-popover/tagger-button.tsx | 1 + .../file/annotation-popover/tagger.tsx | 4 +- .../src/components/file/search-annotation.tsx | 23 ++--- .../src/components/file/suggestion-label.tsx | 6 +- .../components/file/tag-annotation/index.tsx | 85 ++++++------------- .../file/tag-annotation/remove-dialog.tsx | 37 -------- .../file/tag-annotation/replace-dialog.tsx | 7 +- 7 files changed, 48 insertions(+), 115 deletions(-) delete mode 100644 src/renderer/src/components/file/tag-annotation/remove-dialog.tsx diff --git a/src/renderer/src/components/file/annotation-popover/tagger-button.tsx b/src/renderer/src/components/file/annotation-popover/tagger-button.tsx index 9c0f1810..a8ee9b90 100644 --- a/src/renderer/src/components/file/annotation-popover/tagger-button.tsx +++ b/src/renderer/src/components/file/annotation-popover/tagger-button.tsx @@ -14,6 +14,7 @@ const button = sva({ p: "0.5", rounded: "[6px]", cursor: "pointer", + flexShrink: "0", _hover: { bg: "action.hover", }, diff --git a/src/renderer/src/components/file/annotation-popover/tagger.tsx b/src/renderer/src/components/file/annotation-popover/tagger.tsx index cbfd7c59..16375978 100644 --- a/src/renderer/src/components/file/annotation-popover/tagger.tsx +++ b/src/renderer/src/components/file/annotation-popover/tagger.tsx @@ -78,7 +78,7 @@ export default function Tagger({ onClickAll, onClickOne }: MarkTaggerProps) {
Afectar todas las ocurrencias ); - function handleAddOne() { + function handleAddOne(label: AllLabels, suffix: number | null) { + const labelWithSuffix = suffix ? (`${label}_${suffix}` as const) : label; const annotationData = createAnnotationData( children, annotation as LabelAnnotation, - annotateTo ?? undefined, + labelWithSuffix, ); if (annotationData) { add(annotationData); showToast("Se agregó la etiqueta en esta ocurrencia.", "success", Check); } } - function handleAddAll() { - if (!annotateTo) return; - addBySearch(children, annotateTo); + function handleAddAll(label: AllLabels, suffix: number | null) { + const labelWithSuffix = suffix ? (`${label}_${suffix}` as const) : label; + addBySearch(children, labelWithSuffix); showToast( "Se agregó la etiqueta en todas las ocurrencias.", "success", diff --git a/src/renderer/src/components/file/suggestion-label.tsx b/src/renderer/src/components/file/suggestion-label.tsx index 685f883b..81476c71 100644 --- a/src/renderer/src/components/file/suggestion-label.tsx +++ b/src/renderer/src/components/file/suggestion-label.tsx @@ -1,13 +1,13 @@ import Suggestion from "@/components/ui/suggestion"; import { HStack, styled } from "@/styled/jsx"; -import type { AllLabels } from "@/types/aymurai"; +import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; import type { ComponentPropsWithoutRef } from "react"; interface SuggestionLabelProps extends Omit, "translate" | "color"> { isClickable?: boolean; children: string; - label: AllLabels; + label: AllLabels | AllLabelsWithSufix | undefined; } export default function SuggestionLabel({ isClickable = false, @@ -26,7 +26,7 @@ export default function SuggestionLabel({ textStyle="cta.md.strong" fontFamily="[Archivo !important]" > - {label} + {label ?? "DESCONOCIDO"} diff --git a/src/renderer/src/components/file/tag-annotation/index.tsx b/src/renderer/src/components/file/tag-annotation/index.tsx index d7a36d11..4f68c37e 100644 --- a/src/renderer/src/components/file/tag-annotation/index.tsx +++ b/src/renderer/src/components/file/tag-annotation/index.tsx @@ -8,11 +8,10 @@ import type { } from "@/components/file-annotator/types"; import { useAnnotation } from "@/context/Annotation"; import { showToast } from "@/features/showToast"; -import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; +import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; import AnnotationPopover from "../annotation-popover"; import SuggestionLabel from "../suggestion-label"; -import RemoveDialog from "./remove-dialog"; import ReplaceDialog from "./replace-dialog"; interface TagAnnotationProps { @@ -28,25 +27,13 @@ export default function TagAnnotation({ `Annotation of type "tag" expected but got: ${annotation.type}`, ); - const { - updateLabel, - removeByText, - updateByText, - label, - suffix, - isAnnotable, - } = useAnnotation(); - const [replaceAllOpen, setReplaceAllOpen] = useState(false); - const [removeAllOpen, setRemoveAllOpen] = useState(false); - const tag = annotation.tag ?? "DESCONOCIDO"; - - const annotateTo: AllLabels | AllLabelsWithSufix | null = label - ? suffix - ? `${label}_${suffix}` - : label - : null; + const { updateLabel, updateByText, updateByCanonicalId, isAnnotable } = useAnnotation(); + const [replaceAllLabelWithSuffix, setReplaceAllLabelWithSuffix] = useState< + AllLabels | AllLabelsWithSufix | null + >(null); + const tag = annotation.tag; - const { start, end, paragraphId } = annotation as LabelAnnotation; + const { start, end, paragraphId, canonical_entity_id } = annotation as LabelAnnotation; const annotationData = annotation.tag ? { text: children, @@ -87,57 +74,39 @@ export default function TagAnnotation({ !open && setReplaceAllLabelWithSuffix(null)} onConfirm={confirmReplaceAll} /> - ); - function handleReplaceOne() { - if (!annotationData || !annotateTo) return; - updateLabel(annotationData, annotateTo); + function handleReplaceOne(label: AllLabels, suffix: number | null) { + console.log({ annotationData, label }); + if (!annotationData || !label) return; + + const labelWithSuffix = suffix ? (`${label}_${suffix}` as const) : label; + updateLabel(annotationData, labelWithSuffix); showToast("Se reemplazó la etiqueta en esta ocurrencia.", "success", Check); } - function handleReplaceAll() { - setReplaceAllOpen(true); + function handleReplaceAll(label: AllLabels, suffix: number | null) { + const labelWithSuffix = suffix ? (`${label}_${suffix}` as const) : label; + setReplaceAllLabelWithSuffix(labelWithSuffix); } function confirmReplaceAll() { - if (!annotationData || !annotateTo) return; - updateByText(annotationData, annotateTo); - setReplaceAllOpen(false); - showToast( - "Se reemplazó la etiqueta en todas las ocurrencias.", - "success", - Check, - ); - } + if (!annotationData || !replaceAllLabelWithSuffix) return; - // function handleRemoveOne() { - // if (!annotationData) return; - // remove(annotationData); - // showToast("Se eliminó la etiqueta en esta ocurrencia.", "success", Check); - // } - - // function handleRemoveAll() { - // setRemoveAllOpen(true); - // } - - function confirmRemoveAll() { - if (!annotationData) return; - removeByText(annotationData); - setRemoveAllOpen(false); + if (canonical_entity_id) { + updateByCanonicalId(canonical_entity_id, replaceAllLabelWithSuffix); + } else { + updateByText(annotationData, replaceAllLabelWithSuffix); + } + setReplaceAllLabelWithSuffix(null); showToast( - "Se eliminaron todas las etiquetas de este texto.", + "Se reemplazó la etiqueta en todas las ocurrencias.", "success", Check, ); diff --git a/src/renderer/src/components/file/tag-annotation/remove-dialog.tsx b/src/renderer/src/components/file/tag-annotation/remove-dialog.tsx deleted file mode 100644 index 36a23d89..00000000 --- a/src/renderer/src/components/file/tag-annotation/remove-dialog.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import Button from "@/components/ui/button"; -import { - Dialog, - DialogContent, - DialogFooter, - DialogTitle, -} from "@/components/ui/dialog"; -import { Stack } from "@/styled/jsx"; - -interface RemoveDialogProps { - isOpen: boolean; - label: string; - onClose: (open: boolean) => void; - onConfirm: () => void; -} -export default function RemoveDialog({ - isOpen, - onClose, - onConfirm, - label, -}: RemoveDialogProps) { - return ( - - - Eliminar todas las ocurrencias - - ¿Deseas eliminar todas las ocurrencias con la etiqueta{" "} - {label}? - - - - - - - - ); -} diff --git a/src/renderer/src/components/file/tag-annotation/replace-dialog.tsx b/src/renderer/src/components/file/tag-annotation/replace-dialog.tsx index 422e60ff..c2e906b2 100644 --- a/src/renderer/src/components/file/tag-annotation/replace-dialog.tsx +++ b/src/renderer/src/components/file/tag-annotation/replace-dialog.tsx @@ -5,7 +5,6 @@ import { DialogFooter, DialogTitle, } from "@/components/ui/dialog"; -import { Stack } from "@/styled/jsx"; interface ReplaceDialogProps { isOpen: boolean; @@ -23,10 +22,10 @@ export default function ReplaceDialog({ Reemplazar todas las ocurrencias - - ¿Deseas reemplazar todas las ocurrencias con la etiqueta{" "} +

+ ¿Deseas reemplazar todas las ocurrencias del grupo con la etiqueta{" "} {label}? - +

From 01aa8a799fd871f67a6c8511a347f8acd29f6f54 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:25:23 -0300 Subject: [PATCH 164/263] fix TS issues --- src/renderer/src/components/file/search-annotation.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/renderer/src/components/file/search-annotation.tsx b/src/renderer/src/components/file/search-annotation.tsx index 894d1a3c..7ee80280 100644 --- a/src/renderer/src/components/file/search-annotation.tsx +++ b/src/renderer/src/components/file/search-annotation.tsx @@ -42,15 +42,9 @@ export default function SearchAnnotation({ `Annotation of type "search" expected but got: ${annotation.type}`, ); - const { add, addBySearch, createAnnotationData, label, suffix, isAnnotable } = + const { add, addBySearch, createAnnotationData, isAnnotable } = useAnnotation(); - // const annotateTo: AllLabels | AllLabelsWithSufix | null = label - // ? suffix - // ? `${label}_${suffix}` - // : label - // : null; - const metadata: Metadata = { "data-start": annotation.start, "data-end": annotation.end, From 9f62ac692a5584b0ba5ffde504c57176ce9a8f33 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:26:36 -0300 Subject: [PATCH 165/263] adjust predicting and file parser flows --- .../src/components/file-preview/index.tsx | 18 +- .../src/components/file-processing/index.tsx | 10 ++ src/renderer/src/hooks/useFileParse.ts | 69 ++++++++ src/renderer/src/hooks/usePredict.ts | 162 ++++++++++-------- .../src/routes/app.$feature/preview.tsx | 8 +- .../src/routes/app.$feature/process.tsx | 29 +++- src/renderer/src/services/aymurai/index.ts | 1 - src/renderer/src/services/aymurai/queries.ts | 16 ++ .../src/services/aymurai/useFileParser.ts | 47 ----- 9 files changed, 224 insertions(+), 136 deletions(-) create mode 100644 src/renderer/src/hooks/useFileParse.ts delete mode 100644 src/renderer/src/services/aymurai/useFileParser.ts diff --git a/src/renderer/src/components/file-preview/index.tsx b/src/renderer/src/components/file-preview/index.tsx index e1847514..badbe255 100644 --- a/src/renderer/src/components/file-preview/index.tsx +++ b/src/renderer/src/components/file-preview/index.tsx @@ -2,8 +2,8 @@ import { FileX } from "phosphor-react"; import { Checkbox, Spinner, Text } from "@/components"; import { useFileDispatch } from "@/hooks"; +import type { PredictStatus } from "@/hooks/usePredict"; import { toggleSelected } from "@/reducers/file/actions"; -import { useFileParser } from "@/services/aymurai/useFileParser"; import type { DocFile } from "@/types/file"; import { FeatureFlowEnum } from "@/types/features"; @@ -13,15 +13,17 @@ import * as S from "./FilePreview.styles"; interface Props { file: DocFile; + status: PredictStatus; } -export default function FilePreview({ file }: Props) { +export default function FilePreview({ file, status }: Props) { const { feature } = useParams({ from: "/app/$feature/preview" }); const { t } = useTranslation(); const dispatch = useFileDispatch(); - const { data: parsedFile, isError, isPending } = useFileParser(file.data); const isAnonymizer = feature === FeatureFlowEnum.Anonymizer; - const moreThanOneParagraph = parsedFile && parsedFile.document.length > 1; + const moreThanOneParagraph = file.paragraphs && file.paragraphs.length > 1; + const isError = status === "error"; + const isPending = status === "processing"; if (isError) { return ( @@ -50,7 +52,7 @@ export default function FilePreview({ file }: Props) { ); } - if (isPending || !parsedFile) { + if (isPending || !file.paragraphs) { return ( @@ -71,9 +73,9 @@ export default function FilePreview({ file }: Props) { )} - {parsedFile.document.map((p) => ( - - {p} + {file.paragraphs.map((p) => ( + + {p.value} ))} diff --git a/src/renderer/src/components/file-processing/index.tsx b/src/renderer/src/components/file-processing/index.tsx index 434baff3..d7f277dc 100644 --- a/src/renderer/src/components/file-processing/index.tsx +++ b/src/renderer/src/components/file-processing/index.tsx @@ -8,6 +8,7 @@ import type { PredictStatus } from "@/hooks/usePredict"; import { removeFile, replaceFile } from "@/reducers/file/actions"; import { css } from "@/styled/css"; import { Stack } from "@/styled/jsx"; +import { useQueryClient } from "@tanstack/react-query"; import ProgressBar from "./ProgressBar"; function ActionButton({ @@ -45,6 +46,7 @@ export default function FileProcessing({ }: Props) { const inputRef = useRef(null); const dispatch = useFileDispatch(); + const queryClient = useQueryClient(); const handleOpenFinder = () => { inputRef.current?.click(); @@ -56,6 +58,14 @@ export default function FileProcessing({ if (rawFiles) { const files = Array.from(rawFiles); if (files.length > 0) { + queryClient.removeQueries({ queryKey: ["file-parser", fileName], exact: false }); + queryClient.removeQueries({ queryKey: ["disambiguate", fileName], exact: false }); + queryClient.removeQueries({ + predicate: (query) => { + const key = query.queryKey as unknown[]; + return key[0] === "predict" && key[2] === fileName; + }, + }); dispatch(replaceFile(fileName, files[0])); } } diff --git a/src/renderer/src/hooks/useFileParse.ts b/src/renderer/src/hooks/useFileParse.ts new file mode 100644 index 00000000..62c09418 --- /dev/null +++ b/src/renderer/src/hooks/useFileParse.ts @@ -0,0 +1,69 @@ +import { useEffect, useState } from "react"; + +import { useFileDispatch } from "@/hooks"; +import { addParagraphs } from "@/reducers/file/actions"; +import { fileParser } from "@/services/aymurai/queries"; +import type { DocFile } from "@/types/file"; +import { useQueries, useQueryClient } from "@tanstack/react-query"; + +import type { PredictStatus } from "./usePredict"; + +export function useFileParse( + files: DocFile[], +): Record void }> { + const dispatch = useFileDispatch(); + const queryClient = useQueryClient(); + const [abortedFiles, setAbortedFiles] = useState>(new Set()); + + const queries = useQueries({ + queries: files.map((file) => ({ + ...fileParser(file.data), + enabled: !abortedFiles.has(file.data.name), + })), + }); + + useEffect(() => { + queries.forEach((query, i) => { + const file = files[i]; + // Use the Redux state as the guard: if paragraphs are already set, skip. + // This correctly re-dispatches when the same file is reloaded after a replace. + if (!query.isSuccess || !query.data || file.paragraphs !== undefined) + return; + dispatch( + addParagraphs( + query.data.document.map((p) => ({ + value: p, + document_id: query.data.document_id, + id: p, + })), + file.data.name, + ), + ); + }); + }); + + const result: Record void }> = + {}; + files.forEach((file, i) => { + const q = queries[i]; + const fileName = file.data.name; + const isAborted = abortedFiles.has(fileName); + result[fileName] = { + status: isAborted + ? "stopped" + : q.isError + ? "error" + : q.isSuccess + ? "completed" + : "processing", + abort: () => { + queryClient.cancelQueries({ + queryKey: ["file-parser", fileName], + exact: false, + }); + setAbortedFiles((prev) => new Set([...prev, fileName])); + }, + }; + }); + return result; +} diff --git a/src/renderer/src/hooks/usePredict.ts b/src/renderer/src/hooks/usePredict.ts index f10c4073..03aef588 100644 --- a/src/renderer/src/hooks/usePredict.ts +++ b/src/renderer/src/hooks/usePredict.ts @@ -1,85 +1,103 @@ -import { useCallback, useEffect, useRef, useState } from "react"; +import { useState } from "react"; import { useFileDispatch } from "@/hooks"; import { addPredictions, removePredictions } from "@/reducers/file/actions"; -import { predict } from "@/services/aymurai"; - -import { FeatureFlowEnum } from "@/types/features"; +import predict from "@/services/aymurai/predict"; +import { predictParagraph } from "@/services/aymurai/queries"; +import type { Workflows } from "@/types/aymurai"; import type { DocFile } from "@/types/file"; -import { useParams } from "@tanstack/react-router"; +import { useQueries, useQueryClient } from "@tanstack/react-query"; export type PredictStatus = "processing" | "error" | "stopped" | "completed"; -interface UsePredictOptions { - onStatusChange?: (status: PredictStatus) => void; -} +type FilePredict = { + progress: number; + status: PredictStatus; + abort: () => void; +}; + +/** + * Runs predictions for all paragraphs across all given files in parallel via + * React Query. Dispatches results to the Redux file store as each paragraph + * resolves. Returns a per-filename map of `{ progress, status, abort }`. + * + * Abort uses `queryClient.cancelQueries` so there are no manual AbortController + * references to track or clean up. + */ export function usePredict( - file: DocFile, - { onStatusChange }: UsePredictOptions, -) { - const { feature } = useParams({ from: "/app/$feature/process" }); - - const [progress, setProgress] = useState(0); - const [status, setStatus] = useState("processing"); + files: DocFile[], + workflow: Workflows, +): Record { const dispatch = useFileDispatch(); - - const isAnonimizing = feature === FeatureFlowEnum.Anonymizer; - const paragraphs = file.paragraphs; - - // Store static values - const controller = useRef(new AbortController()); - - // Handlers - const updateStatus = useCallback((newValue: PredictStatus) => { - setStatus(newValue); - onStatusChange?.(newValue); - // This next line is disabled because the function should only be created once - }, []); - - const abort = () => { - controller.current.abort(); - - dispatch(removePredictions(file.data.name)); - updateStatus("stopped"); - setProgress(0); - }; - - // Stream predictions - useEffect(() => { - let loading = true; - - const fetch = async () => { - if (!loading || !paragraphs || status !== "processing") return; - - const promises = paragraphs.map(async (p) => { - const prediction = await predict( - p, - controller.current, - isAnonimizing ? "anonymizer" : "datapublic", - ); - - dispatch(addPredictions(file.data.name, prediction)); - // Increase progress % - setProgress((current) => current + 1 / paragraphs!.length); - }); - - // Once all promises are resolved, set status to completed or error if applicable - await Promise.all(promises) - .then(() => { - updateStatus("completed"); - }) - .catch(() => { - setProgress(0); - updateStatus("error"); + const queryClient = useQueryClient(); + const [abortedFiles, setAbortedFiles] = useState>(new Set()); + + // Flatten all (file, paragraph) pairs — one React Query entry each + const pairs = files.flatMap((file) => + (file.paragraphs ?? []).map((paragraph) => ({ file, paragraph })), + ); + + const queries = useQueries({ + queries: pairs.map(({ file, paragraph }) => ({ + // Use the factory for the query key and shared defaults (staleTime, retry) + ...predictParagraph(paragraph, workflow, file.data.name), + enabled: !abortedFiles.has(file.data.name), + // Override queryFn to dispatch to Redux as each paragraph arrives. + // Defined inline to avoid TS's `queryFn?: ...` optionality on the factory type. + queryFn: async ({ signal }: { signal?: AbortSignal }) => { + const controller = new AbortController(); + signal?.addEventListener("abort", () => controller.abort()); + const predictions = await predict(paragraph, controller, workflow); + dispatch(addPredictions(file.data.name, predictions)); + return predictions; + }, + })), + }); + + // Build per-file { progress, status, abort } from the flat query results + const result: Record = {}; + + for (const file of files) { + const fileName = file.data.name; + const total = (file.paragraphs ?? []).length; + + // Collect only the queries that belong to this file + const fileQueries = pairs.reduce<(typeof queries)[number][]>( + (acc, pair, i) => { + if (pair.file.data.name === fileName) acc.push(queries[i]); + return acc; + }, + [], + ); + + const successCount = fileQueries.filter((q) => q.isSuccess).length; + const errorCount = fileQueries.filter((q) => q.isError).length; + const progress = total > 0 ? successCount / total : 0; + const isAborted = abortedFiles.has(fileName); + + const status: PredictStatus = isAborted + ? "stopped" + : errorCount > 0 + ? "error" + : total === 0 || successCount === total + ? "completed" + : "processing"; + + result[fileName] = { + progress, + status, + abort: () => { + // Cancel all in-flight paragraph queries for this file via RQ's own + // cancellation mechanism — no manual controller refs to clean up + queryClient.cancelQueries({ + queryKey: ["predict", workflow, fileName], + exact: false, }); + dispatch(removePredictions(fileName)); + setAbortedFiles((prev) => new Set([...prev, fileName])); + }, }; + } - fetch(); - - return () => { - loading = false; - }; - }, [controller, status]); - - return { progress, abort, status }; + return result; } diff --git a/src/renderer/src/routes/app.$feature/preview.tsx b/src/renderer/src/routes/app.$feature/preview.tsx index f0e5f35f..6d116016 100644 --- a/src/renderer/src/routes/app.$feature/preview.tsx +++ b/src/renderer/src/routes/app.$feature/preview.tsx @@ -8,6 +8,7 @@ import BackButton from "@/components/ui/back-button"; import Card from "@/components/ui/card"; import RequireFile from "@/features/RequireFile"; import { useFileDispatch, useFiles } from "@/hooks"; +import { useFileParse } from "@/hooks/useFileParse"; import { SectionTitle } from "@/layout/section-title"; import { addFiles, filterUnselected } from "@/reducers/file/actions"; import { css } from "@/styled/css"; @@ -36,6 +37,7 @@ function RouteComponent() { const files = useFiles(); const dispatch = useFileDispatch(); + const parseStatuses = useFileParse(files); const isProcessing = files.some((file) => !file.paragraphs); @@ -83,7 +85,11 @@ function RouteComponent() { {files.map((file) => ( - + ))}
diff --git a/src/renderer/src/routes/app.$feature/process.tsx b/src/renderer/src/routes/app.$feature/process.tsx index cad128db..9dc55a0e 100644 --- a/src/renderer/src/routes/app.$feature/process.tsx +++ b/src/renderer/src/routes/app.$feature/process.tsx @@ -9,6 +9,7 @@ import Card from "@/components/ui/card"; import RequireFile from "@/features/RequireFile"; import { useFileDispatch, useFiles } from "@/hooks"; import { useDisambiguate } from "@/hooks/useDisambiguate"; +import { useFileParse } from "@/hooks/useFileParse"; import { type PredictStatus, usePredict } from "@/hooks/usePredict"; import { SectionTitle } from "@/layout/section-title"; import { filterUnprocessed } from "@/reducers/file/actions"; @@ -45,6 +46,7 @@ function RouteComponent() { const workflow: Workflows = feature === FeatureFlowEnum.Anonymizer ? "anonymizer" : "datapublic"; + const parseStatuses = useFileParse(files); const fileStatuses = usePredict(files, workflow); const disambiguateStatuses = useDisambiguate( files, @@ -62,35 +64,48 @@ function RouteComponent() { const isProcessing = files.some( (f) => + parseStatuses[f.data.name]?.status === "processing" || fileStatuses[f.data.name]?.status === "processing" || disambiguateStatuses[f.data.name]?.status === "processing", ); - // For the anonymizer flow there are two sequential steps (predict + disambiguate), - // so each contributes half the progress bar. For datapublic, predict is the only step. + // Weighted progress: 10% parse / 70% predict / 20% disambiguate (anonymizer) + // or 10% parse / 90% predict (datapublic). const getProgress = (fileName: string): number => { + const parseDone = parseStatuses[fileName]?.status === "completed" ? 1 : 0; const predictProgress = fileStatuses[fileName]?.progress ?? 0; - if (workflow !== "anonymizer") return predictProgress; + if (workflow !== "anonymizer") { + return parseDone * 0.1 + predictProgress * 0.9; + } const disambiguateDone = - disambiguateStatuses[fileName]?.status === "completed"; - return (predictProgress + (disambiguateDone ? 1 : 0)) / 2; + disambiguateStatuses[fileName]?.status === "completed" ? 1 : 0; + return parseDone * 0.1 + predictProgress * 0.7 + disambiguateDone * 0.2; }; - // Status must also account for both steps so "completed" text only shows when the - // bar is genuinely at 100%. + // Status accounts for all three stages so "completed" only shows at 100%. const getCombinedStatus = (fileName: string): PredictStatus => { + const parseStatus = parseStatuses[fileName]?.status ?? "processing"; + if (parseStatus !== "completed") return parseStatus; + const predictStatus = fileStatuses[fileName]?.status ?? "processing"; if (workflow !== "anonymizer" || predictStatus !== "completed") return predictStatus; + return disambiguateStatuses[fileName]?.status ?? "processing"; }; const handleAbort = (file: DocFile) => () => { + queryClient.removeQueries({ + queryKey: ["file-parser", file.data.name], + exact: false, + }); queryClient.removeQueries({ queryKey: ["predict", feature, file.data.name], + exact: false, }); fileStatuses[file.data.name]?.abort?.(); + parseStatuses[file.data.name]?.abort?.(); }; return ( diff --git a/src/renderer/src/services/aymurai/index.ts b/src/renderer/src/services/aymurai/index.ts index af651c7a..35a0de7d 100644 --- a/src/renderer/src/services/aymurai/index.ts +++ b/src/renderer/src/services/aymurai/index.ts @@ -2,7 +2,6 @@ import predict from "./predict"; export { predict }; export * from "./useConnectToHost"; -export * from "./useFileParser"; export * from "./useRunLocalServer"; export * as aymuraiService from "./queries"; diff --git a/src/renderer/src/services/aymurai/queries.ts b/src/renderer/src/services/aymurai/queries.ts index d8a4b883..fd4d426c 100644 --- a/src/renderer/src/services/aymurai/queries.ts +++ b/src/renderer/src/services/aymurai/queries.ts @@ -1,4 +1,5 @@ import { disambiguateSchema } from "@/schema/disambiguate"; +import { documentExtractSchema } from "@/schema/extract"; import type { PredictLabel, Workflows } from "@/types/aymurai"; import type { DocFile, Paragraph } from "@/types/file"; import { mutationOptions, queryOptions } from "@tanstack/react-query"; @@ -117,6 +118,21 @@ export const disambiguate = (file: DocFile) => }, }); +export const fileParser = (file: File) => + queryOptions({ + queryKey: ["file-parser", file.name, file.size], + queryFn: async () => { + const formData = new FormData(); + formData.append("file", file); + const response = await api.post("/misc/document-extract", formData, { + headers: { "Content-Type": "multipart/form-data" }, + }); + return documentExtractSchema.parse(response.data); + }, + retry: false, + retryOnMount: false, + }); + export const odtToPdf = () => mutationOptions({ mutationFn: async (file: Blob) => { diff --git a/src/renderer/src/services/aymurai/useFileParser.ts b/src/renderer/src/services/aymurai/useFileParser.ts deleted file mode 100644 index 9d767a30..00000000 --- a/src/renderer/src/services/aymurai/useFileParser.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { useEffect } from "react"; - -import { useFileDispatch } from "@/hooks"; -import { addParagraphs } from "@/reducers/file/actions"; -import { documentExtractSchema } from "@/schema/extract"; - -import { useQuery } from "@tanstack/react-query"; -import api from "../api"; - -export function useFileParser(file: File) { - const dispatch = useFileDispatch(); - - const query = useQuery({ - queryKey: ["file-parser", file.name, file.size], - queryFn: async () => { - const formData = new FormData(); - formData.append("file", file); - - const response = await api.post("/misc/document-extract", formData, { - headers: { "Content-Type": "multipart/form-data" }, - }); - - return documentExtractSchema.parse(response.data); - }, - retry: false, - retryOnMount: false, - }); - - useEffect(() => { - if (query.isSuccess && query.data) { - // TODO: remove redux in the future - dispatch( - addParagraphs( - // Convert structure for backwards compatibility - query.data.document.map((p) => ({ - value: p, - document_id: query.data.document_id, - id: p, - })), - file.name, - ), - ); - } - }, [query.isSuccess]); - - return query; -} From d10fe8c707d7766f0400e1e7573dc8543ae701ba Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:26:52 -0300 Subject: [PATCH 166/263] add useShallow to local storage default getters --- src/renderer/src/store/useLocal.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/renderer/src/store/useLocal.ts b/src/renderer/src/store/useLocal.ts index 09a3da1a..56ca1647 100644 --- a/src/renderer/src/store/useLocal.ts +++ b/src/renderer/src/store/useLocal.ts @@ -1,4 +1,5 @@ import { create } from "zustand"; +import { useShallow } from "zustand/react/shallow"; import { devtools, persist } from "zustand/middleware"; import type { AnonymizerLabels } from "../types/aymurai"; import { FeatureFlowEnum } from "../types/features"; @@ -66,9 +67,9 @@ export const useSetTutorialSeen = () => useLocalStore((state) => state.setTutorialSeen); export const useExcludedTagsConfig = () => - useLocalStore((s) => ({ tags: s.excludedTags, words: s.excludedWords })); + useLocalStore(useShallow((s) => ({ tags: s.excludedTags, words: s.excludedWords }))); export const useExcludedTagsConfigActions = () => - useLocalStore((s) => ({ + useLocalStore(useShallow((s) => ({ setTags: s.setExcludedTags, setWords: s.setExcludedWords, - })); + }))); From 6aa895f4ef2f268f12e290210a96194374e146dc Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:29:55 -0300 Subject: [PATCH 167/263] simplify and remove unused code on fille annotator component --- .../file-annotator/FileAnnotator.styles.ts | 114 +----- .../src/components/file-annotator/Mark.tsx | 343 ------------------ .../components/file-annotator/annotations.ts | 6 +- .../src/components/file-annotator/index.tsx | 125 ++++--- .../src/components/file-annotator/types.ts | 1 + 5 files changed, 80 insertions(+), 509 deletions(-) delete mode 100644 src/renderer/src/components/file-annotator/Mark.tsx diff --git a/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts b/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts index e66007a2..5c825801 100644 --- a/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts +++ b/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts @@ -21,122 +21,10 @@ export const File = styled("div", { "& p, & span, & em": { fontFamily: "$file", fontSize: 16, - lineHeight: "100%", - my: "1em", + lineHeight: "160%", }, }); export const Paragraph = styled("p", { margin: "8px 0px", }); - -export const ButtonContainer = styled("div", { - position: "absolute", - top: "-36px", - right: "50%", - transform: "translateX(50%)", - - display: "flex", - alignItems: "center", - gap: "1px", - - visibility: "hidden", - - background: "#787fc9", - borderRadius: "4px", - padding: "2px", - - "&::before": { - content: "", - position: "absolute", - width: "100%", - height: "calc(16px + 100%)", - left: "50%", - top: "0", - transform: "translateX(-50%)", - zIndex: -1, - }, -}); - -export const Button = styled("button", { - background: "transparent", - border: "none", - cursor: "pointer", - display: "flex", - alignItems: "center", - justifyContent: "center", - transition: "background-color 0.2s", - width: "28px", - height: "28px", - flexShrink: 0, - - "&:hover": { - background: "rgba(0, 0, 0, 0.1)", - }, - - variants: { - smallImage: { - true: { - padding: "2px", - - img: { - width: "24px", - height: "24px", - }, - }, - false: { - padding: "4px", - - img: { - width: "20px", - height: "20px", - }, - }, - }, - }, - defaultVariants: { - smallImage: false, - }, -}); - -export const Mark = styled("mark", { - position: "relative", - overflowWrap: "break-word", - padding: "0px 2px", - borderRadius: 8, - - [`&:hover ${ButtonContainer}`]: { - visibility: "visible", - }, - - variants: { - type: { - tag: { - backgroundColor: "$primaryAlt", - - "& strong": { - fontSize: "12px", - padding: "0px", - ml: "6px", - }, - }, - search: { - borderRadius: 0, - fontWeight: 700, - backgroundColor: "$bgSearch", - }, - }, - annotable: { - true: { - cursor: "pointer", - }, - false: { - cursor: "default", - }, - }, - }, - defaultVariants: { - type: "tag", - annotable: false, - }, -}); diff --git a/src/renderer/src/components/file-annotator/Mark.tsx b/src/renderer/src/components/file-annotator/Mark.tsx deleted file mode 100644 index c30cff1b..00000000 --- a/src/renderer/src/components/file-annotator/Mark.tsx +++ /dev/null @@ -1,343 +0,0 @@ -import Select, { type SelectOption } from "@/components/select"; -import Input from "@/components/ui/input"; -import { useAnnotation } from "@/context/Annotation"; -import { - type AllLabels, - type AllLabelsWithSufix, - anonymizerLabels, -} from "@/types/aymurai"; -import { type FC, type HTMLAttributes, useRef, useState } from "react"; -import Dialog, { DialogButtons, DialogMessage } from "../dialog"; -import Button from "../ui/button"; -import * as S from "./FileAnnotator.styles"; -import type { Annotation, LabelAnnotation, Metadata } from "./types"; - -interface MarkProps extends HTMLAttributes { - annotation: Annotation; - children: string; -} - -type DialogState = { - open: boolean; - title?: string; - action: "replace" | "replaceAll" | "removeAll"; - suffix: number | null; - selectedOption: SelectOption | undefined; -}; - -export const Mark: FC = ({ children, annotation, ...props }) => { - const { - add, - remove, - removeByText, - isAnnotable, - updateLabel, - updateByText, - addBySearch, - } = useAnnotation(); - const [dialogState, setDialogState] = useState({ - open: false, - title: "Reemplazar", - action: "replace", - suffix: null, - selectedOption: undefined, - }); - const inputLabelSufixRef = useRef(null); - - const annotationOperations = { - add, - remove, - removeByText, - }; - - let metadata: Metadata = { - "data-start": annotation.start, - "data-end": annotation.end, - }; - - if (annotation.type !== "text") { - metadata = { - ...metadata, - "data-tag": annotation.tag, - }; - } - - const createAnnotationData = (annotation: LabelAnnotation) => { - const { start, end, paragraphId, tag } = annotation; - if (!tag) return null; - return { - text: children, - start_char: start, - end_char: end, - paragraphId: paragraphId, - attrs: { - aymurai_label: tag, - aymurai_label_subclass: null, - aymurai_alt_text: null, - aymurai_alt_start_char: start, - aymurai_alt_end_char: end, - }, - }; - }; - - const handleAnnotationOperation = ( - operation: keyof typeof annotationOperations, - ) => { - const annotationData = createAnnotationData(annotation as LabelAnnotation); - if (!annotationData) return; - - if (operation === "removeByText") { - setDialogState({ - open: true, - action: "removeAll", - suffix: null, - selectedOption: undefined, - }); - } else { - annotationOperations[operation](annotationData); - } - }; - - const handleRemoveAll = () => { - const annotationData = createAnnotationData(annotation as LabelAnnotation); - if (!annotationData) return; - - setDialogState({ - open: true, - action: "removeAll", - suffix: null, - selectedOption: undefined, - }); - }; - - const handleRemove = () => { - const annotationData = createAnnotationData(annotation as LabelAnnotation); - if (!annotationData) return; - - remove(annotationData); - }; - - const handleAddBySearch = (annotation: LabelAnnotation) => { - if (!annotation?.tag) return; - - addBySearch(children, annotation.tag); - }; - - const changeLabelSelectHandler = (option: SelectOption | undefined) => { - setDialogState((state) => ({ - ...state, - selectedOption: option, - })); - }; - - const applyChanges = () => { - if (!dialogState.selectedOption) { - if (dialogState.action === "removeAll") { - const annotationData = createAnnotationData( - annotation as LabelAnnotation, - ); - if (!annotationData) return; - - removeByText(annotationData); - } - } else { - const annotationData = createAnnotationData( - annotation as LabelAnnotation, - ); - if (!annotationData) return; - - const labelWithSuffix = dialogState.suffix - ? (`${dialogState.selectedOption.id}_${dialogState.suffix}` as AllLabelsWithSufix) - : (dialogState.selectedOption.id as AllLabels | AllLabelsWithSufix); - - if (dialogState.action === "replace") { - updateLabel(annotationData, labelWithSuffix); - } else if (dialogState.action === "replaceAll") { - updateByText(annotationData, labelWithSuffix); - } - } - - setDialogState((state) => ({ - ...state, - open: false, - suffix: null, - selectedOption: undefined, - })); - }; - - const changeLabelSufixHandler = (value: string) => { - setDialogState((state) => ({ - ...state, - suffix: value ? Number(value) : null, - })); - }; - - switch (annotation.type) { - case "tag": - case "search": - return ( - <> - - {children} - - {annotation.type === "tag" && {annotation.tag}} - - {isAnnotable && annotation.type === "search" && annotation.tag ? ( - - handleAnnotationOperation("add")} - title="Agregar esta ocurrencia" - > - +¹ - - handleAddBySearch(annotation)} - title="Agregar todas las ocurrencias" - > - + - - - ) : annotation.tag ? ( - - { - setDialogState({ - open: true, - title: "Reemplazar esta ocurrencia", - action: "replace", - suffix: null, - selectedOption: undefined, - }); - }} - title="Reemplazar esta ocurrencia" - > - Replace One - - { - setDialogState({ - open: true, - title: "Reemplazar todas las ocurrencias", - action: "replaceAll", - suffix: null, - selectedOption: undefined, - }); - }} - title="Reemplazar todas las ocurrencias" - > - Replace All - - handleRemove()} - title="Eliminar esta ocurrencia" - > - Delete One - - handleRemoveAll()} - title="Eliminar todas las ocurrencias" - > - Delete All - - - ) : null} - - - setDialogState((state) => ({ - ...state, - open: false, - suffix: null, - selectedOption: undefined, - })) - } - > - {dialogState.action === "removeAll" ? ( - <> - - ¿Deseas eliminar todas las etiquetas {children}? - - - - - - - ) : ( - <> - - Por favor, introduce la nueva etiqueta para reemplazar{" "} - {dialogState.action === "replace" - ? "esta ocurrencia" - : "todas las ocurrencias"}{" "} - de {children}. - - - - - - - - )} - - - ); - case "text": - default: - return ( - - {children} - - ); - } -}; diff --git a/src/renderer/src/components/file-annotator/annotations.ts b/src/renderer/src/components/file-annotator/annotations.ts index a171745b..ab846f64 100644 --- a/src/renderer/src/components/file-annotator/annotations.ts +++ b/src/renderer/src/components/file-annotator/annotations.ts @@ -21,6 +21,7 @@ const labelToAnnotation = (labels: PredictLabel[]): Annotation[] => { type: "tag", tag: attrs.aymurai_label!, paragraphId, + canonical_entity_id: attrs.canonical_entity_id, })); }; @@ -76,7 +77,7 @@ const getSearchAnnotations = ( * @param predictions List of labels predicted by AymurAI * @returns A map with the paragraph id as key and an array of predictions as value */ -const predictionsToMap = ( +export const predictionsToMap = ( predictions: PredictLabel[], ): Map => { const map = new Map(); @@ -109,8 +110,7 @@ export const createAnnotationsWithSearch = ( paragraph: Paragraph, searchLabel: AllLabels | AllLabelsWithSufix | null, ): Annotation[] => { - const matchingLabels = predictionsToMap(predictions).get(paragraph.id) ?? []; - const matchingAnnotations = labelToAnnotation(matchingLabels); + const matchingAnnotations = labelToAnnotation(predictions); const searchAnnotations = getSearchAnnotations( search, paragraph, diff --git a/src/renderer/src/components/file-annotator/index.tsx b/src/renderer/src/components/file-annotator/index.tsx index f8b42219..8d32aa07 100644 --- a/src/renderer/src/components/file-annotator/index.tsx +++ b/src/renderer/src/components/file-annotator/index.tsx @@ -1,42 +1,71 @@ -import { useMemo, useState } from "react"; +import { memo, useMemo, useState, useTransition } from "react"; import { SearchBar } from "./SearchBar"; import type { SelectOption } from "@/components/ui/select"; -import AnnotationProvider from "@/context/Annotation"; +import AnnotationProvider, { useAnnotation } from "@/context/Annotation"; import { HStack } from "@/styled/jsx"; -import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; -import type { DocFile } from "@/types/file"; +import type { AllLabels, AllLabelsWithSufix, PredictLabel } from "@/types/aymurai"; +import type { DocFile, Paragraph as ParagraphType } from "@/types/file"; import LabelManager from "../anonymizer/label-manager"; +import SearchAnnotation from "../file/search-annotation"; +import TagAnnotation from "../file/tag-annotation"; import * as S from "./FileAnnotator.styles"; -import { Mark } from "./Mark"; -import { createAnnotationsWithSearch } from "./annotations"; +import { createAnnotationsWithSearch, predictionsToMap } from "./annotations"; import { generateSplits } from "./generateSplits"; -import type { Annotation } from "./types"; interface ParagraphProps { children: string; - annotations?: Annotation[]; - id: string; + search: string; + paragraph: ParagraphType; + predictions: PredictLabel[]; } -const Paragraph = ({ children, annotations = [], id }: ParagraphProps) => { +const Paragraph = memo(({ children, search, paragraph, predictions }: ParagraphProps) => { + const { label, suffix } = useAnnotation(); + const searchTag = label + ? suffix + ? (`${label}_${suffix}` as AllLabelsWithSufix) + : label + : null; + + const annotations = useMemo(() => { + return createAnnotationsWithSearch( + predictions, + search, + paragraph, + searchTag, + ); + }, [predictions, search, paragraph, searchTag]); + const splits = generateSplits(children, annotations); return ( - + {splits.map((s) => { const content = children.slice(s.start, s.end); const key = `${s.start}-${s.end}`; - return ( - - {content} - - ); + switch (s.type) { + case "search": + return ( + + {content} + + ); + case "tag": + return ( + + {content} + + ); + case "text": + default: + return {content}; + } })} ); -}; +}); interface Props { file: DocFile; @@ -44,63 +73,59 @@ interface Props { } export default function FileAnnotator({ file, isAnnotable = false }: Props) { const [search, setSearch] = useState(""); + const [, startTransition] = useTransition(); - const [labelSearch, setLabelSearch] = useState(null); - const [sufixlabelSearch, setSufixLabelSearch] = useState(0); + const [label, setLabel] = useState(null); + const [suffix, setSuffix] = useState(0); const [labelManagerOpen, setLabelManagerOpen] = useState(false); - const searchTag = useMemo(() => { - return labelSearch - ? sufixlabelSearch - ? `${labelSearch}_${sufixlabelSearch}` - : labelSearch - : null; - }, [labelSearch, sufixlabelSearch]); - const paragraphs = file.paragraphs!; + const predictionsMap = useMemo( + () => predictionsToMap(file.predictions ?? []), + [file.predictions], + ); + const selectChangeHandler = (option?: SelectOption) => { - // We're sure the option is an AllLabels enum. - // Check the type following the SearchBar component - setLabelSearch((option?.id as AllLabels) ?? null); + setLabel((option?.id as AllLabels) ?? null); }; const toggleManagerLabel = () => { setLabelManagerOpen(!labelManagerOpen); }; + const handleSearchChange = (value: string) => { + startTransition(() => setSearch(value)); + }; + return ( - {paragraphs.map((p) => { - const annotations = createAnnotationsWithSearch( - file.predictions ?? [], - search, - p, - searchTag, - ); - return ( - - {p.value} - - ); - })} + {paragraphs.map((p) => ( + + {p.value} + + ))} diff --git a/src/renderer/src/components/file-annotator/types.ts b/src/renderer/src/components/file-annotator/types.ts index f461a302..89c1b950 100644 --- a/src/renderer/src/components/file-annotator/types.ts +++ b/src/renderer/src/components/file-annotator/types.ts @@ -9,6 +9,7 @@ export interface LabelAnnotation extends BaseAnnotation { type: "tag" | "search"; paragraphId: string; tag?: AllLabels | AllLabelsWithSufix; + canonical_entity_id?: string | null; } export interface TextAnnotation extends BaseAnnotation { type: "text"; From 74d4dac299b1dc2a4a659e448c0b04c620912a9a Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:30:09 -0300 Subject: [PATCH 168/263] add value as undefined on ui/input component --- src/renderer/src/components/ui/input.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/src/components/ui/input.tsx b/src/renderer/src/components/ui/input.tsx index 83e69483..674a1efd 100644 --- a/src/renderer/src/components/ui/input.tsx +++ b/src/renderer/src/components/ui/input.tsx @@ -118,7 +118,7 @@ interface InputProps helper?: string; // Control id?: string; - value: string; + value: string | undefined; onChange?: React.ChangeEventHandler; disabled?: boolean; error?: string | null; From de2b641caec7ac694098e7db59ba4aa0a4a11fbe Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:30:43 -0300 Subject: [PATCH 169/263] add random cannonical id on search add event --- src/renderer/src/context/Annotation/index.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/renderer/src/context/Annotation/index.tsx b/src/renderer/src/context/Annotation/index.tsx index ad5ff922..32670ddf 100644 --- a/src/renderer/src/context/Annotation/index.tsx +++ b/src/renderer/src/context/Annotation/index.tsx @@ -118,6 +118,8 @@ export default function AnnotationProvider({ (search: string, label: AllLabels | AllLabelsWithSufix) => { if (!search || search.length < 3) return; + const canonical_entity_id = crypto.randomUUID(); + file.paragraphs?.forEach((paragraph: Paragraph) => { const indexes = findSearchIndexes(paragraph.value, search); indexes.forEach((start: number) => { @@ -132,6 +134,7 @@ export default function AnnotationProvider({ aymurai_alt_text: null, aymurai_alt_start_char: start, aymurai_alt_end_char: start + search.length, + canonical_entity_id, }, }; dispatch(appendPrediction(file.data.name, prediction)); From ae09277cb085cbb046e509e5cc80b425640dcfcb Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:30:54 -0300 Subject: [PATCH 170/263] add update by cannonical id function --- src/renderer/src/context/Annotation/index.tsx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/renderer/src/context/Annotation/index.tsx b/src/renderer/src/context/Annotation/index.tsx index 32670ddf..fd422e77 100644 --- a/src/renderer/src/context/Annotation/index.tsx +++ b/src/renderer/src/context/Annotation/index.tsx @@ -5,6 +5,7 @@ import { removePrediction, removePredictionsByText, updatePredictionLabel, + updatePredictionsByCanonicalId, updatePredictionsByText, } from "@/reducers/file/actions"; import type { @@ -37,6 +38,10 @@ interface AnnotationContextValues { prediction: PredictLabel, newLabel: AllLabels | AllLabelsWithSufix, ) => void; + updateByCanonicalId: ( + canonicalId: string, + newLabel: AllLabels | AllLabelsWithSufix, + ) => void; addBySearch: (search: string, label: AllLabels | AllLabelsWithSufix) => void; } @@ -52,6 +57,7 @@ export const AnnotationContext = createContext({ removeByText: () => {}, updateLabel: () => {}, updateByText: () => {}, + updateByCanonicalId: () => {}, addBySearch: () => {}, }); AnnotationContext.displayName = "AnnotationContext"; @@ -114,6 +120,13 @@ export default function AnnotationProvider({ [dispatch, file.data.name], ); + const updateByCanonicalId = useCallback( + (canonicalId: string, newLabel: AllLabels | AllLabelsWithSufix) => { + dispatch(updatePredictionsByCanonicalId(canonicalId, newLabel)); + }, + [dispatch], + ); + const addBySearch = useCallback( (search: string, label: AllLabels | AllLabelsWithSufix) => { if (!search || search.length < 3) return; @@ -191,6 +204,7 @@ export default function AnnotationProvider({ removeByText, updateLabel, updateByText, + updateByCanonicalId, addBySearch, }} > @@ -209,6 +223,7 @@ export const useAnnotation = () => { suffix, updateLabel, updateByText, + updateByCanonicalId, addBySearch, } = useContext(AnnotationContext); @@ -245,6 +260,7 @@ export const useAnnotation = () => { suffix, updateLabel, updateByText, + updateByCanonicalId, addBySearch, createAnnotationData, }; From 528c646fc87bf92cf8de03bbdf7ed71bff02c0c3 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:31:29 -0300 Subject: [PATCH 171/263] add more canonical id operations on reducers --- src/renderer/src/reducers/file/actions.ts | 58 +++++++++++++++++++++++ src/renderer/src/reducers/file/index.ts | 50 ++++++++++++++++++- 2 files changed, 107 insertions(+), 1 deletion(-) diff --git a/src/renderer/src/reducers/file/actions.ts b/src/renderer/src/reducers/file/actions.ts index be2c085e..d840a7a4 100644 --- a/src/renderer/src/reducers/file/actions.ts +++ b/src/renderer/src/reducers/file/actions.ts @@ -28,6 +28,9 @@ export enum ActionTypes { REMOVE_PREDICTIONS_BY_TEXT = "REMOVE_PREDICTIONS_BY_TEXT", UPDATE_PREDICTION_LABEL = "UPDATE_PREDICTION_LABEL", UPDATE_PREDICTIONS_BY_TEXT = "UPDATE_PREDICTIONS_BY_TEXT", + REMOVE_PREDICTIONS_BY_CANONICAL_ID = "REMOVE_PREDICTIONS_BY_CANONICAL_ID", + REMOVE_PREDICTION_VALUE_BY_CANONICAL_ID = "REMOVE_PREDICTION_VALUE_BY_CANONICAL_ID", + UPDATE_PREDICTIONS_BY_CANONICAL_ID = "UPDATE_PREDICTIONS_BY_CANONICAL_ID", } /** @@ -343,3 +346,58 @@ export function updatePredictionsByText( payload: { fileName, text, newLabel }, }; } + +export type RemovePredictionsByCanonicalId = Action< + ActionTypes.REMOVE_PREDICTIONS_BY_CANONICAL_ID, + { canonicalId: string } +>; +/** + * Removes all predictions across all files that share the given canonical_entity_id + * @param canonicalId The canonical entity id to match + */ +export function removePredictionsByCanonicalId( + canonicalId: string, +): RemovePredictionsByCanonicalId { + return { + type: ActionTypes.REMOVE_PREDICTIONS_BY_CANONICAL_ID, + payload: { canonicalId }, + }; +} + +export type RemovePredictionValueByCanonicalId = Action< + ActionTypes.REMOVE_PREDICTION_VALUE_BY_CANONICAL_ID, + { canonicalId: string; value: string } +>; +/** + * Removes predictions across all files matching the given canonical_entity_id and text value + * @param canonicalId The canonical entity id to match + * @param value The prediction text to remove + */ +export function removePredictionValueByCanonicalId( + canonicalId: string, + value: string, +): RemovePredictionValueByCanonicalId { + return { + type: ActionTypes.REMOVE_PREDICTION_VALUE_BY_CANONICAL_ID, + payload: { canonicalId, value }, + }; +} + +export type UpdatePredictionsByCanonicalId = Action< + ActionTypes.UPDATE_PREDICTIONS_BY_CANONICAL_ID, + { canonicalId: string; newLabel: AllLabels | AllLabelsWithSufix } +>; +/** + * Updates the label of all predictions across all files sharing the given canonical_entity_id + * @param canonicalId The canonical entity id to match + * @param newLabel The new label to set + */ +export function updatePredictionsByCanonicalId( + canonicalId: string, + newLabel: AllLabels | AllLabelsWithSufix, +): UpdatePredictionsByCanonicalId { + return { + type: ActionTypes.UPDATE_PREDICTIONS_BY_CANONICAL_ID, + payload: { canonicalId, newLabel }, + }; +} diff --git a/src/renderer/src/reducers/file/index.ts b/src/renderer/src/reducers/file/index.ts index ff50ec59..4ee73cfe 100644 --- a/src/renderer/src/reducers/file/index.ts +++ b/src/renderer/src/reducers/file/index.ts @@ -13,6 +13,9 @@ import { type RemovePrediction, type RemovePredictionsAction, type RemovePredictionsByText, + type RemovePredictionsByCanonicalId, + type RemovePredictionValueByCanonicalId, + type UpdatePredictionsByCanonicalId, type ReplaceFileAction, type ToggleSelectedAction, type UpdatePredictionLabel, @@ -49,7 +52,10 @@ export type Action = | RemovePrediction | RemovePredictionsByText | UpdatePredictionLabel - | UpdatePredictionsByText; + | UpdatePredictionsByText + | RemovePredictionsByCanonicalId + | RemovePredictionValueByCanonicalId + | UpdatePredictionsByCanonicalId; /** * Reducer function for `DocFile[]` state @@ -272,6 +278,48 @@ export default function reducer(state: State, action: Action): State { }); } + // ---------------------------------------- + // REMOVE PREDICTIONS BY CANONICAL ID + // ---------------------------------------- + case ActionTypes.REMOVE_PREDICTIONS_BY_CANONICAL_ID: { + const { canonicalId } = action.payload; + return state.map((file) => ({ + ...file, + predictions: file.predictions?.filter( + (p) => p.attrs.canonical_entity_id !== canonicalId, + ), + })); + } + + // ------------------------------------------------ + // REMOVE PREDICTION VALUE BY CANONICAL ID + // ------------------------------------------------ + case ActionTypes.REMOVE_PREDICTION_VALUE_BY_CANONICAL_ID: { + const { canonicalId, value } = action.payload; + return state.map((file) => ({ + ...file, + predictions: file.predictions?.filter( + (p) => + !(p.attrs.canonical_entity_id === canonicalId && p.text === value), + ), + })); + } + + // ---------------------------------------- + // UPDATE PREDICTIONS BY CANONICAL ID + // ---------------------------------------- + case ActionTypes.UPDATE_PREDICTIONS_BY_CANONICAL_ID: { + const { canonicalId, newLabel } = action.payload; + return state.map((file) => ({ + ...file, + predictions: file.predictions?.map((p) => + p.attrs.canonical_entity_id === canonicalId + ? { ...p, attrs: { ...p.attrs, aymurai_label: newLabel } } + : p, + ), + })); + } + // ---------------- // ADD PARAGRAPHS // ---------------- From 6f8a478c245236e4c7ae11b83bad30712bf07600 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:32:01 -0300 Subject: [PATCH 172/263] adjust typings --- src/renderer/src/types/aymurai.ts | 11 +++++++---- .../src/utils/predictions/suggestions/index.ts | 2 +- .../src/utils/predictions/suggestions/types.ts | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/renderer/src/types/aymurai.ts b/src/renderer/src/types/aymurai.ts index a716125b..b62ac1f0 100644 --- a/src/renderer/src/types/aymurai.ts +++ b/src/renderer/src/types/aymurai.ts @@ -1,4 +1,4 @@ -import type { SelectOption } from "@/components/select"; +import type { SelectOption } from "@/components/ui/select"; // ------------ // PREDICTION @@ -12,6 +12,7 @@ type LabelAttributes = { aymurai_alt_text: string | null; aymurai_alt_start_char: number | null; aymurai_alt_end_char: number | null; + canonical_entity_id?: string | null; }; export type PredictLabel = { @@ -88,10 +89,10 @@ export enum LabelAnonimizer { USUARIX = "USUARIX", } -export type AllLabels = LabelType | LabelDecisiones | LabelAnonimizer; +export type AllLabels = LabelType | LabelDecisiones | LabelAnonimizer | AnonymizerLabels; export type AllLabelsWithSufix = `${AllLabels}_${number}`; -export const anonymizerLabels: SelectOption[] = [ +export const anonymizerLabels = [ { id: "DNI", text: "DNI" }, { id: "PER", text: "Persona" }, { id: "TEL", text: "Número de teléfono" }, @@ -122,7 +123,9 @@ export const anonymizerLabels: SelectOption[] = [ { id: "NUM_MATRICULA", text: "Número matrícula" }, { id: "PATENTE_DOMINIO", text: "Patente dominio" }, { id: "TEXTO_ANONIMIZAR", text: "Texto anonimizar" }, -]; +] as const satisfies SelectOption[]; + +export type AnonymizerLabels = (typeof anonymizerLabels)[number]["id"]; // -------------------- // DOCUMENT EXTRACTION diff --git a/src/renderer/src/utils/predictions/suggestions/index.ts b/src/renderer/src/utils/predictions/suggestions/index.ts index e83d127f..30ac006f 100644 --- a/src/renderer/src/utils/predictions/suggestions/index.ts +++ b/src/renderer/src/utils/predictions/suggestions/index.ts @@ -1,4 +1,4 @@ -import type { SelectOption } from "@/components/select"; +import type { SelectOption } from "@/components/ui/select"; import { type AllLabels, type AllLabelsWithSufix, diff --git a/src/renderer/src/utils/predictions/suggestions/types.ts b/src/renderer/src/utils/predictions/suggestions/types.ts index ac0c1896..787a2532 100644 --- a/src/renderer/src/utils/predictions/suggestions/types.ts +++ b/src/renderer/src/utils/predictions/suggestions/types.ts @@ -1,4 +1,4 @@ -import type { Suggestion } from "@/components/select"; +import type { SelectSuggestion as Suggestion } from "@/components/ui/select"; import type { AllLabels, AllLabelsWithSufix, From 072d751e6f5528996e7501da8c60d73e52e403f3 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:32:30 -0300 Subject: [PATCH 173/263] remove axios' default api url --- src/renderer/src/services/api.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/renderer/src/services/api.ts b/src/renderer/src/services/api.ts index d01bc28f..ac07587a 100644 --- a/src/renderer/src/services/api.ts +++ b/src/renderer/src/services/api.ts @@ -1,9 +1,5 @@ import axios from "axios"; -import { AYMURAI_API_URL } from "@/utils/config"; - -const api = axios.create({ - baseURL: AYMURAI_API_URL, -}); +const api = axios.create(); export default api; From ea61e4e241e6d45b84bc25c1424efefb9f9f1487 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:47:29 -0300 Subject: [PATCH 174/263] add fixed height to validation dataset page --- .../src/routes/app.$feature/validation.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/renderer/src/routes/app.$feature/validation.tsx b/src/renderer/src/routes/app.$feature/validation.tsx index 4eb52eb2..b8b13223 100644 --- a/src/renderer/src/routes/app.$feature/validation.tsx +++ b/src/renderer/src/routes/app.$feature/validation.tsx @@ -4,7 +4,7 @@ import Footer from "@/components/layout/footer"; import Header from "@/components/layout/header"; import RequireFile from "@/features/RequireFile"; import { useFiles } from "@/hooks"; -import { Grid } from "@/styled/jsx"; +import { Grid, Stack } from "@/styled/jsx"; import { FeatureFlowEnum, featureNamespace } from "@/types/features"; import { createFileRoute, @@ -57,12 +57,14 @@ function RouteComponent() { ); return ( -
} - feature={feature} - /> - + +
} + feature={feature} + /> + + ); } From a36a7401938a1ed87437a4c8389d993e67ceed71 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:47:51 -0300 Subject: [PATCH 175/263] make suggestion clickable on uncontrolled text input --- src/renderer/src/components/uncontrolled-input/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/src/components/uncontrolled-input/index.tsx b/src/renderer/src/components/uncontrolled-input/index.tsx index 32667972..fdfaa0af 100644 --- a/src/renderer/src/components/uncontrolled-input/index.tsx +++ b/src/renderer/src/components/uncontrolled-input/index.tsx @@ -122,6 +122,7 @@ export default forwardRef<{ value: string }, Props>(function UncontrolledInput( onClick={handleClickSuggestion} onKeyDown={handleKeySuggestion} tabIndex={0} + clickable > {suggestion} From 70c44a044225adb14bba1a67f2f3f61a395e7939 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:48:50 -0300 Subject: [PATCH 176/263] more fixes in height to validate dataset --- .../src/components/validate-dataset/index.tsx | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/renderer/src/components/validate-dataset/index.tsx b/src/renderer/src/components/validate-dataset/index.tsx index e5068cf6..26629066 100644 --- a/src/renderer/src/components/validate-dataset/index.tsx +++ b/src/renderer/src/components/validate-dataset/index.tsx @@ -9,7 +9,6 @@ import { css } from "@/styled/css"; import { HStack, Stack } from "@/styled/jsx"; import { isFileValidated, isValidationCompleted } from "@/utils/file"; import { useNavigate, useParams } from "@tanstack/react-router"; -import MainContent from "../layout/main-content"; import FormGroup from "./form-group"; import { moveNext, movePrevious } from "./utils"; @@ -60,31 +59,37 @@ export function ValidateDataset() { }; return ( - <> + - - - - 3. Validación de datos - - - - + + + 3. Validación de datos + + +
- +
); } From d975e3fd20fbc2d10c5b6178ae738ff1e0f4b173 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:49:48 -0300 Subject: [PATCH 177/263] include label policies and annotations when anonymizing document --- .../src/components/file-annotator/index.tsx | 117 +++++++++++------- .../components/finish/finish-anonymizer.tsx | 16 ++- src/renderer/src/services/aymurai/queries.ts | 39 ++++-- 3 files changed, 115 insertions(+), 57 deletions(-) diff --git a/src/renderer/src/components/file-annotator/index.tsx b/src/renderer/src/components/file-annotator/index.tsx index 8d32aa07..6e713bc8 100644 --- a/src/renderer/src/components/file-annotator/index.tsx +++ b/src/renderer/src/components/file-annotator/index.tsx @@ -3,9 +3,16 @@ import { memo, useMemo, useState, useTransition } from "react"; import { SearchBar } from "./SearchBar"; import type { SelectOption } from "@/components/ui/select"; +import { EXCLUDED_TAGS } from "@/constants/excluded-tags"; import AnnotationProvider, { useAnnotation } from "@/context/Annotation"; +import { useExcludedTagsConfig } from "@/store/useLocal"; import { HStack } from "@/styled/jsx"; -import type { AllLabels, AllLabelsWithSufix, PredictLabel } from "@/types/aymurai"; +import type { + AllLabels, + AllLabelsWithSufix, + AnonymizerLabels, + PredictLabel, +} from "@/types/aymurai"; import type { DocFile, Paragraph as ParagraphType } from "@/types/file"; import LabelManager from "../anonymizer/label-manager"; import SearchAnnotation from "../file/search-annotation"; @@ -20,52 +27,54 @@ interface ParagraphProps { paragraph: ParagraphType; predictions: PredictLabel[]; } -const Paragraph = memo(({ children, search, paragraph, predictions }: ParagraphProps) => { - const { label, suffix } = useAnnotation(); - const searchTag = label - ? suffix - ? (`${label}_${suffix}` as AllLabelsWithSufix) - : label - : null; - - const annotations = useMemo(() => { - return createAnnotationsWithSearch( - predictions, - search, - paragraph, - searchTag, - ); - }, [predictions, search, paragraph, searchTag]); +const Paragraph = memo( + ({ children, search, paragraph, predictions }: ParagraphProps) => { + const { label, suffix } = useAnnotation(); + const searchTag = label + ? suffix + ? (`${label}_${suffix}` as AllLabelsWithSufix) + : label + : null; - const splits = generateSplits(children, annotations); + const annotations = useMemo(() => { + return createAnnotationsWithSearch( + predictions, + search, + paragraph, + searchTag, + ); + }, [predictions, search, paragraph, searchTag]); - return ( - - {splits.map((s) => { - const content = children.slice(s.start, s.end); - const key = `${s.start}-${s.end}`; - - switch (s.type) { - case "search": - return ( - - {content} - - ); - case "tag": - return ( - - {content} - - ); - case "text": - default: - return {content}; - } - })} - - ); -}); + const splits = generateSplits(children, annotations); + + return ( + + {splits.map((s) => { + const content = children.slice(s.start, s.end); + const key = `${s.start}-${s.end}`; + + switch (s.type) { + case "search": + return ( + + {content} + + ); + case "tag": + return ( + + {content} + + ); + case "text": + default: + return {content}; + } + })} + + ); + }, +); interface Props { file: DocFile; @@ -80,10 +89,24 @@ export default function FileAnnotator({ file, isAnnotable = false }: Props) { const [labelManagerOpen, setLabelManagerOpen] = useState(false); const paragraphs = file.paragraphs!; + const { tags, words } = useExcludedTagsConfig(); + const effectiveTags = tags ?? EXCLUDED_TAGS; + + const filteredPredictions = useMemo( + () => + (file.predictions ?? []).filter((label) => { + const tag = label.attrs.aymurai_label as AnonymizerLabels; + if (effectiveTags[tag] === false) return false; + if (words.some((w) => label.text.toLowerCase() === w.toLowerCase())) + return false; + return true; + }), + [file.predictions, effectiveTags, words], + ); const predictionsMap = useMemo( - () => predictionsToMap(file.predictions ?? []), - [file.predictions], + () => predictionsToMap(filteredPredictions), + [filteredPredictions], ); const selectChangeHandler = (option?: SelectOption) => { diff --git a/src/renderer/src/components/finish/finish-anonymizer.tsx b/src/renderer/src/components/finish/finish-anonymizer.tsx index c8d8ca8b..baa43949 100644 --- a/src/renderer/src/components/finish/finish-anonymizer.tsx +++ b/src/renderer/src/components/finish/finish-anonymizer.tsx @@ -1,5 +1,6 @@ import { useFiles } from "@/hooks"; import { aymuraiService } from "@/services/aymurai"; +import { useExcludedTagsConfig } from "@/store/useLocal"; import { HStack } from "@/styled/jsx"; import { FeatureFlowEnum } from "@/types/features"; import { useMutation, useQuery } from "@tanstack/react-query"; @@ -15,6 +16,7 @@ interface FinishAnonymizerProps { export default function FinishAnonymizer({ onRestart }: FinishAnonymizerProps) { const { t } = useTranslation("anonymizer"); const file = useFiles().at(0); + const { tags, words } = useExcludedTagsConfig(); if (!file) throw new Error("Reached /finish but there's no file to read"); @@ -22,7 +24,7 @@ export default function FinishAnonymizer({ onRestart }: FinishAnonymizerProps) { data: odtFile, isLoading, isError, - } = useQuery(aymuraiService.anonymize(file)); + } = useQuery(aymuraiService.anonymize(file, tags, words)); const { mutate: convertToPdf, isPending: isPdfPending } = useMutation( aymuraiService.odtToPdf(), @@ -63,10 +65,18 @@ export default function FinishAnonymizer({ onRestart }: FinishAnonymizerProps) { - - diff --git a/src/renderer/src/services/aymurai/queries.ts b/src/renderer/src/services/aymurai/queries.ts index fd4d426c..bb347fc1 100644 --- a/src/renderer/src/services/aymurai/queries.ts +++ b/src/renderer/src/services/aymurai/queries.ts @@ -1,17 +1,18 @@ import { disambiguateSchema } from "@/schema/disambiguate"; import { documentExtractSchema } from "@/schema/extract"; -import type { PredictLabel, Workflows } from "@/types/aymurai"; +import type { AnonymizerLabels, PredictLabel, Workflows } from "@/types/aymurai"; import type { DocFile, Paragraph } from "@/types/file"; +import { EXCLUDED_TAGS } from "@/constants/excluded-tags"; import { mutationOptions, queryOptions } from "@tanstack/react-query"; import api from "../api"; import predict from "./predict"; interface Body { data: { - // The paragraph document: string; labels: PredictLabel[]; }[]; + label_policies?: Record; } /** @@ -34,26 +35,50 @@ export const predictParagraph = ( retry: false, }); -const body = (file: DocFile): Body => { +const body = ( + file: DocFile, + excludedTags: Record | null, + excludedWords: string[], +): Body => { + const effectiveTags = excludedTags ?? EXCLUDED_TAGS; const paragraphs = file.paragraphs ?? []; const labels = file.predictions ?? []; + const label_policies = Object.fromEntries( + Object.entries(effectiveTags) + .filter(([, enabled]) => !enabled) + .map(([id]) => [id, { anonymize: false }]), + ) as Record; + return { data: paragraphs.map((p) => ({ document: p.value, - labels: labels.filter((l) => l.paragraphId === p.id), + labels: labels + .filter((l) => l.paragraphId === p.id) + .map((l) => { + const isExcluded = excludedWords.some( + (w) => l.text.toLowerCase() === w.toLowerCase(), + ); + return isExcluded + ? { ...l, attrs: { ...l.attrs, aymurai_anonymize: false } } + : l; + }), })), + ...(Object.keys(label_policies).length > 0 && { label_policies }), }; }; -export const anonymize = (file: DocFile) => +export const anonymize = ( + file: DocFile, + excludedTags: Record | null, + excludedWords: string[], +) => queryOptions({ queryKey: ["anonymize", file.data.name], queryFn: async () => { const formData = new FormData(); formData.append("file", file.data); - // TODO: add annotations whenever the backend implements it - formData.append("annotations", JSON.stringify(body(file))); + formData.append("annotations", JSON.stringify(body(file, excludedTags, excludedWords))); const response = await api.post( "/anonymizer/anonymize-document", From a0f6c6873475bd07fec904a9471522a56539c26b Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:53:38 -0300 Subject: [PATCH 178/263] fix ts clone element issue --- src/renderer/src/components/validation-form/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/src/components/validation-form/index.tsx b/src/renderer/src/components/validation-form/index.tsx index 3861c351..3d15eecf 100644 --- a/src/renderer/src/components/validation-form/index.tsx +++ b/src/renderer/src/components/validation-form/index.tsx @@ -42,7 +42,7 @@ export default function ValidationForm({ // Add the onChange handler to every children const childrenWithHandler = Children.map(children, (child) => { if (isValidElement(child)) { - return cloneElement(child as ReactElement, { onChange }); + return cloneElement(child as ReactElement<{ onChange: () => void }>, { onChange }); } return child; }); From 8dc38fbbf4c7fa071fab7354e1e113e83587ec87 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:53:52 -0300 Subject: [PATCH 179/263] add knip --- knip.json | 6 + package.json | 4 +- pnpm-lock.yaml | 617 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 604 insertions(+), 23 deletions(-) create mode 100644 knip.json diff --git a/knip.json b/knip.json new file mode 100644 index 00000000..4651583e --- /dev/null +++ b/knip.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://unpkg.com/knip@6/schema.json", + "tags": [ + "-lintignore" + ] +} diff --git a/package.json b/package.json index df8d99c2..d03639c2 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "build:unpack": "npm run build && electron-builder --dir", "build:win": "npm run build && electron-builder --win", "build:mac": "cross-env VITE_APP_MODE=electron electron-vite build && electron-builder --mac", - "build:linux": "cross-env VITE_APP_MODE=electron electron-vite build && electron-builder --linux" + "build:linux": "cross-env VITE_APP_MODE=electron electron-vite build && electron-builder --linux", + "knip": "knip" }, "dependencies": { "@electron-toolkit/preload": "^3.0.2", @@ -70,6 +71,7 @@ "exceljs": "^4.4.0", "husky": "^8.0.0", "i18next": "^25.8.13", + "knip": "^6.7.0", "lint-staged": "^13.0.3", "markdownlint-cli": "^0.32.2", "nodemon": "^2.0.20", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a23cf505..41ca6568 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,10 +71,10 @@ importers: version: 1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-router-devtools': specifier: ^1.139.12 - version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(lightningcss@1.30.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(tsx@4.20.6) + version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(tsx@4.20.6)(yaml@2.8.3) '@tanstack/router-plugin': specifier: ^1.139.12 - version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6)) + version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3)) '@types/node': specifier: '20' version: 20.19.1 @@ -89,7 +89,7 @@ importers: version: 3.4.1 '@vitejs/plugin-react': specifier: ^4.5.0 - version: 4.5.0(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6)) + version: 4.5.0(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3)) axios: specifier: ^1.12.0 version: 1.13.4 @@ -113,7 +113,7 @@ importers: version: 3.2.1 electron-vite: specifier: ^3.1.0 - version: 3.1.0(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6)) + version: 3.1.0(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3)) exceljs: specifier: ^4.4.0 version: 4.4.0 @@ -123,6 +123,9 @@ importers: i18next: specifier: ^25.8.13 version: 25.8.13(typescript@5.9.2) + knip: + specifier: ^6.7.0 + version: 6.7.0(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) lint-staged: specifier: ^13.0.3 version: 13.3.0 @@ -158,7 +161,7 @@ importers: version: 5.9.2 vite: specifier: ^6.3.5 - version: 6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6) + version: 6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3) wait-on: specifier: ^6.0.1 version: 6.0.1 @@ -588,6 +591,15 @@ packages: engines: {node: '>=14.14'} hasBin: true + '@emnapi/core@1.9.2': + resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} + + '@emnapi/runtime@1.9.2': + resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@esbuild/aix-ppc64@0.25.5': resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} engines: {node: '>=18'} @@ -830,6 +842,12 @@ packages: '@cfworker/json-schema': optional: true + '@napi-rs/wasm-runtime@1.1.4': + resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -851,6 +869,228 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} deprecated: This functionality has been moved to @npmcli/fs + '@oxc-parser/binding-android-arm-eabi@0.127.0': + resolution: {integrity: sha512-0LC7ye4hvqbIKxAzThzvswgHLFu2AURKzYLeSVvLdu2TBOYWQDmHnTqPLeA597BcUCxiLqLsS4CJ5uoI5WYWCQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxc-parser/binding-android-arm64@0.127.0': + resolution: {integrity: sha512-b5jtVTH6AU5CJXHNdj7Jj9IEiR9yVjjnwHzPJhGyHGPdcsZSzBCkS9GBbV33niRMvKthDwQRFRJfI4a+k4PvYg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxc-parser/binding-darwin-arm64@0.127.0': + resolution: {integrity: sha512-obCE8B7ISKkJidjlhv9xRGJPOSDG2Yu6PRga9Ruaz35uintHxbp1Ki/Yc71wx4rj3Edrm0a1kzG1TAwit0wFpg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxc-parser/binding-darwin-x64@0.127.0': + resolution: {integrity: sha512-JL6Xb5IwPQT8rUzlpsX7E+AgfcdNklXNPFp8pjCQQ5MQOQo5rtEB2ui+3Hgg9Sn7Y9Egj6YOLLiHhLpdAe12Aw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxc-parser/binding-freebsd-x64@0.127.0': + resolution: {integrity: sha512-SDQ/3MQFw58fqQz3Z1PhSKFF3JoCF4gmlNjziDm8X02tTahCw0qJbd7FGPDKw1i4VTBZene9JPyC3mHtSvi+wA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxc-parser/binding-linux-arm-gnueabihf@0.127.0': + resolution: {integrity: sha512-Av+D1MIqzV0YMGPT9we2SIZaMKD7Cxs4CvXSx/yxaWHewZjYEjScpOf5igc8IILASViw4WTnjlwUdI1KzVtDHQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm-musleabihf@0.127.0': + resolution: {integrity: sha512-Cs2fdJ8cPpFdeebj6p4dag8A4+56hPvZ0AhQQzlaLswGz1tz7bXt1nETLeorrM9+AMcWFFkqxcXwDGfTVidY8g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm64-gnu@0.127.0': + resolution: {integrity: sha512-qdOfTcT6SY8gsJrrV92uyEUyjqMGPpIB5JZUG6QN5dukYd+7/j0kX6MwK1DgQj39jtUYixxPiaRUiEN1+0CXgQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@oxc-parser/binding-linux-arm64-musl@0.127.0': + resolution: {integrity: sha512-EoTCZneNFU/P2qrpEM+RHmQwt+CvDkyGESG6qhr7KaegXLZwePfbrkCDfAk8/rhxbDUVGsZILX+2tqPzFtoFWA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@oxc-parser/binding-linux-ppc64-gnu@0.127.0': + resolution: {integrity: sha512-zALjmZYgxFLHjXeudcDF0xFGNydTAtkAeXAr2EuC17ywCyFxcmQra4w0BMde0Yi/re4Bi4iwEoEXtYN7l6eBLQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@oxc-parser/binding-linux-riscv64-gnu@0.127.0': + resolution: {integrity: sha512-fPP8M6zQLS7Jz7o9d5ArUSuAuSK3e+WCYVrCpdzeCOejidtZExJ9tjhDrAd3HEPqARBCPmdpqxESPFqy44vkBQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + + '@oxc-parser/binding-linux-riscv64-musl@0.127.0': + resolution: {integrity: sha512-7IcC4Ao02oGpfnjt+X/oF4U2mllo2qoSkw5xxiXNKL9MCTsTiAC6616beOuehdxGcnz1bRoPC1RQ2f1GQDdN+g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + + '@oxc-parser/binding-linux-s390x-gnu@0.127.0': + resolution: {integrity: sha512-pbXIhiNFHoqWeqDNLiJ9JkpHz1IM9k4DXa66x+1GTWMG7iLxtkXgE53iiuKSXwmk3zIYmaPVfBvgcAhS583K4Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@oxc-parser/binding-linux-x64-gnu@0.127.0': + resolution: {integrity: sha512-MYCguB9RvBvlSd6gbuNI7QwiLoCCAlGnlRJFPrzLI6U1/9wkC/WK6LtBAUln55H1Ctqw45PWmqrobKoMhsYQzQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@oxc-parser/binding-linux-x64-musl@0.127.0': + resolution: {integrity: sha512-5eY0B/bxf1xIUxb4NOTvOI3KWtBQfPWYyKAzgcrCt0mDibSZygVpO1Pz8bkeiSZ5Jj9+M09dkggG3H8I5d0Uyg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@oxc-parser/binding-openharmony-arm64@0.127.0': + resolution: {integrity: sha512-Gld0ajrFTUXNtdw20fVBuTQx66FA75nIVg+//pPfR3sXkuABB4mTBhl3r9JNzrJpgW//qiwxf0nWXUWGJSL3UQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxc-parser/binding-wasm32-wasi@0.127.0': + resolution: {integrity: sha512-T6KVD7rhLzFlwGRXMnxUFfkCZD8FHnb968wVXW1mXzgRFc5RNXOBY2mPPDZ77x5Ln76ltLMgtPg0cOkU1NSrEQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@oxc-parser/binding-win32-arm64-msvc@0.127.0': + resolution: {integrity: sha512-Ujvw4X+LD1CCGULcsQcvb4YNVoBGqt+JHgNNzGGaCImELiZLk477ifUH53gIbE7EKd933NdTi25JWEr9K2HwXw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxc-parser/binding-win32-ia32-msvc@0.127.0': + resolution: {integrity: sha512-0cwxKO7KHQQQfo4Uf4B2SQrhgm+cJaP9OvFFhx52Tkg4bezsacu83GB2/In5bC415Ueeym+kXdnge/57rbSfTw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxc-parser/binding-win32-x64-msvc@0.127.0': + resolution: {integrity: sha512-rOrnSQSCbhI2kowr9XxE7m9a8oQXnBHjnS6j95LxxAnEZ0+Fz20WlRXG4ondQb+ejjt2KOsa65sE6++L6kUd+w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@oxc-project/types@0.127.0': + resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==} + + '@oxc-resolver/binding-android-arm-eabi@11.19.1': + resolution: {integrity: sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg==} + cpu: [arm] + os: [android] + + '@oxc-resolver/binding-android-arm64@11.19.1': + resolution: {integrity: sha512-oolbkRX+m7Pq2LNjr/kKgYeC7bRDMVTWPgxBGMjSpZi/+UskVo4jsMU3MLheZV55jL6c3rNelPl4oD60ggYmqA==} + cpu: [arm64] + os: [android] + + '@oxc-resolver/binding-darwin-arm64@11.19.1': + resolution: {integrity: sha512-nUC6d2i3R5B12sUW4O646qD5cnMXf2oBGPLIIeaRfU9doJRORAbE2SGv4eW6rMqhD+G7nf2Y8TTJTLiiO3Q/dQ==} + cpu: [arm64] + os: [darwin] + + '@oxc-resolver/binding-darwin-x64@11.19.1': + resolution: {integrity: sha512-cV50vE5+uAgNcFa3QY1JOeKDSkM/9ReIcc/9wn4TavhW/itkDGrXhw9jaKnkQnGbjJ198Yh5nbX/Gr2mr4Z5jQ==} + cpu: [x64] + os: [darwin] + + '@oxc-resolver/binding-freebsd-x64@11.19.1': + resolution: {integrity: sha512-xZOQiYGFxtk48PBKff+Zwoym7ScPAIVp4c14lfLxizO2LTTTJe5sx9vQNGrBymrf/vatSPNMD4FgsaaRigPkqw==} + cpu: [x64] + os: [freebsd] + + '@oxc-resolver/binding-linux-arm-gnueabihf@11.19.1': + resolution: {integrity: sha512-lXZYWAC6kaGe/ky2su94e9jN9t6M0/6c+GrSlCqL//XO1cxi5lpAhnJYdyrKfm0ZEr/c7RNyAx3P7FSBcBd5+A==} + cpu: [arm] + os: [linux] + + '@oxc-resolver/binding-linux-arm-musleabihf@11.19.1': + resolution: {integrity: sha512-veG1kKsuK5+t2IsO9q0DErYVSw2azvCVvWHnfTOS73WE0STdLLB7Q1bB9WR+yHPQM76ASkFyRbogWo1GR1+WbQ==} + cpu: [arm] + os: [linux] + + '@oxc-resolver/binding-linux-arm64-gnu@11.19.1': + resolution: {integrity: sha512-heV2+jmXyYnUrpUXSPugqWDRpnsQcDm2AX4wzTuvgdlZfoNYO0O3W2AVpJYaDn9AG4JdM6Kxom8+foE7/BcSig==} + cpu: [arm64] + os: [linux] + + '@oxc-resolver/binding-linux-arm64-musl@11.19.1': + resolution: {integrity: sha512-jvo2Pjs1c9KPxMuMPIeQsgu0mOJF9rEb3y3TdpsrqwxRM+AN6/nDDwv45n5ZrUnQMsdBy5gIabioMKnQfWo9ew==} + cpu: [arm64] + os: [linux] + + '@oxc-resolver/binding-linux-ppc64-gnu@11.19.1': + resolution: {integrity: sha512-vLmdNxWCdN7Uo5suays6A/+ywBby2PWBBPXctWPg5V0+eVuzsJxgAn6MMB4mPlshskYbppjpN2Zg83ArHze9gQ==} + cpu: [ppc64] + os: [linux] + + '@oxc-resolver/binding-linux-riscv64-gnu@11.19.1': + resolution: {integrity: sha512-/b+WgR+VTSBxzgOhDO7TlMXC1ufPIMR6Vj1zN+/x+MnyXGW7prTLzU9eW85Aj7Th7CCEG9ArCbTeqxCzFWdg2w==} + cpu: [riscv64] + os: [linux] + + '@oxc-resolver/binding-linux-riscv64-musl@11.19.1': + resolution: {integrity: sha512-YlRdeWb9j42p29ROh+h4eg/OQ3dTJlpHSa+84pUM9+p6i3djtPz1q55yLJhgW9XfDch7FN1pQ/Vd6YP+xfRIuw==} + cpu: [riscv64] + os: [linux] + + '@oxc-resolver/binding-linux-s390x-gnu@11.19.1': + resolution: {integrity: sha512-EDpafVOQWF8/MJynsjOGFThcqhRHy417sRyLfQmeiamJ8qVhSKAn2Dn2VVKUGCjVB9C46VGjhNo7nOPUi1x6uA==} + cpu: [s390x] + os: [linux] + + '@oxc-resolver/binding-linux-x64-gnu@11.19.1': + resolution: {integrity: sha512-NxjZe+rqWhr+RT8/Ik+5ptA3oz7tUw361Wa5RWQXKnfqwSSHdHyrw6IdcTfYuml9dM856AlKWZIUXDmA9kkiBQ==} + cpu: [x64] + os: [linux] + + '@oxc-resolver/binding-linux-x64-musl@11.19.1': + resolution: {integrity: sha512-cM/hQwsO3ReJg5kR+SpI69DMfvNCp+A/eVR4b4YClE5bVZwz8rh2Nh05InhwI5HR/9cArbEkzMjcKgTHS6UaNw==} + cpu: [x64] + os: [linux] + + '@oxc-resolver/binding-openharmony-arm64@11.19.1': + resolution: {integrity: sha512-QF080IowFB0+9Rh6RcD19bdgh49BpQHUW5TajG1qvWHvmrQznTZZjYlgE2ltLXyKY+qs4F/v5xuX1XS7Is+3qA==} + cpu: [arm64] + os: [openharmony] + + '@oxc-resolver/binding-wasm32-wasi@11.19.1': + resolution: {integrity: sha512-w8UCKhX826cP/ZLokXDS6+milN8y4X7zidsAttEdWlVoamTNf6lhBJldaWr3ukTDiye7s4HRcuPEPOXNC432Vg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@oxc-resolver/binding-win32-arm64-msvc@11.19.1': + resolution: {integrity: sha512-nJ4AsUVZrVKwnU/QRdzPCCrO0TrabBqgJ8pJhXITdZGYOV28TIYystV1VFLbQ7DtAcaBHpocT5/ZJnF78YJPtQ==} + cpu: [arm64] + os: [win32] + + '@oxc-resolver/binding-win32-ia32-msvc@11.19.1': + resolution: {integrity: sha512-EW+ND5q2Tl+a3pH81l1QbfgbF3HmqgwLfDfVithRFheac8OTcnbXt/JxqD2GbDkb7xYEqy1zNaVFRr3oeG8npA==} + cpu: [ia32] + os: [win32] + + '@oxc-resolver/binding-win32-x64-msvc@11.19.1': + resolution: {integrity: sha512-6hIU3RQu45B+VNTY4Ru8ppFwjVS/S5qwYyGhBotmjxfEKk41I2DlGtRfGJndZ5+6lneE2pwloqunlOyZuX/XAw==} + cpu: [x64] + os: [win32] + '@pandacss/config@1.8.1': resolution: {integrity: sha512-SvFvfDav//c2lbk9+IPRGCLGhUd1G8z/Nxs0CwZNLXpI0xTNy0ISGMV1ZKkqBFbmH95e+/5oZXnnM4rAS1LO0g==} @@ -1578,6 +1818,9 @@ packages: '@ts-morph/common@0.28.1': resolution: {integrity: sha512-W74iWf7ILp1ZKNYXY5qbddNaml7e9Sedv5lvU1V8lftlitkc9Pq1A+jlH23ltDgWYeZFFEqGCD1Ies9hqu3O+g==} + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -2547,6 +2790,9 @@ packages: fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fd-package-json@2.0.0: + resolution: {integrity: sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==} + fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} @@ -2623,6 +2869,11 @@ packages: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} + formatly@0.3.0: + resolution: {integrity: sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w==} + engines: {node: '>=18.3.0'} + hasBin: true + forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -2736,6 +2987,9 @@ packages: get-tsconfig@4.13.0: resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -3051,6 +3305,10 @@ packages: javascript-stringify@2.1.0: resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==} + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + joi@17.13.3: resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} @@ -3118,6 +3376,11 @@ packages: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} + knip@6.7.0: + resolution: {integrity: sha512-ckL51NDH1YJxnv1kNB0iUdDngB4f/e9Igz8uIqYfmNDoyOFmmk1V0WFv3LQ7/hzC63b2Z9X41gGUE9eOWrZpaA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + lazy-val@1.0.5: resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==} @@ -3633,6 +3896,13 @@ packages: outdent@0.8.0: resolution: {integrity: sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==} + oxc-parser@0.127.0: + resolution: {integrity: sha512-bkgD4qHlN7WxLdX8bLXdaU54TtQtAIg/ZBAfm0aje/mo3MRDo3P0hZSgr4U7O3xfX+fQmR5AP04JS/TGcZLcFA==} + engines: {node: ^20.19.0 || >=22.12.0} + + oxc-resolver@11.19.1: + resolution: {integrity: sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg==} + p-cancelable@2.1.1: resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} engines: {node: '>=8'} @@ -3789,6 +4059,10 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + pidtree@0.6.0: resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} engines: {node: '>=0.10'} @@ -4304,6 +4578,10 @@ packages: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + smol-toml@1.6.1: + resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==} + engines: {node: '>= 18'} + socks-proxy-agent@7.0.0: resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} engines: {node: '>= 10'} @@ -4402,6 +4680,10 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + strip-json-comments@5.0.3: + resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} + engines: {node: '>=14.16'} + strip-outer@1.0.1: resolution: {integrity: sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==} engines: {node: '>=0.10.0'} @@ -4472,6 +4754,10 @@ packages: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + tmp-promise@3.0.3: resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} @@ -4571,6 +4857,10 @@ packages: uc.micro@1.0.6: resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} + unbash@3.0.0: + resolution: {integrity: sha512-FeFPZ/WFT0mbRCuydiZzpPFlrYN8ZUpphQKoq4EeElVIYjYyGzPMxQR/simUwCOJIyVhpFk4RbtyO7RuMpMnHA==} + engines: {node: '>=14'} + undefsafe@2.0.5: resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} @@ -4766,6 +5056,10 @@ packages: engines: {node: '>=10.0.0'} hasBin: true + walk-up-path@4.0.0: + resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} + engines: {node: 20 || >=22} + wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} @@ -4834,6 +5128,11 @@ packages: resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==} engines: {node: '>= 14'} + yaml@2.8.3: + resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} @@ -4881,6 +5180,9 @@ packages: zod@4.0.14: resolution: {integrity: sha512-nGFJTnJN6cM2v9kXL+SOBq3AtjQby3Mv5ySGFof5UGRHrRioSJ5iG680cYNjE/yWk671nROcpPj4hAS8nyLhSw==} + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zustand@5.0.7: resolution: {integrity: sha512-Ot6uqHDW/O2VdYsKLLU8GQu8sCOM1LcoE8RwvLv9uuRT9s6SOHCKs0ZEOhxg+I1Ld+A1Q5lwx+UlKXXUoCZITg==} engines: {node: '>=12.20.0'} @@ -5630,6 +5932,22 @@ snapshots: - supports-color optional: true + '@emnapi/core@1.9.2': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.9.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild/aix-ppc64@0.25.5': optional: true @@ -5835,6 +6153,13 @@ snapshots: - hono - supports-color + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + dependencies: + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@tybys/wasm-util': 0.10.1 + optional: true + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -5857,6 +6182,137 @@ snapshots: mkdirp: 1.0.4 rimraf: 3.0.2 + '@oxc-parser/binding-android-arm-eabi@0.127.0': + optional: true + + '@oxc-parser/binding-android-arm64@0.127.0': + optional: true + + '@oxc-parser/binding-darwin-arm64@0.127.0': + optional: true + + '@oxc-parser/binding-darwin-x64@0.127.0': + optional: true + + '@oxc-parser/binding-freebsd-x64@0.127.0': + optional: true + + '@oxc-parser/binding-linux-arm-gnueabihf@0.127.0': + optional: true + + '@oxc-parser/binding-linux-arm-musleabihf@0.127.0': + optional: true + + '@oxc-parser/binding-linux-arm64-gnu@0.127.0': + optional: true + + '@oxc-parser/binding-linux-arm64-musl@0.127.0': + optional: true + + '@oxc-parser/binding-linux-ppc64-gnu@0.127.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-gnu@0.127.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-musl@0.127.0': + optional: true + + '@oxc-parser/binding-linux-s390x-gnu@0.127.0': + optional: true + + '@oxc-parser/binding-linux-x64-gnu@0.127.0': + optional: true + + '@oxc-parser/binding-linux-x64-musl@0.127.0': + optional: true + + '@oxc-parser/binding-openharmony-arm64@0.127.0': + optional: true + + '@oxc-parser/binding-wasm32-wasi@0.127.0': + dependencies: + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + optional: true + + '@oxc-parser/binding-win32-arm64-msvc@0.127.0': + optional: true + + '@oxc-parser/binding-win32-ia32-msvc@0.127.0': + optional: true + + '@oxc-parser/binding-win32-x64-msvc@0.127.0': + optional: true + + '@oxc-project/types@0.127.0': {} + + '@oxc-resolver/binding-android-arm-eabi@11.19.1': + optional: true + + '@oxc-resolver/binding-android-arm64@11.19.1': + optional: true + + '@oxc-resolver/binding-darwin-arm64@11.19.1': + optional: true + + '@oxc-resolver/binding-darwin-x64@11.19.1': + optional: true + + '@oxc-resolver/binding-freebsd-x64@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-arm-gnueabihf@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-arm-musleabihf@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-arm64-gnu@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-arm64-musl@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-ppc64-gnu@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-riscv64-gnu@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-riscv64-musl@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-s390x-gnu@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-x64-gnu@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-x64-musl@11.19.1': + optional: true + + '@oxc-resolver/binding-openharmony-arm64@11.19.1': + optional: true + + '@oxc-resolver/binding-wasm32-wasi@11.19.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + dependencies: + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + optional: true + + '@oxc-resolver/binding-win32-arm64-msvc@11.19.1': + optional: true + + '@oxc-resolver/binding-win32-ia32-msvc@11.19.1': + optional: true + + '@oxc-resolver/binding-win32-x64-msvc@11.19.1': + optional: true + '@pandacss/config@1.8.1': dependencies: '@pandacss/logger': 1.8.1 @@ -6528,13 +6984,13 @@ snapshots: '@tanstack/query-core': 5.100.5 react: 19.2.4 - '@tanstack/react-router-devtools@1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(lightningcss@1.30.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(tsx@4.20.6)': + '@tanstack/react-router-devtools@1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(tsx@4.20.6)(yaml@2.8.3)': dependencies: '@tanstack/react-router': 1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/router-devtools-core': 1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(lightningcss@1.30.2)(solid-js@1.9.10)(tsx@4.20.6) + '@tanstack/router-devtools-core': 1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(solid-js@1.9.10)(tsx@4.20.6)(yaml@2.8.3) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - vite: 7.2.4(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6) + vite: 7.2.4(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3) optionalDependencies: '@tanstack/router-core': 1.139.12 transitivePeerDependencies: @@ -6587,14 +7043,14 @@ snapshots: tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - '@tanstack/router-devtools-core@1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(lightningcss@1.30.2)(solid-js@1.9.10)(tsx@4.20.6)': + '@tanstack/router-devtools-core@1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(solid-js@1.9.10)(tsx@4.20.6)(yaml@2.8.3)': dependencies: '@tanstack/router-core': 1.139.12 clsx: 2.1.1 goober: 2.1.18(csstype@3.2.3) solid-js: 1.9.10 tiny-invariant: 1.3.3 - vite: 7.2.4(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6) + vite: 7.2.4(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3) optionalDependencies: csstype: 3.2.3 transitivePeerDependencies: @@ -6623,7 +7079,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6))': + '@tanstack/router-plugin@1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) @@ -6641,7 +7097,7 @@ snapshots: zod: 3.25.76 optionalDependencies: '@tanstack/react-router': 1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - vite: 6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6) + vite: 6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3) transitivePeerDependencies: - supports-color @@ -6672,6 +7128,11 @@ snapshots: path-browserify: 1.0.1 tinyglobby: 0.2.15 + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.27.4 @@ -6758,7 +7219,7 @@ snapshots: '@types/node': 16.18.126 optional: true - '@vitejs/plugin-react@4.5.0(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6))': + '@vitejs/plugin-react@4.5.0(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3))': dependencies: '@babel/core': 7.27.4 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.27.4) @@ -6766,7 +7227,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.9 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6) + vite: 6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3) transitivePeerDependencies: - supports-color @@ -6815,7 +7276,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -7672,7 +8133,7 @@ snapshots: electron-to-chromium@1.5.283: {} - electron-vite@3.1.0(vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6)): + electron-vite@3.1.0(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3)): dependencies: '@babel/core': 7.27.4 '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.27.4) @@ -7680,7 +8141,7 @@ snapshots: esbuild: 0.25.5 magic-string: 0.30.17 picocolors: 1.1.1 - vite: 6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6) + vite: 6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3) transitivePeerDependencies: - supports-color @@ -7915,6 +8376,10 @@ snapshots: dependencies: reusify: 1.1.0 + fd-package-json@2.0.0: + dependencies: + walk-up-path: 4.0.0 + fd-slicer@1.1.0: dependencies: pend: 1.2.0 @@ -7927,6 +8392,10 @@ snapshots: optionalDependencies: picomatch: 4.0.3 + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + filelist@1.0.4: dependencies: minimatch: 5.1.6 @@ -7997,6 +8466,10 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 + formatly@0.3.0: + dependencies: + fd-package-json: 2.0.0 + forwarded@0.2.0: {} fresh@2.0.0: {} @@ -8128,6 +8601,10 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + get-tsconfig@4.14.0: + dependencies: + resolve-pkg-maps: 1.0.0 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -8275,7 +8752,7 @@ snapshots: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -8294,7 +8771,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -8435,6 +8912,8 @@ snapshots: javascript-stringify@2.1.0: {} + jiti@2.6.1: {} + joi@17.13.3: dependencies: '@hapi/hoek': 9.3.0 @@ -8497,6 +8976,26 @@ snapshots: kleur@4.1.5: {} + knip@6.7.0(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2): + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + formatly: 0.3.0 + get-tsconfig: 4.14.0 + jiti: 2.6.1 + minimist: 1.2.8 + oxc-parser: 0.127.0 + oxc-resolver: 11.19.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + picomatch: 4.0.4 + smol-toml: 1.6.1 + strip-json-comments: 5.0.3 + tinyglobby: 0.2.16 + unbash: 3.0.0 + yaml: 2.8.3 + zod: 4.3.6 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + lazy-val@1.0.5: {} lazystream@1.0.1: @@ -8989,6 +9488,57 @@ snapshots: outdent@0.8.0: {} + oxc-parser@0.127.0: + dependencies: + '@oxc-project/types': 0.127.0 + optionalDependencies: + '@oxc-parser/binding-android-arm-eabi': 0.127.0 + '@oxc-parser/binding-android-arm64': 0.127.0 + '@oxc-parser/binding-darwin-arm64': 0.127.0 + '@oxc-parser/binding-darwin-x64': 0.127.0 + '@oxc-parser/binding-freebsd-x64': 0.127.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.127.0 + '@oxc-parser/binding-linux-arm-musleabihf': 0.127.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.127.0 + '@oxc-parser/binding-linux-arm64-musl': 0.127.0 + '@oxc-parser/binding-linux-ppc64-gnu': 0.127.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.127.0 + '@oxc-parser/binding-linux-riscv64-musl': 0.127.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.127.0 + '@oxc-parser/binding-linux-x64-gnu': 0.127.0 + '@oxc-parser/binding-linux-x64-musl': 0.127.0 + '@oxc-parser/binding-openharmony-arm64': 0.127.0 + '@oxc-parser/binding-wasm32-wasi': 0.127.0 + '@oxc-parser/binding-win32-arm64-msvc': 0.127.0 + '@oxc-parser/binding-win32-ia32-msvc': 0.127.0 + '@oxc-parser/binding-win32-x64-msvc': 0.127.0 + + oxc-resolver@11.19.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2): + optionalDependencies: + '@oxc-resolver/binding-android-arm-eabi': 11.19.1 + '@oxc-resolver/binding-android-arm64': 11.19.1 + '@oxc-resolver/binding-darwin-arm64': 11.19.1 + '@oxc-resolver/binding-darwin-x64': 11.19.1 + '@oxc-resolver/binding-freebsd-x64': 11.19.1 + '@oxc-resolver/binding-linux-arm-gnueabihf': 11.19.1 + '@oxc-resolver/binding-linux-arm-musleabihf': 11.19.1 + '@oxc-resolver/binding-linux-arm64-gnu': 11.19.1 + '@oxc-resolver/binding-linux-arm64-musl': 11.19.1 + '@oxc-resolver/binding-linux-ppc64-gnu': 11.19.1 + '@oxc-resolver/binding-linux-riscv64-gnu': 11.19.1 + '@oxc-resolver/binding-linux-riscv64-musl': 11.19.1 + '@oxc-resolver/binding-linux-s390x-gnu': 11.19.1 + '@oxc-resolver/binding-linux-x64-gnu': 11.19.1 + '@oxc-resolver/binding-linux-x64-musl': 11.19.1 + '@oxc-resolver/binding-openharmony-arm64': 11.19.1 + '@oxc-resolver/binding-wasm32-wasi': 11.19.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + '@oxc-resolver/binding-win32-arm64-msvc': 11.19.1 + '@oxc-resolver/binding-win32-ia32-msvc': 11.19.1 + '@oxc-resolver/binding-win32-x64-msvc': 11.19.1 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + p-cancelable@2.1.1: {} p-defer@1.0.0: {} @@ -9098,6 +9648,8 @@ snapshots: picomatch@4.0.3: {} + picomatch@4.0.4: {} + pidtree@0.6.0: {} pify@2.3.0: {} @@ -9643,10 +10195,12 @@ snapshots: smart-buffer@4.2.0: {} + smol-toml@1.6.1: {} + socks-proxy-agent@7.0.0: dependencies: agent-base: 6.0.2 - debug: 4.4.1 + debug: 4.4.3 socks: 2.8.7 transitivePeerDependencies: - supports-color @@ -9738,6 +10292,8 @@ snapshots: strip-json-comments@3.1.1: {} + strip-json-comments@5.0.3: {} + strip-outer@1.0.1: dependencies: escape-string-regexp: 1.0.5 @@ -9822,6 +10378,11 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + tmp-promise@3.0.3: dependencies: tmp: 0.2.3 @@ -9896,6 +10457,8 @@ snapshots: uc.micro@1.0.6: {} + unbash@3.0.0: {} + undefsafe@2.0.5: {} undici-types@6.21.0: {} @@ -10004,7 +10567,7 @@ snapshots: extsprintf: 1.4.1 optional: true - vite@6.3.5(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6): + vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3): dependencies: esbuild: 0.25.5 fdir: 6.4.5(picomatch@4.0.2) @@ -10015,10 +10578,12 @@ snapshots: optionalDependencies: '@types/node': 20.19.1 fsevents: 2.3.3 + jiti: 2.6.1 lightningcss: 1.30.2 tsx: 4.20.6 + yaml: 2.8.3 - vite@7.2.4(@types/node@20.19.1)(lightningcss@1.30.2)(tsx@4.20.6): + vite@7.2.4(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3): dependencies: esbuild: 0.25.5 fdir: 6.5.0(picomatch@4.0.3) @@ -10029,8 +10594,10 @@ snapshots: optionalDependencies: '@types/node': 20.19.1 fsevents: 2.3.3 + jiti: 2.6.1 lightningcss: 1.30.2 tsx: 4.20.6 + yaml: 2.8.3 void-elements@3.1.0: {} @@ -10044,6 +10611,8 @@ snapshots: transitivePeerDependencies: - debug + walk-up-path@4.0.0: {} + wcwidth@1.0.1: dependencies: defaults: 1.0.4 @@ -10104,6 +10673,8 @@ snapshots: yaml@2.3.1: {} + yaml@2.8.3: {} + yargs-parser@20.2.9: optional: true @@ -10158,6 +10729,8 @@ snapshots: zod@4.0.14: {} + zod@4.3.6: {} + zustand@5.0.7(@types/react@19.2.13)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)): optionalDependencies: '@types/react': 19.2.13 From 151e2710be4c05ea24d217bbb799307c4b112a6d Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:54:14 -0300 Subject: [PATCH 180/263] make OS taskbar API safe to call in web --- src/renderer/src/services/taskbar/index.ts | 2 +- src/renderer/src/services/taskbar/utils.ts | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/renderer/src/services/taskbar/index.ts b/src/renderer/src/services/taskbar/index.ts index aba76794..e63442b6 100644 --- a/src/renderer/src/services/taskbar/index.ts +++ b/src/renderer/src/services/taskbar/index.ts @@ -4,7 +4,7 @@ import taskbarAPI from "./utils"; * Notify the user with a sound and an action on the taskbar/dock */ function notify() { - taskbarAPI().notify(); + taskbarAPI()?.notify?.(); const audio = new Audio("audio/notification.mp3"); audio.play(); } diff --git a/src/renderer/src/services/taskbar/utils.ts b/src/renderer/src/services/taskbar/utils.ts index bd6cc604..f7e23bad 100644 --- a/src/renderer/src/services/taskbar/utils.ts +++ b/src/renderer/src/services/taskbar/utils.ts @@ -4,8 +4,4 @@ */ export default function taskbar() { if (window.taskbar) return window.taskbar; - - throw new Error( - 'There was an error trying to use the "taskbar" API, check your preload script', - ); } From eb791d074b276f575695cb98348eaf847da3c4d7 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:54:31 -0300 Subject: [PATCH 181/263] add missing anonymize value on label attrs --- src/renderer/src/types/aymurai.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/src/types/aymurai.ts b/src/renderer/src/types/aymurai.ts index b62ac1f0..abd9dee8 100644 --- a/src/renderer/src/types/aymurai.ts +++ b/src/renderer/src/types/aymurai.ts @@ -13,6 +13,7 @@ type LabelAttributes = { aymurai_alt_start_char: number | null; aymurai_alt_end_char: number | null; canonical_entity_id?: string | null; + aymurai_anonymize?: boolean | null; }; export type PredictLabel = { From 49c3bc22c653f94a24bee92ef2431c879ce097cf Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 04:57:01 -0300 Subject: [PATCH 182/263] fix electron ts issues --- electron.vite.config.ts | 9 ++++++++- src/main/createWindow.ts | 5 ++--- tsconfig.node.json | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/electron.vite.config.ts b/electron.vite.config.ts index a83d94b9..9f4a2aab 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -6,6 +6,7 @@ * `envDir` is set explicitly so `.env` files are resolved from the project root. */ import { resolve } from "node:path"; +import { tanstackRouter } from "@tanstack/router-plugin/vite"; import react from "@vitejs/plugin-react"; import { defineConfig, externalizeDepsPlugin } from "electron-vite"; @@ -26,6 +27,12 @@ export default defineConfig({ "@": resolve("src/renderer/src"), }, }, - plugins: [react()], + plugins: [ + tanstackRouter({ + target: "react", + autoCodeSplitting: true, + }), + react(), + ], }, }); diff --git a/src/main/createWindow.ts b/src/main/createWindow.ts index 966ea137..379be1e7 100644 --- a/src/main/createWindow.ts +++ b/src/main/createWindow.ts @@ -33,12 +33,11 @@ function configureWindow(window: BrowserWindow | null) { window.show(); }); - window.webContents.on("new-window", (e, url) => { - // Check if the url is in the 'whitelist' + window.webContents.setWindowOpenHandler(({ url }) => { if (EXTERNAL_URLS.find((val) => url.includes(val))) { - e.preventDefault(); shell.openExternal(url); } + return { action: "deny" }; }); // and handlers diff --git a/tsconfig.node.json b/tsconfig.node.json index db23a68c..414dff54 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -3,6 +3,7 @@ "include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*"], "compilerOptions": { "composite": true, + "moduleResolution": "bundler", "types": ["electron-vite/node"] } } From b888214a0191881a9d2e1b3b85dd2b74a6f8ec4b Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 11:17:20 -0300 Subject: [PATCH 183/263] make how it works modal bigger --- src/renderer/src/components/how-it-works-modal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/src/components/how-it-works-modal.tsx b/src/renderer/src/components/how-it-works-modal.tsx index 32d034e6..cd1acf14 100644 --- a/src/renderer/src/components/how-it-works-modal.tsx +++ b/src/renderer/src/components/how-it-works-modal.tsx @@ -34,7 +34,7 @@ const closeButton = css({ }); const content = css({ - maxWidth: "[1000px]", + minWidth: "[900px]", }); interface HowItWorksModalProps { From a723be01578eaea4b41952cee5025bbac38cd924 Mon Sep 17 00:00:00 2001 From: AymurAI Frontend Date: Mon, 27 Apr 2026 13:29:48 -0300 Subject: [PATCH 184/263] restore useNotify feature in process page --- src/renderer/src/hooks/useNotify.ts | 34 ------------------- .../src/routes/app.$feature/process.tsx | 11 +++++- 2 files changed, 10 insertions(+), 35 deletions(-) delete mode 100644 src/renderer/src/hooks/useNotify.ts diff --git a/src/renderer/src/hooks/useNotify.ts b/src/renderer/src/hooks/useNotify.ts deleted file mode 100644 index 081c4a0d..00000000 --- a/src/renderer/src/hooks/useNotify.ts +++ /dev/null @@ -1,34 +0,0 @@ -import taskbar from "@/services/taskbar"; -import type { - ProcessState, - initProcessState, -} from "@/utils/process/initProcessState"; -import { useEffect, useState } from "react"; - -/** - * Checks if the prediction process is completed - * @param state Current files state - * @returns `true` if the prediction process is completed, `false` otherwise - */ -function isPredictionCompleted(state: ProcessState[]) { - return !state.some(({ status }) => status === "processing"); -} - -export default function useNotify( - process: ReturnType, -) { - const [isToastVisible, setIsToastVisible] = useState(false); - - const hideToast = () => setIsToastVisible(false); - - // Not ideal to use an useEffect to change an state, but doing it ina proper way - // requires refactor to change state based on process state - useEffect(() => { - if (isPredictionCompleted(process) && !isToastVisible) { - taskbar.notify(); - setIsToastVisible(true); - } - }, [isPredictionCompleted(process)]); - - return { isToastVisible, hideToast }; -} diff --git a/src/renderer/src/routes/app.$feature/process.tsx b/src/renderer/src/routes/app.$feature/process.tsx index 9dc55a0e..81bf6ea1 100644 --- a/src/renderer/src/routes/app.$feature/process.tsx +++ b/src/renderer/src/routes/app.$feature/process.tsx @@ -18,13 +18,14 @@ import { HStack, Stack, styled } from "@/styled/jsx"; import type { Workflows } from "@/types/aymurai"; import { FeatureFlowEnum, featureNamespace } from "@/types/features"; import type { DocFile } from "@/types/file"; +import taskbar from "@/services/taskbar"; import { useQueryClient } from "@tanstack/react-query"; import { createFileRoute, useNavigate, useParams, } from "@tanstack/react-router"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; export const Route = createFileRoute("/app/$feature/process")({ @@ -43,6 +44,7 @@ function RouteComponent() { const files = useFiles(); const [isDismissed, setIsDismissed] = useState(false); + const hasNotified = useRef(false); const workflow: Workflows = feature === FeatureFlowEnum.Anonymizer ? "anonymizer" : "datapublic"; @@ -69,6 +71,13 @@ function RouteComponent() { disambiguateStatuses[f.data.name]?.status === "processing", ); + useEffect(() => { + if (files.length > 0 && !isProcessing && !hasNotified.current) { + hasNotified.current = true; + taskbar.notify(); + } + }, [isProcessing, files.length]); + // Weighted progress: 10% parse / 70% predict / 20% disambiguate (anonymizer) // or 10% parse / 90% predict (datapublic). const getProgress = (fileName: string): number => { From f4d5c5aae0c6c4d10e5c4b0f78aa5fc8ba4e7ee6 Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Mon, 27 Apr 2026 15:40:45 -0300 Subject: [PATCH 185/263] changes in render --- .../transcription-editor/SpeakerDialog.tsx | 63 +++++++++ src/renderer/src/env.d.ts | 1 + src/renderer/src/hooks/useTranscribe.ts | 50 ++++++- src/renderer/src/pages/login/Host.tsx | 7 +- .../src/pages/process/voice/index.tsx | 126 +++++++++++++++++- .../src/reducers/transcription/actions.ts | 20 +++ .../src/reducers/transcription/index.ts | 22 +++ src/renderer/src/schema/asr.ts | 8 ++ .../src/services/aymurai/asrMapper.ts | 16 ++- .../src/services/aymurai/transcribe.ts | 65 ++++++--- .../src/services/aymurai/transcribeStream.ts | 114 ++++++++++++++++ src/renderer/src/utils/config.ts | 22 ++- 12 files changed, 475 insertions(+), 39 deletions(-) create mode 100644 src/renderer/src/services/aymurai/transcribeStream.ts diff --git a/src/renderer/src/components/transcription-editor/SpeakerDialog.tsx b/src/renderer/src/components/transcription-editor/SpeakerDialog.tsx index ddf35605..8661ee1e 100644 --- a/src/renderer/src/components/transcription-editor/SpeakerDialog.tsx +++ b/src/renderer/src/components/transcription-editor/SpeakerDialog.tsx @@ -8,6 +8,7 @@ import { addSpeaker, reassignTurnSpeaker, renameSpeakerGlobal, + updateTurnStartMs, } from "@/reducers/transcription/actions"; import { styled } from "@/styles/stitches.config"; import type { @@ -16,6 +17,22 @@ import type { Transcription, Turn, } from "@/types/transcription"; +import { formatMs } from "./formatMs"; + +// Parses "mm:ss" or "hh:mm:ss" into milliseconds. Returns null on invalid input. +function parseTimestampToMs(input: string): number | null { + const trimmed = input.trim(); + if (!/^\d{1,3}(?::\d{1,2}){1,2}$/.test(trimmed)) return null; + const parts = trimmed.split(":").map((p) => Number.parseInt(p, 10)); + if (parts.some((n) => Number.isNaN(n))) return null; + let h = 0; + let m = 0; + let s = 0; + if (parts.length === 2) [m, s] = parts; + else [h, m, s] = parts; + if (m > 59 || s > 59) return null; + return ((h * 60 + m) * 60 + s) * 1000; +} // --------------------------------------------------------------------------- // Styled components @@ -174,6 +191,8 @@ function SpeakerDialog({ const [selectedSpeakerId, setSelectedSpeakerId] = useState(turn.speakerId); const [showNewSpeaker, setShowNewSpeaker] = useState(false); const [newSpeakerName, setNewSpeakerName] = useState(""); + const [timestampValue, setTimestampValue] = useState(formatMs(turn.startMs)); + const [timestampError, setTimestampError] = useState(null); const handleRename = () => { const trimmed = renameValue.trim(); @@ -182,6 +201,21 @@ function SpeakerDialog({ onClose(); }; + const handleTimestampSave = () => { + const parsed = parseTimestampToMs(timestampValue); + if (parsed === null) { + setTimestampError("Formato inválido. Usá mm:ss o hh:mm:ss."); + return; + } + if (parsed === turn.startMs) { + onClose(); + return; + } + setTimestampError(null); + dispatch(updateTurnStartMs(transcription.id, turn.id, parsed)); + onClose(); + }; + const handleSelectSpeaker = (speakerId: string) => { setSelectedSpeakerId(speakerId); setShowNewSpeaker(false); @@ -228,6 +262,35 @@ function SpeakerDialog({ + {/* Section: Edit timestamp */} +
+ Marca de tiempo + + { + setTimestampValue(e.target.value); + if (timestampError) setTimestampError(null); + }} + onKeyDown={(e) => { + if (e.key === "Enter") handleTimestampSave(); + }} + placeholder="mm:ss" + inputMode="numeric" + aria-label="Marca de tiempo del turno" + /> + + + + {timestampError ?? + "Formato mm:ss o hh:mm:ss. Cambia el inicio de este turno."} + +
+ + + {/* Section B: Change this turn */}
Cambiar este turno diff --git a/src/renderer/src/env.d.ts b/src/renderer/src/env.d.ts index 31705f39..b1df01f4 100644 --- a/src/renderer/src/env.d.ts +++ b/src/renderer/src/env.d.ts @@ -3,6 +3,7 @@ interface ImportMetaEnv { readonly VITE_USE_MOCK_STT?: string; readonly VITE_STT_MOCK_DELAY_MS?: string; + readonly VITE_ASR_USE_CACHE?: string; } interface ImportMeta { diff --git a/src/renderer/src/hooks/useTranscribe.ts b/src/renderer/src/hooks/useTranscribe.ts index 0149f767..db695a80 100644 --- a/src/renderer/src/hooks/useTranscribe.ts +++ b/src/renderer/src/hooks/useTranscribe.ts @@ -26,8 +26,13 @@ export function useTranscribe( ) { const [progress, setProgress] = useState(0); const [status, setStatus] = useState("idle"); + const [partialText, setPartialText] = useState(""); - const controller = useRef(new AbortController()); + // Tracks the AbortController of the in-flight run so the consumer's abort() + // can cancel whatever is currently running. A new controller is created per + // run inside the effect — never reuse one across runs (an aborted controller + // stays aborted forever). + const activeControllerRef = useRef(null); // biome-ignore lint/correctness/useExhaustiveDependencies: intentionally omitting onStatusChange to avoid re-runs on parent re-renders const updateStatus = useCallback((newValue: TranscribeStatus) => { @@ -36,9 +41,10 @@ export function useTranscribe( }, []); const abort = () => { - controller.current.abort(); + activeControllerRef.current?.abort(); updateStatus("stopped"); setProgress(0); + setPartialText(""); }; // biome-ignore lint/correctness/useExhaustiveDependencies: dispatch/onTranscription/updateStatus are stable callbacks; files is the intended trigger @@ -46,19 +52,42 @@ export function useTranscribe( if (files.length === 0) return; let active = true; + const controller = new AbortController(); + activeControllerRef.current = controller; + const perFileRatios = new Array(files.length).fill(0); + + const recomputeProgress = () => { + if (!active) return; + const total = perFileRatios.reduce((sum, r) => sum + r, 0); + setProgress(total / files.length); + }; const run = async () => { updateStatus("processing"); setProgress(0); - - const promises = files.map(async (file) => { - const result = await transcribe(file, controller.current.signal); + setPartialText(""); + + const promises = files.map(async (file, idx) => { + const result = await transcribe(file, { + signal: controller.signal, + onProgress: (ratio) => { + if (!active) return; + perFileRatios[idx] = ratio; + recomputeProgress(); + }, + onPartialText: (text) => { + if (!active) return; + setPartialText(text); + }, + }); if (!active) return; + perFileRatios[idx] = 1; + recomputeProgress(); + onTranscription?.(result); dispatch?.(addTranscription(result)); - setProgress((current) => current + 1 / files.length); }); await Promise.all(promises) @@ -81,8 +110,15 @@ export function useTranscribe( return () => { active = false; + // Cancel the in-flight SSE so a re-run (e.g. React StrictMode's + // mount → unmount → mount in dev) doesn't leave a stale stream open. + // The catch handler bails early because `active` is already false. + controller.abort(); + if (activeControllerRef.current === controller) { + activeControllerRef.current = null; + } }; }, [files]); - return { progress, status, abort }; + return { progress, status, abort, partialText }; } diff --git a/src/renderer/src/pages/login/Host.tsx b/src/renderer/src/pages/login/Host.tsx index 111a2dbb..e3ac2a22 100644 --- a/src/renderer/src/pages/login/Host.tsx +++ b/src/renderer/src/pages/login/Host.tsx @@ -91,7 +91,12 @@ export function Host() { {/* Remote host option selected */} {isLocal === false && ( - + Ingresa la dirección del servidor al que deseas conectarte diff --git a/src/renderer/src/pages/process/voice/index.tsx b/src/renderer/src/pages/process/voice/index.tsx index dd90c99d..53ee5478 100644 --- a/src/renderer/src/pages/process/voice/index.tsx +++ b/src/renderer/src/pages/process/voice/index.tsx @@ -1,5 +1,5 @@ import { Bell } from "phosphor-react"; -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; import { useNavigate } from "react-router-dom"; import { @@ -20,6 +20,63 @@ import { useFiles } from "@/hooks"; import { useTranscribe } from "@/hooks/useTranscribe"; import { useTranscriptionDispatch } from "@/hooks/useTranscriptions"; import { Footer, Section } from "@/layout/main"; +import { keyframes, styled } from "@/styles"; + +const scrollUp = keyframes({ + "0%": { transform: "translateY(100%)" }, + "100%": { transform: "translateY(-100%)" }, +}); + +const PreviewViewport = styled("div", { + position: "relative", + alignSelf: "stretch", + width: "100%", + height: "240px", + overflow: "hidden", + border: "1px solid #E5E3E0", + borderRadius: "8px", + padding: "20px 24px", + backgroundColor: "rgba(255, 255, 255, 0.6)", + boxSizing: "border-box", + maskImage: + "linear-gradient(to bottom, transparent 0%, black 14%, black 86%, transparent 100%)", + WebkitMaskImage: + "linear-gradient(to bottom, transparent 0%, black 14%, black 86%, transparent 100%)", +}); + +const PreviewTrack = styled("div", { + position: "absolute", + left: "24px", + right: "24px", + fontFamily: "$primary", + fontWeight: 300, + fontSize: "18px", + lineHeight: "30px", + color: "#625C68", + whiteSpace: "pre-wrap", + willChange: "transform", + animationName: `${scrollUp}`, + animationTimingFunction: "linear", + animationIterationCount: "infinite", +}); + +const PreviewPlaceholder = styled("span", { + position: "absolute", + inset: "20px 24px", + fontFamily: "$primary", + fontWeight: 300, + fontSize: "18px", + lineHeight: "30px", + color: "#9F99A5", + fontStyle: "italic", +}); + +// ~25ms per character so the preview scrolls at a brisk but readable pace, +// clamped so very short or very long texts still feel right. +function estimateScrollDuration(text: string): number { + const chars = text.length || 1; + return Math.max(6, Math.min(40, chars * 0.025)); +} export default function VoiceProcess() { const navigate = useNavigate(); @@ -28,7 +85,7 @@ export default function VoiceProcess() { const audioFiles = useMemo(() => files.map((f) => f.data), [files]); - const { progress, status } = useTranscribe(audioFiles, { + const { progress, status, partialText } = useTranscribe(audioFiles, { dispatch: transcriptionDispatch, }); @@ -36,8 +93,44 @@ export default function VoiceProcess() { const isCompleted = status === "completed"; const isError = status === "error"; + const isProcessing = status === "processing"; const progressPercent = Math.round(progress * 100); + // Show the latest partial text in the preview, but only swap it in once the + // current scroll loop completes — otherwise each SSE update would cut the + // animation mid-flight and (with very frequent updates) leave the track + // perpetually starting from off-screen, looking blank. + const [displayedText, setDisplayedText] = useState(""); + const pendingTextRef = useRef(""); + + useEffect(() => { + pendingTextRef.current = partialText; + // First text ever — start the loop immediately rather than waiting for an + // iteration boundary that doesn't exist yet. + if (partialText && !displayedText) { + setDisplayedText(partialText); + } + }, [partialText, displayedText]); + + // Reset preview state when transcription finishes or restarts. + useEffect(() => { + if (!isProcessing) { + setDisplayedText(""); + pendingTextRef.current = ""; + } + }, [isProcessing]); + + const previewDuration = useMemo( + () => estimateScrollDuration(displayedText), + [displayedText], + ); + + const handleTrackIteration = () => { + if (pendingTextRef.current && pendingTextRef.current !== displayedText) { + setDisplayedText(pendingTextRef.current); + } + }; + // biome-ignore lint/correctness/useExhaustiveDependencies: only fire when completion changes, not on every isToastVisible toggle useEffect(() => { if (isCompleted && !isToastVisible) { @@ -64,8 +157,13 @@ export default function VoiceProcess() { 2. Transcripción de audio - - + + AymurAI está transcribiendo los archivos de audio @@ -95,6 +193,26 @@ export default function VoiceProcess() { css={{ width: `${isCompleted ? 100 : progressPercent}%` }} /> + + {isProcessing && ( + + {displayedText ? ( + + {displayedText} + + ) : ( + + Esperando las primeras palabras… + + )} + + )} diff --git a/src/renderer/src/reducers/transcription/actions.ts b/src/renderer/src/reducers/transcription/actions.ts index 83ef63b3..0e507ea6 100644 --- a/src/renderer/src/reducers/transcription/actions.ts +++ b/src/renderer/src/reducers/transcription/actions.ts @@ -14,6 +14,7 @@ export enum ActionTypes { RENAME_SPEAKER_GLOBAL = "RENAME_SPEAKER_GLOBAL", REASSIGN_TURN_SPEAKER = "REASSIGN_TURN_SPEAKER", UPDATE_TURN_TEXT = "UPDATE_TURN_TEXT", + UPDATE_TURN_START_MS = "UPDATE_TURN_START_MS", INSERT_TURN = "INSERT_TURN", REMOVE_TURN = "REMOVE_TURN", ADD_SPEAKER = "ADD_SPEAKER", @@ -123,6 +124,25 @@ export function updateTurnText( }; } +export type UpdateTurnStartMsAction = Action< + ActionTypes.UPDATE_TURN_START_MS, + { transcriptionId: string; turnId: string; startMs: number } +>; +/** + * Updates the start timestamp (in milliseconds) of a turn. + * If the new start exceeds the current end, end is shifted to keep duration positive. + */ +export function updateTurnStartMs( + transcriptionId: string, + turnId: string, + startMs: number, +): UpdateTurnStartMsAction { + return { + type: ActionTypes.UPDATE_TURN_START_MS, + payload: { transcriptionId, turnId, startMs }, + }; +} + export type InsertTurnAction = Action< ActionTypes.INSERT_TURN, { transcriptionId: string; afterTurnId: string | null; turn: Turn } diff --git a/src/renderer/src/reducers/transcription/index.ts b/src/renderer/src/reducers/transcription/index.ts index 392a2798..1bb2c4b1 100644 --- a/src/renderer/src/reducers/transcription/index.ts +++ b/src/renderer/src/reducers/transcription/index.ts @@ -10,6 +10,7 @@ import { type RemoveTranscriptionAction, type RemoveTurnAction, type RenameSpeakerGlobalAction, + type UpdateTurnStartMsAction, type UpdateTurnTextAction, } from "./actions"; @@ -21,6 +22,7 @@ export type TranscriptionAction = | RenameSpeakerGlobalAction | ReassignTurnSpeakerAction | UpdateTurnTextAction + | UpdateTurnStartMsAction | InsertTurnAction | RemoveTurnAction | AddSpeakerAction @@ -128,6 +130,26 @@ export default function reducer( })); } + // ---------------- + // UPDATE TURN START MS + // ---------------- + case ActionTypes.UPDATE_TURN_START_MS: { + const { transcriptionId, turnId, startMs } = payload; + const safeStart = Math.max(0, Math.floor(startMs)); + return updateTranscription(state, transcriptionId, (t) => ({ + ...t, + turns: t.turns.map((turn) => { + if (turn.id !== turnId) return turn; + const duration = Math.max(0, turn.endMs - turn.startMs); + return { + ...turn, + startMs: safeStart, + endMs: safeStart + duration, + }; + }), + })); + } + // ---------------- // INSERT TURN // ---------------- diff --git a/src/renderer/src/schema/asr.ts b/src/renderer/src/schema/asr.ts index e2128f39..cc63867c 100644 --- a/src/renderer/src/schema/asr.ts +++ b/src/renderer/src/schema/asr.ts @@ -13,5 +13,13 @@ export const ASRDocumentSchema = z.object({ document: z.array(ASRParagraphSchema), }); +export const ASRStreamEventSchema = z.object({ + document_id: z.string(), + document: z.array(ASRParagraphSchema), + current_time: z.number().nullable(), + total_time: z.number(), +}); + export type ASRParagraph = z.infer; export type ASRDocument = z.infer; +export type ASRStreamEvent = z.infer; diff --git a/src/renderer/src/services/aymurai/asrMapper.ts b/src/renderer/src/services/aymurai/asrMapper.ts index 94ff3a7f..77a37d15 100644 --- a/src/renderer/src/services/aymurai/asrMapper.ts +++ b/src/renderer/src/services/aymurai/asrMapper.ts @@ -98,10 +98,14 @@ export function mapTranscriptionToASRParagraphRequests( speakerNoMap.set(speaker.id, idx + 1); } - return transcription.turns.map((turn) => ({ - speaker_no: speakerNoMap.get(turn.speakerId) ?? 1, - start: turn.startMs / 1000, - end: turn.endMs / 1000, - text: turn.text, - })); + return transcription.turns.map((turn) => { + const speaker = transcription.speakers.find((s) => s.id === turn.speakerId); + return { + speaker_no: speakerNoMap.get(turn.speakerId) ?? 1, + speaker_name: speaker?.label ?? null, + start: turn.startMs / 1000, + end: turn.endMs / 1000, + text: turn.text, + }; + }); } diff --git a/src/renderer/src/services/aymurai/transcribe.ts b/src/renderer/src/services/aymurai/transcribe.ts index d2a7d7e5..f39ea160 100644 --- a/src/renderer/src/services/aymurai/transcribe.ts +++ b/src/renderer/src/services/aymurai/transcribe.ts @@ -1,39 +1,66 @@ import { CanceledError } from "axios"; -import { ASRDocumentSchema } from "@/schema/asr"; import type { Transcription } from "@/types/transcription"; -import { STT_MOCK_DELAY_MS, USE_MOCK_STT } from "@/utils/config"; -import api from "../api"; -import { mapASRDocumentToTranscription } from "./asrMapper"; +import { STT_MOCK_DELAY_MS, USE_ASR_CACHE, USE_MOCK_STT } from "@/utils/config"; import { buildFixture } from "./fixtures/transcription"; +import { transcribeStream } from "./transcribeStream"; + +export interface TranscribeOptions { + signal?: AbortSignal; + onProgress?: (ratio: number) => void; + onPartialText?: (text: string) => void; +} + +const MOCK_PREVIEW_CHUNKS = [ + "Estamos aquí reunidos en virtud de un caso que tiene el número 78274.", + "La fiscalía está trabajando la investigación de ese caso, para lo cual estaba prevista la discusión de los hechos como corresponde en un juicio oral y público.", + "Nosotros lo que solicitamos es la suspensión del presente juicio a prueba en la primera parte del artículo 76 del código penal.", + "A los efectos de la suspensión lo que propuso mi cliente fue el pago de 100.000 pesos en cuatro cuotas de 25.000 pesos.", + "Tiene alguna propuesta más allá de que las pautas están supeditadas a que la fiscalía pueda fundar respecto de los hechos y los objetivos.", +]; export async function transcribe( file: File, - signal?: AbortSignal, + { signal, onProgress, onPartialText }: TranscribeOptions = {}, ): Promise { if (USE_MOCK_STT) { return new Promise((resolve, reject) => { - const timer = setTimeout( - () => resolve(buildFixture(file)), - STT_MOCK_DELAY_MS, - ); + const startedAt = Date.now(); + const tickMs = 100; + let lastChunkIdx = -1; + const tick = setInterval(() => { + const elapsed = Date.now() - startedAt; + const ratio = Math.min(0.99, elapsed / STT_MOCK_DELAY_MS); + onProgress?.(ratio); + + if (onPartialText) { + const chunkIdx = Math.min( + MOCK_PREVIEW_CHUNKS.length - 1, + Math.floor(ratio * MOCK_PREVIEW_CHUNKS.length), + ); + if (chunkIdx !== lastChunkIdx) { + lastChunkIdx = chunkIdx; + onPartialText(MOCK_PREVIEW_CHUNKS.slice(0, chunkIdx + 1).join(" ")); + } + } + }, tickMs); + const timer = setTimeout(() => { + clearInterval(tick); + onProgress?.(1); + resolve(buildFixture(file)); + }, STT_MOCK_DELAY_MS); signal?.addEventListener("abort", () => { + clearInterval(tick); clearTimeout(timer); reject(new CanceledError()); }); }); } - const audioObjectUrl = URL.createObjectURL(file); - - const form = new FormData(); - form.append("file", file); - - const raw = await api.post("/asr/transcribe", form, { - headers: { "Content-Type": "multipart/form-data" }, + return transcribeStream(file, { signal, + useCache: USE_ASR_CACHE, + onProgress, + onPartialText, }); - - const doc = ASRDocumentSchema.parse(raw); - return mapASRDocumentToTranscription(doc, file, audioObjectUrl); } diff --git a/src/renderer/src/services/aymurai/transcribeStream.ts b/src/renderer/src/services/aymurai/transcribeStream.ts new file mode 100644 index 00000000..7df353d0 --- /dev/null +++ b/src/renderer/src/services/aymurai/transcribeStream.ts @@ -0,0 +1,114 @@ +import { fetchEventSource } from "@microsoft/fetch-event-source"; +import { CanceledError } from "axios"; + +import { + type ASRDocument, + type ASRParagraph, + ASRStreamEventSchema, +} from "@/schema/asr"; +import api from "@/services/api"; +import type { Transcription } from "@/types/transcription"; +import { mapASRDocumentToTranscription } from "./asrMapper"; + +export interface TranscribeStreamOptions { + signal?: AbortSignal; + useCache: boolean; + onProgress?: (ratio: number) => void; + onPartialText?: (text: string) => void; +} + +class FatalStreamError extends Error {} + +export async function transcribeStream( + file: File, + { signal, useCache, onProgress, onPartialText }: TranscribeStreamOptions, +): Promise { + const audioObjectUrl = URL.createObjectURL(file); + + const form = new FormData(); + form.append("file", file); + + const paragraphs = new Map(); + const anonymousParagraphs: ASRParagraph[] = []; + let documentId: string | null = null; + + const baseURL = api.defaults.baseURL?.replace(/\/$/, ""); + if (!baseURL) { + throw new Error( + "No server selected. Connect to a server from the login page first.", + ); + } + const url = `${baseURL}/asr/transcribe/stream?use_cache=${useCache}`; + + try { + await fetchEventSource(url, { + method: "POST", + body: form, + signal, + openWhenHidden: true, + async onopen(response) { + if (!response.ok) { + throw new FatalStreamError( + `Transcription stream failed: ${response.status} ${response.statusText}`, + ); + } + }, + onmessage(ev) { + if (!ev.data) return; + const parsed = ASRStreamEventSchema.safeParse(JSON.parse(ev.data)); + if (!parsed.success) return; + + const { document_id, document, current_time, total_time } = parsed.data; + documentId = document_id; + + for (const para of document) { + if (para.paragraph_id) { + paragraphs.set(para.paragraph_id, para); + } else { + anonymousParagraphs.push(para); + } + } + + if (onProgress && total_time > 0) { + const ratio = (current_time ?? 0) / total_time; + onProgress(Math.max(0, Math.min(1, ratio))); + } + + if (onPartialText) { + // Each SSE event already carries the complete document so far; build + // the preview straight from it. Don't reuse the merged accumulators + // above because anonymous paragraphs get .push()'d every event and + // would duplicate themselves in the preview. + const cumulative = document + .filter((p) => p.speaker_no >= 0) + .map((p) => p.text.trim()) + .filter(Boolean) + .join(" "); + onPartialText(cumulative); + } + }, + onerror(err) { + // Disable the library's default retry behavior — re-throw to abort. + throw err; + }, + }); + } catch (err) { + if (signal?.aborted || (err as { name?: string })?.name === "AbortError") { + throw new CanceledError(); + } + throw err; + } + + if (!documentId) { + throw new Error("Transcription stream ended without a document_id"); + } + + const doc: ASRDocument = { + document_id: documentId, + document: [...paragraphs.values(), ...anonymousParagraphs], + }; + + onProgress?.(1); + + return mapASRDocumentToTranscription(doc, file, audioObjectUrl); +} diff --git a/src/renderer/src/utils/config.ts b/src/renderer/src/utils/config.ts index 613e335b..e58558d6 100644 --- a/src/renderer/src/utils/config.ts +++ b/src/renderer/src/utils/config.ts @@ -6,7 +6,17 @@ export const PREDICT_PORT = 8899; /** * Only allow these extensions to be analyzed */ -export const WHITELISTED_EXTENSIONS = ["doc", "docx", "pdf", "mp3", "wav", "m4a", "webm", "ogg", "flac"]; +export const WHITELISTED_EXTENSIONS = [ + "doc", + "docx", + "pdf", + "mp3", + "wav", + "m4a", + "webm", + "ogg", + "flac", +]; /** * Dataset Spreadsheet @@ -15,7 +25,9 @@ export const DATASET_URL = "https://docs.google.com/spreadsheets/d/1pzaGNM5BzRAOlj8p0NYtxnkU4VI_X5UcQsnIMOtLSVY/edit#gid=257379348"; /** - * AymurAI API URL + * AymurAI API URL — fallback only. The active base URL comes from the + * server-selection page (Zustand `localStore.serverHost`) which patches + * `api.defaults.baseURL` on connect. */ export const AYMURAI_API_URL = `http://localhost:${PREDICT_PORT}`; @@ -23,3 +35,9 @@ export const USE_MOCK_STT = import.meta.env.VITE_USE_MOCK_STT === "true"; export const STT_MOCK_DELAY_MS = Number( import.meta.env.VITE_STT_MOCK_DELAY_MS ?? 4000, ); + +// Cache ON in production, OFF in dev. Override with VITE_ASR_USE_CACHE=true|false. +export const USE_ASR_CACHE = + import.meta.env.VITE_ASR_USE_CACHE !== undefined + ? import.meta.env.VITE_ASR_USE_CACHE === "true" + : import.meta.env.PROD; From 275572c2af0cfd1d07465a2a31caf6de0f742848 Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Mon, 27 Apr 2026 15:41:24 -0300 Subject: [PATCH 186/263] add library for sse --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index ee45905f..27a97fc9 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "dependencies": { "@electron-toolkit/preload": "^3.0.2", "@electron-toolkit/utils": "^4.0.0", + "@microsoft/fetch-event-source": "^2.0.1", "electron-squirrel-startup": "^1.0.0" }, "devDependencies": { From 645be8673307d40f961b41b6f3bbe3ea72316d74 Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Mon, 27 Apr 2026 16:48:51 -0300 Subject: [PATCH 187/263] docs(readme): document pnpm prepare, lefthook, panda Recommend running `pnpm prepare` after install/pull (panda codegen + lefthook install), update the styling tech entry to Panda CSS, and replace the stale `pre-commit: LintStaged` script note with `prepare` and `knip` entries. Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 559f844f..f1f2d246 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ tools - ⚡ **Electron** as the _deployment and packaging tool_. It also serves the purpose of communicating the webapp with the _NodeJS_ process. -- 🪡 **Stitches** as the _styling library_ +- 🐼 **Panda CSS** as the _styling library_ (migrating off legacy Stitches) - 🛣️ **Tanstack React Router** as the _routing library_ to navigate across the webapp - 📄 **Mammoth** + **ExcelJS** as the _libraries_ to read and write `.docx` and datasheet files @@ -17,6 +17,7 @@ datasheet files - **pnpm** as _package manager_ - **biome** as code _linter and formatter_ +- **lefthook** for git hooks (pre-commit + pre-push gates) ##  Getting started @@ -28,6 +29,14 @@ datasheet files pnpm install ``` +1. Run `prepare` to generate the Panda CSS runtime and install the lefthook + git hooks (also runs automatically after `pnpm install`, but re-run it + after pulling changes that touch `panda.config.ts` or `lefthook.yml`): + + ```bash + pnpm prepare + ``` + 1. Start the app in development mode with ```bash @@ -72,7 +81,8 @@ datasheet files - `typecheck:node`: runs type checking on the _Electron_ application - `typecheck:web`: runs type checking on the _React_ application - `validate`: runs linting and type checking on both React and renderer -- `pre-commit`: runs _LintStaged_ +- `prepare`: runs `panda codegen` and installs lefthook git hooks (auto-runs after `pnpm install`) +- `knip`: detects unused exports and dependencies (also gated on `pre-push`) ### Deployment From f926d37c56d4ff4411f2d33bb20eaa0f409bcd40 Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Tue, 28 Apr 2026 10:52:04 -0300 Subject: [PATCH 188/263] fix(voice-to-text): audio-only picker, dedupe SSE, surface server errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Split WHITELISTED_EXTENSIONS into DOCUMENT_EXTENSIONS and AUDIO_EXTENSIONS; HiddenInput accepts an `extensions` override and the STT onboarding/preview flows now restrict the file picker to audio formats only. - Defer useTranscribe's mutate() by one microtask so StrictMode's mount→cleanup→remount issues a single SSE request instead of two. - Recognize `event: error` on the ASR stream, throw the server-provided detail/code as a FatalStreamError, and preserve its message through the outer catch so the UI surfaces real failure reasons instead of a generic abort. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/renderer/src/components/hidden-input.tsx | 16 ++++++--- .../components/voice-to-text/onboarding.tsx | 8 ++++- .../src/components/voice-to-text/preview.tsx | 8 ++++- src/renderer/src/constants/config.ts | 19 +++++------ src/renderer/src/hooks/useTranscribe.ts | 33 +++++++++++-------- .../src/services/aymurai/transcribeStream.ts | 23 +++++++++++++ 6 files changed, 78 insertions(+), 29 deletions(-) diff --git a/src/renderer/src/components/hidden-input.tsx b/src/renderer/src/components/hidden-input.tsx index c7e2d085..f1d3fd04 100644 --- a/src/renderer/src/components/hidden-input.tsx +++ b/src/renderer/src/components/hidden-input.tsx @@ -11,14 +11,22 @@ const input = css({ interface HiddenInputProps extends Omit, "onChange"> { onChange: React.ChangeEventHandler; + /** + * Optional whitelist override, e.g. audio-only extensions for the + * voice-to-text flow. Defaults to {@link WHITELISTED_EXTENSIONS}. + */ + extensions?: string[]; } -export default function HiddenInput({ className, ...props }: HiddenInputProps) { - // Convert the array into a '.dcox' form - const extensions = WHITELISTED_EXTENSIONS.map((ext) => `.${ext}`).join(","); +export default function HiddenInput({ + className, + extensions = WHITELISTED_EXTENSIONS, + ...props +}: HiddenInputProps) { + const accept = extensions.map((ext) => `.${ext}`).join(","); return ( - + ); } diff --git a/src/renderer/src/components/voice-to-text/preview.tsx b/src/renderer/src/components/voice-to-text/preview.tsx index d7b0b887..0b428e42 100644 --- a/src/renderer/src/components/voice-to-text/preview.tsx +++ b/src/renderer/src/components/voice-to-text/preview.tsx @@ -10,6 +10,7 @@ import MainContent from "@/components/layout/main-content"; import BackButton from "@/components/ui/back-button"; import Button from "@/components/ui/button"; import Card from "@/components/ui/card"; +import { AUDIO_EXTENSIONS } from "@/constants/config"; import RequireFile from "@/features/RequireFile"; import { useFileDispatch, useFiles } from "@/hooks"; import { SectionTitle } from "@/layout/section-title"; @@ -132,7 +133,12 @@ export default function VoicePreview() { - + ); } diff --git a/src/renderer/src/constants/config.ts b/src/renderer/src/constants/config.ts index 4af4af7e..f3d75837 100644 --- a/src/renderer/src/constants/config.ts +++ b/src/renderer/src/constants/config.ts @@ -6,17 +6,16 @@ export const DATAGENERO_URL = "https://www.datagenero.org/"; /** AI Predict port */ export const PREDICT_PORT = 8899; -/** Only allow these extensions to be analyzed */ +/** Document extensions accepted by the dataset/anonymizer flows. */ +export const DOCUMENT_EXTENSIONS = ["doc", "docx", "pdf"]; + +/** Audio extensions accepted by the voice-to-text flow. */ +export const AUDIO_EXTENSIONS = ["mp3", "wav", "m4a", "webm", "ogg", "flac"]; + +/** Union — kept for any consumer that needs to know "is this analyzable at all". */ export const WHITELISTED_EXTENSIONS = [ - "doc", - "docx", - "pdf", - "mp3", - "wav", - "m4a", - "webm", - "ogg", - "flac", + ...DOCUMENT_EXTENSIONS, + ...AUDIO_EXTENSIONS, ]; /** Dataset Spreadsheet */ diff --git a/src/renderer/src/hooks/useTranscribe.ts b/src/renderer/src/hooks/useTranscribe.ts index 5a48c9c5..2cf7d6d5 100644 --- a/src/renderer/src/hooks/useTranscribe.ts +++ b/src/renderer/src/hooks/useTranscribe.ts @@ -64,25 +64,32 @@ export function useTranscribe( setProgress(0); setPartialText(""); + let active = true; const controller = new AbortController(); controllerRef.current = controller; - mutate( - { files, signal: controller.signal }, - { - onSuccess: (results) => { - for (const result of results) { - onTranscriptionRef.current?.(result); - dispatchRef.current?.(addTranscription(result)); - } + // Defer the actual fire by one microtask. In React StrictMode dev, the + // mount → cleanup → remount pair runs synchronously: the cleanup below + // flips `active = false` before the microtask resolves, so the first + // mount's mutate is skipped and only the surviving mount issues the SSE + // request. In production (no double-mount), this is a no-op delay. + Promise.resolve().then(() => { + if (!active) return; + mutate( + { files, signal: controller.signal }, + { + onSuccess: (results) => { + for (const result of results) { + onTranscriptionRef.current?.(result); + dispatchRef.current?.(addTranscription(result)); + } + }, }, - }, - ); + ); + }); return () => { - // StrictMode cleanup or files change: abort silently. The mutation's - // CanceledError will be reflected as `error` status, but we treat it as - // a stop only if the user clicked stop (userAbortedRef). + active = false; controller.abort(); if (controllerRef.current === controller) { controllerRef.current = null; diff --git a/src/renderer/src/services/aymurai/transcribeStream.ts b/src/renderer/src/services/aymurai/transcribeStream.ts index 7df353d0..4051e53b 100644 --- a/src/renderer/src/services/aymurai/transcribeStream.ts +++ b/src/renderer/src/services/aymurai/transcribeStream.ts @@ -55,6 +55,25 @@ export async function transcribeStream( }, onmessage(ev) { if (!ev.data) return; + + // The backend signals failures with a named SSE event: + // event: error + // data: {"detail": "...", "code": "..."} + // Throwing inside onmessage aborts the stream and propagates to the + // outer catch with the server-provided message. + if (ev.event === "error") { + let detail = "Unexpected error during transcription"; + let code: string | undefined; + try { + const payload = JSON.parse(ev.data); + if (typeof payload?.detail === "string") detail = payload.detail; + if (typeof payload?.code === "string") code = payload.code; + } catch { + // fall through with the default message + } + throw new FatalStreamError(code ? `${detail} (${code})` : detail); + } + const parsed = ASRStreamEventSchema.safeParse(JSON.parse(ev.data)); if (!parsed.success) return; @@ -93,6 +112,10 @@ export async function transcribeStream( }, }); } catch (err) { + // A FatalStreamError originates from us (server-side `event: error` or a + // non-2xx response) — surface its message verbatim, even if the library + // also aborted the underlying request as a side-effect. + if (err instanceof FatalStreamError) throw err; if (signal?.aborted || (err as { name?: string })?.name === "AbortError") { throw new CanceledError(); } From 6649a7dc965fc22b20497e13f86ee6dc10483ec2 Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Tue, 28 Apr 2026 10:59:39 -0300 Subject: [PATCH 189/263] chore(knip): configure entry points and warn-only rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add explicit entry patterns so knip recognizes the Electron main/preload processes, the renderer entry, the route tree, and the various tool configs (electron-vite, forge, panda, postcss, vite). Reduces false positives from 29 unused files to 10 (all genuine legacy dead-code). Downgrade `files`, `exports`, `types`, and similar rules to `warn` so the pre-push gate surfaces remaining backlog without blocking pushes — the findings are advisory and can be triaged separately. Co-Authored-By: Claude Opus 4.7 (1M context) --- knip.json | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/knip.json b/knip.json index 38fab3b1..4af1b1ec 100644 --- a/knip.json +++ b/knip.json @@ -1,4 +1,55 @@ { "$schema": "https://unpkg.com/knip@6/schema.json", - "tags": ["-lintignore"] + "tags": ["-lintignore"], + "rules": { + "files": "warn", + "dependencies": "warn", + "devDependencies": "warn", + "optionalPeerDependencies": "warn", + "unlisted": "warn", + "unresolved": "warn", + "exports": "warn", + "types": "warn", + "duplicates": "warn", + "enumMembers": "warn", + "nsExports": "warn", + "nsTypes": "warn", + "binaries": "warn" + }, + "entry": [ + "src/main/index.ts", + "src/preload/index.ts", + "src/renderer/src/main.tsx", + "src/renderer/index.html", + "src/renderer/src/routes/**/*.{ts,tsx}", + "electron.vite.config.ts", + "forge.config.js", + "panda.config.ts", + "postcss.config.cjs", + "vite.config.ts" + ], + "project": ["src/**/*.{ts,tsx}"], + "ignore": [ + "src/renderer/src/styled/**", + "src/renderer/src/routeTree.gen.ts", + "**/*.d.ts" + ], + "ignoreDependencies": [ + "@electron-toolkit/preload", + "@electron-toolkit/utils", + "electron-squirrel-startup", + "@electron-forge/maker-deb", + "@electron-forge/maker-rpm", + "@electron-forge/maker-squirrel", + "@electron-forge/maker-zip", + "concurrently", + "electron", + "electron-debug", + "electron-devtools-installer", + "markdownlint-cli", + "nodemon", + "prettier", + "wait-on", + "postcss" + ] } From 526f30043cd0a9209d4d3d7077a77d6e0a94b733 Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 5 Jun 2026 09:45:39 -0300 Subject: [PATCH 190/263] test: add minimal vitest setup for renderer logic Installs vitest@2, jsdom, @testing-library/react+jest-dom; adds test/test:watch scripts, vitest.config.ts with @ alias, and a smoke test confirming the runner works. Co-Authored-By: Claude Sonnet 4.6 --- package.json | 11 +- pnpm-lock.yaml | 1070 +++++++++++++++++++++++++-- src/renderer/src/test/setup.ts | 1 + src/renderer/src/test/smoke.test.ts | 7 + vitest.config.ts | 17 + 5 files changed, 1046 insertions(+), 60 deletions(-) create mode 100644 src/renderer/src/test/setup.ts create mode 100644 src/renderer/src/test/smoke.test.ts create mode 100644 vitest.config.ts diff --git a/package.json b/package.json index 6d0d33bd..fc9e99df 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,9 @@ "build:win": "npm run build && electron-builder --win", "build:mac": "cross-env VITE_APP_MODE=electron electron-vite build && electron-builder --mac", "build:linux": "cross-env VITE_APP_MODE=electron electron-vite build && electron-builder --linux", - "knip": "knip" + "knip": "knip", + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "@electron-toolkit/preload": "^3.0.2", @@ -55,6 +57,8 @@ "@tanstack/react-router": "^1.139.12", "@tanstack/react-router-devtools": "^1.139.12", "@tanstack/router-plugin": "^1.139.12", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", "@types/node": "20", "@types/react": "19", "@types/react-dom": "19", @@ -70,6 +74,7 @@ "electron-vite": "^3.1.0", "exceljs": "^4.4.0", "i18next": "^25.8.13", + "jsdom": "^25.0.1", "knip": "^6.7.0", "lefthook": "^2.1.6", "markdownlint-cli": "^0.32.2", @@ -83,11 +88,9 @@ "regex-escape": "^3.4.10", "typescript": "^5.9.2", "vite": "^6.3.5", + "vitest": "^2.1.9", "wait-on": "^6.0.1", "zod": "^4.0.14", "zustand": "^5.0.7" - }, - "pnpm": { - "onlyBuiltDependencies": ["electron", "esbuild"] } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index abd8240b..c86d196c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,7 +44,7 @@ importers: version: 1.0.1(@types/node@20.19.1) '@pandacss/dev': specifier: ^1.8.1 - version: 1.8.1(hono@4.11.7)(typescript@5.9.2) + version: 1.8.1(hono@4.11.7)(jsdom@25.0.1)(typescript@5.9.2) '@radix-ui/react-dialog': specifier: ^1.1.15 version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -78,6 +78,12 @@ importers: '@tanstack/router-plugin': specifier: ^1.139.12 version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3)) + '@testing-library/jest-dom': + specifier: ^6.9.1 + version: 6.9.1 + '@testing-library/react': + specifier: ^16.3.2 + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@types/node': specifier: '20' version: 20.19.1 @@ -123,6 +129,9 @@ importers: i18next: specifier: ^25.8.13 version: 25.8.13(typescript@5.9.2) + jsdom: + specifier: ^25.0.1 + version: 25.0.1 knip: specifier: ^6.7.0 version: 6.7.0(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) @@ -162,6 +171,9 @@ importers: vite: specifier: ^6.3.5 version: 6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3) + vitest: + specifier: ^2.1.9 + version: 2.1.9(@types/node@20.19.1)(jsdom@25.0.1)(lightningcss@1.30.2) wait-on: specifier: ^6.0.1 version: 6.0.1 @@ -177,10 +189,16 @@ packages: 7zip-bin@5.2.0: resolution: {integrity: sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==} + '@adobe/css-tools@4.5.0': + resolution: {integrity: sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==} + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@asamuzakjp/css-color@3.2.0': + resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -343,10 +361,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.27.1': - resolution: {integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==} - engines: {node: '>=6.9.0'} - '@babel/runtime@7.28.6': resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} engines: {node: '>=6.9.0'} @@ -434,6 +448,34 @@ packages: '@clack/prompts@0.11.0': resolution: {integrity: sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==} + '@csstools/color-helpers@5.1.0': + resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} + engines: {node: '>=18'} + + '@csstools/css-calc@2.1.4': + resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-color-parser@3.1.0': + resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-parser-algorithms@3.0.5': + resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-tokenizer@3.0.4': + resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} + engines: {node: '>=18'} + '@csstools/postcss-cascade-layers@5.0.2': resolution: {integrity: sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg==} engines: {node: '>=18'} @@ -549,7 +591,7 @@ packages: engines: {node: '>=12'} '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': - resolution: {tarball: https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2} + resolution: {gitHosted: true, tarball: https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2} version: 10.2.0-electron.1 engines: {node: '>=12.13.0'} hasBin: true @@ -604,102 +646,204 @@ packages: '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + '@esbuild/aix-ppc64@0.25.5': resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.25.5': resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.25.5': resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.25.5': resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.25.5': resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.25.5': resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.25.5': resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.5': resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.25.5': resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.25.5': resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.25.5': resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.25.5': resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.25.5': resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.25.5': resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.25.5': resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.25.5': resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.25.5': resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==} engines: {node: '>=18'} @@ -712,6 +856,12 @@ packages: cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.5': resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==} engines: {node: '>=18'} @@ -724,30 +874,60 @@ packages: cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.5': resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.25.5': resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.25.5': resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.25.5': resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.25.5': resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==} engines: {node: '>=18'} @@ -1856,6 +2036,29 @@ packages: resolution: {integrity: sha512-9PImF1d1tovTUIpjFVa0W7Fwj/MHif7BaaczgJJfbv3sDt1Gh+oW9W9uCw9M3ndEJynnp5ZD/TTs0RGubH5ssg==} engines: {node: '>=12'} + '@testing-library/dom@10.4.1': + resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} + engines: {node: '>=18'} + + '@testing-library/jest-dom@6.9.1': + resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + + '@testing-library/react@16.3.2': + resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} + engines: {node: '>=18'} + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@tootallnate/once@2.0.0': resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} @@ -1866,6 +2069,9 @@ packages: '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -1943,6 +2149,35 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 + '@vitest/expect@2.1.9': + resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==} + + '@vitest/mocker@2.1.9': + resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@2.1.9': + resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==} + + '@vitest/runner@2.1.9': + resolution: {integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==} + + '@vitest/snapshot@2.1.9': + resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==} + + '@vitest/spy@2.1.9': + resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==} + + '@vitest/utils@2.1.9': + resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==} + '@vue/compiler-core@3.5.25': resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==} @@ -1961,6 +2196,7 @@ packages: '@xmldom/xmldom@0.8.10': resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} engines: {node: '>=10.0.0'} + deprecated: this version has critical issues, please update to the latest version abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} @@ -2029,6 +2265,10 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} @@ -2070,10 +2310,21 @@ packages: resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} engines: {node: '>=10'} + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + assert-plus@1.0.0: resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} engines: {node: '>=0.8'} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + ast-types@0.16.1: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} @@ -2238,6 +2489,10 @@ packages: caniuse-lite@1.0.30001766: resolution: {integrity: sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==} + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + chainsaw@0.1.0: resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==} @@ -2245,6 +2500,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} + engines: {node: '>= 16'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -2425,6 +2684,9 @@ packages: resolution: {integrity: sha512-ju88BYCQ2uvjO2bR+SsgLSTwTSctU+6Vp2ePbKPgSCZyy4MWZxYsT738DlKVRE5utUjobjPRm1MkTYKJxCmpTA==} engines: {node: '>=14.9.0'} + css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -2436,9 +2698,17 @@ packages: peerDependencies: postcss: ^8.4.32 + cssstyle@4.6.0: + resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} + engines: {node: '>=18'} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + data-urls@5.0.0: + resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} + engines: {node: '>=18'} + date-fns@2.30.0: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} engines: {node: '>=0.11'} @@ -2480,6 +2750,9 @@ packages: supports-color: optional: true + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + decode-formdata@0.9.0: resolution: {integrity: sha512-q5uwOjR3Um5YD+ZWPOF/1sGHVW9A5rCrRwITQChRXlmPkxDFBqCm4jNTIVdGHNH9OnR+V9MoZVgRhsFb+ARbUw==} @@ -2487,6 +2760,10 @@ packages: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} @@ -2514,6 +2791,10 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + detect-libc@2.0.4: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} @@ -2546,6 +2827,12 @@ packages: os: [darwin] hasBin: true + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + + dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + dotenv-expand@11.0.7: resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} engines: {node: '>=12'} @@ -2673,6 +2960,10 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -2691,6 +2982,9 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -2702,6 +2996,11 @@ packages: es6-error@4.1.1: resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + esbuild@0.25.5: resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==} engines: {node: '>=18'} @@ -2730,6 +3029,9 @@ packages: estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} @@ -2754,6 +3056,10 @@ packages: resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} engines: {node: '>=0.10.0'} + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + exponential-backoff@3.1.3: resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} @@ -2870,10 +3176,6 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - form-data@4.0.2: - resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} - engines: {node: '>= 6'} - form-data@4.0.5: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} @@ -3005,16 +3307,17 @@ packages: glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me glob@8.0.3: resolution: {integrity: sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==} engines: {node: '>=12'} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} @@ -3098,6 +3401,10 @@ packages: resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} engines: {node: '>=10'} + html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} + html-parse-stringify@3.0.1: resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} @@ -3245,6 +3552,9 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} @@ -3310,6 +3620,15 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + jsdom@25.0.1: + resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==} + engines: {node: '>=18'} + peerDependencies: + canvas: ^2.11.2 + peerDependenciesMeta: + canvas: + optional: true + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -3605,6 +3924,9 @@ packages: look-it-up@2.1.0: resolution: {integrity: sha512-nMoGWW2HurtuJf6XAL56FWTDCWLOTSsanrgwOyaR5Y4e3zfG5N/0cU5xWZSEU3tBxhQugRbV1xL9jb+ug7yZww==} + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + lowercase-keys@2.0.0: resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} engines: {node: '>=8'} @@ -3623,6 +3945,10 @@ packages: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} @@ -3721,6 +4047,10 @@ packages: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + minimatch@10.0.1: resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} engines: {node: 20 || >=22} @@ -3864,6 +4194,9 @@ packages: resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} engines: {node: '>=4'} + nwsapi@2.2.23: + resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -3982,6 +4315,9 @@ packages: resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} engines: {node: '>=0.10.0'} + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -4023,9 +4359,16 @@ packages: resolution: {integrity: sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ==} engines: {node: '>=4'} + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + pe-library@0.4.1: resolution: {integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==} engines: {node: '>=12', npm: '>=6'} @@ -4155,6 +4498,10 @@ packages: engines: {node: '>=14'} hasBin: true + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + proc-log@2.0.1: resolution: {integrity: sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -4217,6 +4564,7 @@ packages: rcedit@3.1.0: resolution: {integrity: sha512-WRlRdY1qZbu1L11DklT07KuHfRk42l0NFFJdaExELEu4fEQ982bP5Z6OWGPj/wLLIuKRQDCxZJGAwoFsxhZhNA==} engines: {node: '>= 10.0.0'} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. react-dom@19.2.4: resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} @@ -4246,6 +4594,9 @@ packages: typescript: optional: true + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-refresh@0.17.0: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} @@ -4322,6 +4673,10 @@ packages: resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} engines: {node: '>= 10.13.0'} + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + regex-escape@3.4.11: resolution: {integrity: sha512-051l4Hl/0HoJwTvNztrWVjoxLiseSfCrDgWqwR1cnGM/nyQSeIjmvti5zZ7HzOmsXDPaJ2k0iFxQ6/WNpJD5wQ==} @@ -4407,6 +4762,12 @@ packages: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} + rrweb-cssom@0.7.1: + resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} + + rrweb-cssom@0.8.0: + resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} + run-con@1.2.12: resolution: {integrity: sha512-5257ILMYIF4RztL9uoZ7V9Q97zHtNHn5bN3NobeAnzB1P3ASLgg8qocM2u+R18ttp+VEM78N2LK8XcNVtnSRrg==} hasBin: true @@ -4436,6 +4797,10 @@ packages: resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} engines: {node: '>=10'} + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -4533,6 +4898,9 @@ packages: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -4615,6 +4983,9 @@ packages: resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + stat-mode@1.0.0: resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==} engines: {node: '>= 6'} @@ -4623,6 +4994,9 @@ packages: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -4653,6 +5027,10 @@ packages: resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} engines: {node: '>=0.10.0'} + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -4689,6 +5067,9 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + table@6.9.0: resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} engines: {node: '>=10.0.0'} @@ -4700,6 +5081,7 @@ packages: tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me temp-file@3.4.0: resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} @@ -4723,6 +5105,12 @@ packages: tiny-warning@1.0.3: resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyglobby@0.2.14: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} @@ -4735,6 +5123,25 @@ packages: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + + tldts-core@6.1.86: + resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} + + tldts@6.1.86: + resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} + hasBin: true + tmp-promise@3.0.3: resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} @@ -4754,9 +5161,17 @@ packages: resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==} hasBin: true + tough-cookie@5.1.2: + resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} + engines: {node: '>=16'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} + traverse@0.3.9: resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==} @@ -4927,6 +5342,7 @@ packages: uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true validate-npm-package-license@3.0.4: @@ -4940,6 +5356,42 @@ packages: resolution: {integrity: sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==} engines: {node: '>=0.6.0'} + vite-node@2.1.9: + resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + + vite@5.4.21: + resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + vite@6.3.5: resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -5020,10 +5472,39 @@ packages: yaml: optional: true + vitest@2.1.9: + resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.9 + '@vitest/ui': 2.1.9 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + void-elements@3.1.0: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} engines: {node: '>=0.10.0'} + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + wait-on@6.0.1: resolution: {integrity: sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==} engines: {node: '>=10.0.0'} @@ -5039,9 +5520,26 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -5054,6 +5552,11 @@ packages: engines: {node: '>= 8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -5077,6 +5580,22 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + xmlbuilder@15.1.1: resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} engines: {node: '>=8.0'} @@ -5174,11 +5693,21 @@ snapshots: 7zip-bin@5.2.0: {} + '@adobe/css-tools@4.5.0': {} + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 + '@asamuzakjp/css-color@3.2.0': + dependencies: + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + lru-cache: 10.4.3 + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.27.1 @@ -5414,8 +5943,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/runtime@7.27.1': {} - '@babel/runtime@7.28.6': {} '@babel/template@7.27.2': @@ -5431,7 +5958,7 @@ snapshots: '@babel/parser': 7.27.4 '@babel/template': 7.27.2 '@babel/types': 7.27.3 - debug: 4.4.1 + debug: 4.4.3 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -5504,6 +6031,26 @@ snapshots: picocolors: 1.1.1 sisteransi: 1.0.5 + '@csstools/color-helpers@5.1.0': {} + + '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/color-helpers': 5.1.0 + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-tokenizer@3.0.4': {} + '@csstools/postcss-cascade-layers@5.0.2(postcss@8.5.6)': dependencies: '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) @@ -5791,14 +6338,14 @@ snapshots: '@electron/notarize@1.2.4': dependencies: - debug: 4.4.1 + debug: 4.4.3 fs-extra: 9.1.0 transitivePeerDependencies: - supports-color '@electron/notarize@2.5.0': dependencies: - debug: 4.4.1 + debug: 4.4.3 fs-extra: 9.1.0 promise-retry: 2.0.1 transitivePeerDependencies: @@ -5807,7 +6354,7 @@ snapshots: '@electron/osx-sign@1.3.1': dependencies: compare-version: 0.1.2 - debug: 4.4.1 + debug: 4.4.3 fs-extra: 10.1.0 isbinaryfile: 4.0.10 minimist: 1.2.8 @@ -5818,7 +6365,7 @@ snapshots: '@electron/osx-sign@1.3.3': dependencies: compare-version: 0.1.2 - debug: 4.4.1 + debug: 4.4.3 fs-extra: 10.1.0 isbinaryfile: 4.0.10 minimist: 1.2.8 @@ -5831,7 +6378,7 @@ snapshots: '@electron/node-gyp': https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2 '@malept/cross-spawn-promise': 2.0.0 chalk: 4.1.2 - debug: 4.4.1 + debug: 4.4.3 detect-libc: 2.0.4 fs-extra: 10.1.0 got: 11.8.6 @@ -5870,7 +6417,7 @@ snapshots: dependencies: '@electron/asar': 3.4.1 '@malept/cross-spawn-promise': 1.1.1 - debug: 4.4.1 + debug: 4.4.3 dir-compare: 3.3.0 fs-extra: 9.1.0 minimatch: 3.1.2 @@ -5882,7 +6429,7 @@ snapshots: dependencies: '@electron/asar': 3.4.1 '@malept/cross-spawn-promise': 2.0.0 - debug: 4.4.1 + debug: 4.4.3 dir-compare: 4.2.0 fs-extra: 11.3.0 minimatch: 9.0.5 @@ -5893,7 +6440,7 @@ snapshots: '@electron/windows-sign@1.2.2': dependencies: cross-dirname: 0.1.0 - debug: 4.4.1 + debug: 4.4.3 fs-extra: 11.3.0 minimist: 1.2.8 postject: 1.0.0-alpha.6 @@ -5917,78 +6464,147 @@ snapshots: tslib: 2.8.1 optional: true + '@esbuild/aix-ppc64@0.21.5': + optional: true + '@esbuild/aix-ppc64@0.25.5': optional: true + '@esbuild/android-arm64@0.21.5': + optional: true + '@esbuild/android-arm64@0.25.5': optional: true + '@esbuild/android-arm@0.21.5': + optional: true + '@esbuild/android-arm@0.25.5': optional: true + '@esbuild/android-x64@0.21.5': + optional: true + '@esbuild/android-x64@0.25.5': optional: true + '@esbuild/darwin-arm64@0.21.5': + optional: true + '@esbuild/darwin-arm64@0.25.5': optional: true + '@esbuild/darwin-x64@0.21.5': + optional: true + '@esbuild/darwin-x64@0.25.5': optional: true + '@esbuild/freebsd-arm64@0.21.5': + optional: true + '@esbuild/freebsd-arm64@0.25.5': optional: true + '@esbuild/freebsd-x64@0.21.5': + optional: true + '@esbuild/freebsd-x64@0.25.5': optional: true + '@esbuild/linux-arm64@0.21.5': + optional: true + '@esbuild/linux-arm64@0.25.5': optional: true + '@esbuild/linux-arm@0.21.5': + optional: true + '@esbuild/linux-arm@0.25.5': optional: true + '@esbuild/linux-ia32@0.21.5': + optional: true + '@esbuild/linux-ia32@0.25.5': optional: true + '@esbuild/linux-loong64@0.21.5': + optional: true + '@esbuild/linux-loong64@0.25.5': optional: true + '@esbuild/linux-mips64el@0.21.5': + optional: true + '@esbuild/linux-mips64el@0.25.5': optional: true + '@esbuild/linux-ppc64@0.21.5': + optional: true + '@esbuild/linux-ppc64@0.25.5': optional: true + '@esbuild/linux-riscv64@0.21.5': + optional: true + '@esbuild/linux-riscv64@0.25.5': optional: true + '@esbuild/linux-s390x@0.21.5': + optional: true + '@esbuild/linux-s390x@0.25.5': optional: true + '@esbuild/linux-x64@0.21.5': + optional: true + '@esbuild/linux-x64@0.25.5': optional: true '@esbuild/netbsd-arm64@0.25.5': optional: true + '@esbuild/netbsd-x64@0.21.5': + optional: true + '@esbuild/netbsd-x64@0.25.5': optional: true '@esbuild/openbsd-arm64@0.25.5': optional: true + '@esbuild/openbsd-x64@0.21.5': + optional: true + '@esbuild/openbsd-x64@0.25.5': optional: true + '@esbuild/sunos-x64@0.21.5': + optional: true + '@esbuild/sunos-x64@0.25.5': optional: true + '@esbuild/win32-arm64@0.21.5': + optional: true + '@esbuild/win32-arm64@0.25.5': optional: true + '@esbuild/win32-ia32@0.21.5': + optional: true + '@esbuild/win32-ia32@0.25.5': optional: true + '@esbuild/win32-x64@0.21.5': + optional: true + '@esbuild/win32-x64@0.25.5': optional: true @@ -6093,7 +6709,7 @@ snapshots: '@malept/flatpak-bundler@0.4.0': dependencies: - debug: 4.4.1 + debug: 4.4.3 fs-extra: 9.1.0 lodash: 4.17.21 tmp-promise: 3.0.3 @@ -6319,14 +6935,14 @@ snapshots: postcss-selector-parser: 7.1.1 ts-pattern: 5.9.0 - '@pandacss/dev@1.8.1(hono@4.11.7)(typescript@5.9.2)': + '@pandacss/dev@1.8.1(hono@4.11.7)(jsdom@25.0.1)(typescript@5.9.2)': dependencies: '@clack/prompts': 0.11.0 '@pandacss/config': 1.8.1 '@pandacss/logger': 1.8.1 - '@pandacss/mcp': 1.8.1(hono@4.11.7)(typescript@5.9.2) - '@pandacss/node': 1.8.1(typescript@5.9.2) - '@pandacss/postcss': 1.8.1(typescript@5.9.2) + '@pandacss/mcp': 1.8.1(hono@4.11.7)(jsdom@25.0.1)(typescript@5.9.2) + '@pandacss/node': 1.8.1(jsdom@25.0.1)(typescript@5.9.2) + '@pandacss/postcss': 1.8.1(jsdom@25.0.1)(typescript@5.9.2) '@pandacss/preset-base': 1.8.1 '@pandacss/preset-panda': 1.8.1 '@pandacss/shared': 1.8.1 @@ -6340,10 +6956,10 @@ snapshots: - supports-color - typescript - '@pandacss/extractor@1.8.1(typescript@5.9.2)': + '@pandacss/extractor@1.8.1(jsdom@25.0.1)(typescript@5.9.2)': dependencies: '@pandacss/shared': 1.8.1 - ts-evaluator: 1.2.0(typescript@5.9.2) + ts-evaluator: 1.2.0(jsdom@25.0.1)(typescript@5.9.2) ts-morph: 27.0.2 transitivePeerDependencies: - jsdom @@ -6370,12 +6986,12 @@ snapshots: '@pandacss/types': 1.8.1 kleur: 4.1.5 - '@pandacss/mcp@1.8.1(hono@4.11.7)(typescript@5.9.2)': + '@pandacss/mcp@1.8.1(hono@4.11.7)(jsdom@25.0.1)(typescript@5.9.2)': dependencies: '@clack/prompts': 0.11.0 '@modelcontextprotocol/sdk': 1.25.3(hono@4.11.7)(zod@4.0.14) '@pandacss/logger': 1.8.1 - '@pandacss/node': 1.8.1(typescript@5.9.2) + '@pandacss/node': 1.8.1(jsdom@25.0.1)(typescript@5.9.2) '@pandacss/token-dictionary': 1.8.1 '@pandacss/types': 1.8.1 zod: 4.0.14 @@ -6386,13 +7002,13 @@ snapshots: - supports-color - typescript - '@pandacss/node@1.8.1(typescript@5.9.2)': + '@pandacss/node@1.8.1(jsdom@25.0.1)(typescript@5.9.2)': dependencies: '@pandacss/config': 1.8.1 '@pandacss/core': 1.8.1 '@pandacss/generator': 1.8.1 '@pandacss/logger': 1.8.1 - '@pandacss/parser': 1.8.1(typescript@5.9.2) + '@pandacss/parser': 1.8.1(jsdom@25.0.1)(typescript@5.9.2) '@pandacss/reporter': 1.8.1 '@pandacss/shared': 1.8.1 '@pandacss/token-dictionary': 1.8.1 @@ -6421,11 +7037,11 @@ snapshots: - jsdom - typescript - '@pandacss/parser@1.8.1(typescript@5.9.2)': + '@pandacss/parser@1.8.1(jsdom@25.0.1)(typescript@5.9.2)': dependencies: '@pandacss/config': 1.8.1 '@pandacss/core': 1.8.1 - '@pandacss/extractor': 1.8.1(typescript@5.9.2) + '@pandacss/extractor': 1.8.1(jsdom@25.0.1)(typescript@5.9.2) '@pandacss/logger': 1.8.1 '@pandacss/shared': 1.8.1 '@pandacss/types': 1.8.1 @@ -6437,9 +7053,9 @@ snapshots: - jsdom - typescript - '@pandacss/postcss@1.8.1(typescript@5.9.2)': + '@pandacss/postcss@1.8.1(jsdom@25.0.1)(typescript@5.9.2)': dependencies: - '@pandacss/node': 1.8.1(typescript@5.9.2) + '@pandacss/node': 1.8.1(jsdom@25.0.1)(typescript@5.9.2) postcss: 8.5.6 transitivePeerDependencies: - jsdom @@ -7091,6 +7707,36 @@ snapshots: '@tanstack/virtual-file-routes@1.139.0': {} + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/runtime': 7.28.6 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + '@testing-library/jest-dom@6.9.1': + dependencies: + '@adobe/css-tools': 4.5.0 + aria-query: 5.3.2 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + picocolors: 1.1.1 + redent: 3.0.0 + + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@testing-library/dom': 10.4.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@tootallnate/once@2.0.0': {} '@ts-morph/common@0.28.1': @@ -7104,6 +7750,8 @@ snapshots: tslib: 2.8.1 optional: true + '@types/aria-query@5.0.4': {} + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.27.4 @@ -7202,6 +7850,46 @@ snapshots: transitivePeerDependencies: - supports-color + '@vitest/expect@2.1.9': + dependencies: + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.3.3 + tinyrainbow: 1.2.0 + + '@vitest/mocker@2.1.9(vite@5.4.21(@types/node@20.19.1)(lightningcss@1.30.2))': + dependencies: + '@vitest/spy': 2.1.9 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 5.4.21(@types/node@20.19.1)(lightningcss@1.30.2) + + '@vitest/pretty-format@2.1.9': + dependencies: + tinyrainbow: 1.2.0 + + '@vitest/runner@2.1.9': + dependencies: + '@vitest/utils': 2.1.9 + pathe: 1.1.2 + + '@vitest/snapshot@2.1.9': + dependencies: + '@vitest/pretty-format': 2.1.9 + magic-string: 0.30.21 + pathe: 1.1.2 + + '@vitest/spy@2.1.9': + dependencies: + tinyspy: 3.0.2 + + '@vitest/utils@2.1.9': + dependencies: + '@vitest/pretty-format': 2.1.9 + loupe: 3.2.1 + tinyrainbow: 1.2.0 + '@vue/compiler-core@3.5.25': dependencies: '@babel/parser': 7.28.5 @@ -7298,6 +7986,8 @@ snapshots: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi-styles@6.2.1: {} ansis@4.2.0: {} @@ -7392,9 +8082,17 @@ snapshots: dependencies: tslib: 2.8.1 + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + + aria-query@5.3.2: {} + assert-plus@1.0.0: optional: true + assertion-error@2.0.1: {} + ast-types@0.16.1: dependencies: tslib: 2.8.1 @@ -7617,6 +8315,14 @@ snapshots: caniuse-lite@1.0.30001766: {} + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.3 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + chainsaw@0.1.0: dependencies: traverse: 0.3.9 @@ -7626,6 +8332,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + check-error@2.1.3: {} + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -7802,17 +8510,29 @@ snapshots: dependencies: '@types/node': 17.0.45 + css.escape@1.5.1: {} + cssesc@3.0.0: {} cssnano-utils@5.0.1(postcss@8.5.6): dependencies: postcss: 8.5.6 + cssstyle@4.6.0: + dependencies: + '@asamuzakjp/css-color': 3.2.0 + rrweb-cssom: 0.8.0 + csstype@3.2.3: {} + data-urls@5.0.0: + dependencies: + whatwg-mimetype: 4.0.0 + whatwg-url: 14.2.0 + date-fns@2.30.0: dependencies: - '@babel/runtime': 7.27.1 + '@babel/runtime': 7.28.6 dayjs@1.11.13: {} @@ -7834,12 +8554,16 @@ snapshots: dependencies: ms: 2.1.3 + decimal.js@10.6.0: {} + decode-formdata@0.9.0: {} decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 + deep-eql@5.0.2: {} + deep-extend@0.6.0: {} defaults@1.0.4: @@ -7866,6 +8590,8 @@ snapshots: depd@2.0.0: {} + dequal@2.0.3: {} + detect-libc@2.0.4: {} detect-node-es@1.1.0: {} @@ -7914,6 +8640,10 @@ snapshots: verror: 1.10.1 optional: true + dom-accessibility-api@0.5.16: {} + + dom-accessibility-api@0.6.3: {} + dotenv-expand@11.0.7: dependencies: dotenv: 16.5.0 @@ -8066,7 +8796,7 @@ snapshots: builder-util: 26.0.11 builder-util-runtime: 9.3.1 chalk: 4.1.2 - form-data: 4.0.2 + form-data: 4.0.5 fs-extra: 10.1.0 lazy-val: 1.0.5 mime: 2.6.0 @@ -8134,6 +8864,8 @@ snapshots: entities@4.5.0: {} + entities@6.0.1: {} + env-paths@2.2.1: {} err-code@2.0.3: {} @@ -8146,6 +8878,8 @@ snapshots: es-errors@1.3.0: {} + es-module-lexer@1.7.0: {} + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -8160,6 +8894,32 @@ snapshots: es6-error@4.1.1: optional: true + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + esbuild@0.25.5: optionalDependencies: '@esbuild/aix-ppc64': 0.25.5 @@ -8201,6 +8961,10 @@ snapshots: estree-walker@2.0.2: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + etag@1.8.1: {} eventsource-parser@3.0.6: {} @@ -8235,6 +8999,8 @@ snapshots: dependencies: homedir-polyfill: 1.0.3 + expect-type@1.3.0: {} + exponential-backoff@3.1.3: {} express-rate-limit@7.5.1(express@5.2.1): @@ -8249,7 +9015,7 @@ snapshots: content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 - debug: 4.4.1 + debug: 4.4.3 depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 @@ -8350,7 +9116,7 @@ snapshots: finalhandler@2.1.1: dependencies: - debug: 4.4.1 + debug: 4.4.3 encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -8375,7 +9141,7 @@ snapshots: flora-colossus@2.0.0: dependencies: - debug: 4.4.1 + debug: 4.4.3 fs-extra: 10.1.0 transitivePeerDependencies: - supports-color @@ -8387,13 +9153,6 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - form-data@4.0.2: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - mime-types: 2.1.35 - form-data@4.0.5: dependencies: asynckit: 0.4.0 @@ -8469,7 +9228,7 @@ snapshots: galactus@1.0.0: dependencies: - debug: 4.4.1 + debug: 4.4.3 flora-colossus: 2.0.0 fs-extra: 10.1.0 transitivePeerDependencies: @@ -8668,6 +9427,10 @@ snapshots: dependencies: lru-cache: 6.0.0 + html-encoding-sniffer@4.0.0: + dependencies: + whatwg-encoding: 3.1.1 + html-parse-stringify@3.0.1: dependencies: void-elements: 3.1.0 @@ -8693,7 +9456,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.3 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -8712,7 +9475,7 @@ snapshots: https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.3 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -8801,6 +9564,8 @@ snapshots: is-number@7.0.0: {} + is-potential-custom-element-name@1.0.1: {} + is-promise@4.0.0: {} is-stream@1.1.0: {} @@ -8856,6 +9621,34 @@ snapshots: dependencies: argparse: 2.0.1 + jsdom@25.0.1: + dependencies: + cssstyle: 4.6.0 + data-urls: 5.0.0 + decimal.js: 10.6.0 + form-data: 4.0.5 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.23 + parse5: 7.3.0 + rrweb-cssom: 0.7.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 5.1.2 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.2.0 + ws: 8.21.0 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -9111,6 +9904,8 @@ snapshots: look-it-up@2.1.0: {} + loupe@3.2.1: {} + lowercase-keys@2.0.0: {} lru-cache@10.4.3: {} @@ -9125,6 +9920,8 @@ snapshots: lru-cache@7.18.3: {} + lz-string@1.5.0: {} + magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -9234,6 +10031,8 @@ snapshots: mimic-response@3.1.0: {} + min-indent@1.0.1: {} + minimatch@10.0.1: dependencies: brace-expansion: 2.0.1 @@ -9368,6 +10167,8 @@ snapshots: dependencies: path-key: 2.0.1 + nwsapi@2.2.23: {} + object-assign@4.1.1: {} object-inspect@1.13.4: {} @@ -9514,6 +10315,10 @@ snapshots: parse-passwd@1.0.0: {} + parse5@7.3.0: + dependencies: + entities: 6.0.1 + parseurl@1.3.3: {} path-browserify@1.0.1: {} @@ -9541,8 +10346,12 @@ snapshots: dependencies: pify: 2.3.0 + pathe@1.1.2: {} + pathe@2.0.3: {} + pathval@2.0.1: {} + pe-library@0.4.1: {} pend@1.2.0: {} @@ -9647,6 +10456,12 @@ snapshots: prettier@3.7.3: {} + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + proc-log@2.0.1: {} process-nextick-args@2.0.1: {} @@ -9720,6 +10535,8 @@ snapshots: react-dom: 19.2.4(react@19.2.4) typescript: 5.9.2 + react-is@17.0.2: {} + react-refresh@0.17.0: {} react-remove-scroll-bar@2.3.8(@types/react@19.2.13)(react@19.2.4): @@ -9753,7 +10570,7 @@ snapshots: read-binary-file-arch@1.0.6: dependencies: - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -9806,6 +10623,11 @@ snapshots: dependencies: resolve: 1.22.10 + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + regex-escape@3.4.11: {} require-directory@2.1.1: {} @@ -9928,7 +10750,7 @@ snapshots: router@2.2.0: dependencies: - debug: 4.4.1 + debug: 4.4.3 depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 @@ -9936,6 +10758,10 @@ snapshots: transitivePeerDependencies: - supports-color + rrweb-cssom@0.7.1: {} + + rrweb-cssom@0.8.0: {} + run-con@1.2.12: dependencies: deep-extend: 0.6.0 @@ -9967,6 +10793,10 @@ snapshots: dependencies: xmlchars: 2.2.0 + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + scheduler@0.27.0: {} semver-compare@1.0.0: @@ -10068,6 +10898,8 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 + siginfo@2.0.0: {} + signal-exit@3.0.7: {} signal-exit@4.1.0: {} @@ -10151,10 +10983,14 @@ snapshots: dependencies: minipass: 3.3.6 + stackback@0.0.2: {} + stat-mode@1.0.0: {} statuses@2.0.2: {} + std-env@3.10.0: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -10187,6 +11023,10 @@ snapshots: strip-eof@1.0.0: {} + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + strip-json-comments@3.1.1: {} strip-json-comments@5.0.3: {} @@ -10217,6 +11057,8 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + symbol-tree@3.2.4: {} + table@6.9.0: dependencies: ajv: 8.17.1 @@ -10265,6 +11107,10 @@ snapshots: tiny-warning@1.0.3: {} + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + tinyglobby@0.2.14: dependencies: fdir: 6.4.5(picomatch@4.0.2) @@ -10280,6 +11126,18 @@ snapshots: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 + tinypool@1.1.1: {} + + tinyrainbow@1.2.0: {} + + tinyspy@3.0.2: {} + + tldts-core@6.1.86: {} + + tldts@6.1.86: + dependencies: + tldts-core: 6.1.86 + tmp-promise@3.0.3: dependencies: tmp: 0.2.3 @@ -10294,8 +11152,16 @@ snapshots: touch@3.1.1: {} + tough-cookie@5.1.2: + dependencies: + tldts: 6.1.86 + tr46@0.0.3: {} + tr46@5.1.1: + dependencies: + punycode: 2.3.1 + traverse@0.3.9: {} tree-kill@1.2.2: {} @@ -10308,12 +11174,14 @@ snapshots: dependencies: utf8-byte-length: 1.0.5 - ts-evaluator@1.2.0(typescript@5.9.2): + ts-evaluator@1.2.0(jsdom@25.0.1)(typescript@5.9.2): dependencies: ansi-colors: 4.1.3 crosspath: 2.0.0 object-path: 0.11.8 typescript: 5.9.2 + optionalDependencies: + jsdom: 25.0.1 ts-morph@27.0.2: dependencies: @@ -10462,6 +11330,34 @@ snapshots: extsprintf: 1.4.1 optional: true + vite-node@2.1.9(@types/node@20.19.1)(lightningcss@1.30.2): + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 1.1.2 + vite: 5.4.21(@types/node@20.19.1)(lightningcss@1.30.2) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite@5.4.21(@types/node@20.19.1)(lightningcss@1.30.2): + dependencies: + esbuild: 0.21.5 + postcss: 8.5.6 + rollup: 4.53.3 + optionalDependencies: + '@types/node': 20.19.1 + fsevents: 2.3.3 + lightningcss: 1.30.2 + vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3): dependencies: esbuild: 0.25.5 @@ -10494,8 +11390,48 @@ snapshots: tsx: 4.20.6 yaml: 2.8.3 + vitest@2.1.9(@types/node@20.19.1)(jsdom@25.0.1)(lightningcss@1.30.2): + dependencies: + '@vitest/expect': 2.1.9 + '@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@20.19.1)(lightningcss@1.30.2)) + '@vitest/pretty-format': 2.1.9 + '@vitest/runner': 2.1.9 + '@vitest/snapshot': 2.1.9 + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.3.0 + magic-string: 0.30.21 + pathe: 1.1.2 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.1.1 + tinyrainbow: 1.2.0 + vite: 5.4.21(@types/node@20.19.1)(lightningcss@1.30.2) + vite-node: 2.1.9(@types/node@20.19.1)(lightningcss@1.30.2) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 20.19.1 + jsdom: 25.0.1 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + void-elements@3.1.0: {} + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + wait-on@6.0.1: dependencies: axios: 0.25.0 @@ -10514,8 +11450,21 @@ snapshots: webidl-conversions@3.0.1: {} + webidl-conversions@7.0.0: {} + webpack-virtual-modules@0.6.2: {} + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + + whatwg-url@14.2.0: + dependencies: + tr46: 5.1.1 + webidl-conversions: 7.0.0 + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -10529,6 +11478,11 @@ snapshots: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + word-wrap@1.2.5: optional: true @@ -10554,6 +11508,10 @@ snapshots: wrappy@1.0.2: {} + ws@8.21.0: {} + + xml-name-validator@5.0.0: {} + xmlbuilder@15.1.1: {} xmlchars@2.2.0: {} diff --git a/src/renderer/src/test/setup.ts b/src/renderer/src/test/setup.ts new file mode 100644 index 00000000..f149f27a --- /dev/null +++ b/src/renderer/src/test/setup.ts @@ -0,0 +1 @@ +import "@testing-library/jest-dom/vitest"; diff --git a/src/renderer/src/test/smoke.test.ts b/src/renderer/src/test/smoke.test.ts new file mode 100644 index 00000000..5cca2aaa --- /dev/null +++ b/src/renderer/src/test/smoke.test.ts @@ -0,0 +1,7 @@ +import { describe, expect, it } from "vitest"; + +describe("vitest", () => { + it("runs", () => { + expect(1 + 1).toBe(2); + }); +}); diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 00000000..48d25c7d --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,17 @@ +import { resolve } from "node:path"; +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + resolve: { + alias: { + "@": resolve(__dirname, "src/renderer/src"), + "@/styled": resolve(__dirname, "src/renderer/src/styled"), + }, + }, + test: { + environment: "jsdom", + globals: true, + setupFiles: ["src/renderer/src/test/setup.ts"], + include: ["src/renderer/src/**/*.{test,spec}.{ts,tsx}"], + }, +}); From 220b64610cf7bf88550d1b796e8b0c55208c47fe Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 5 Jun 2026 09:49:56 -0300 Subject: [PATCH 191/263] chore(knip): keep @testing-library/react for renderer tests Co-Authored-By: Claude Sonnet 4.6 --- knip.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/knip.json b/knip.json index 4af1b1ec..083556b6 100644 --- a/knip.json +++ b/knip.json @@ -50,6 +50,7 @@ "nodemon", "prettier", "wait-on", - "postcss" + "postcss", + "@testing-library/react" ] } From 302cd60369bfeabc22efdb9a0414a10fb23c861b Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 5 Jun 2026 09:51:48 -0300 Subject: [PATCH 192/263] i18n(voice-to-text): add redesigned copy keys Co-Authored-By: Claude Sonnet 4.6 --- .../i18n/locales/es/voice-to-text.ts | 78 +++++++++++++------ 1 file changed, 55 insertions(+), 23 deletions(-) diff --git a/src/renderer/src/constants/i18n/locales/es/voice-to-text.ts b/src/renderer/src/constants/i18n/locales/es/voice-to-text.ts index 0e9ec48a..ecbaf772 100644 --- a/src/renderer/src/constants/i18n/locales/es/voice-to-text.ts +++ b/src/renderer/src/constants/i18n/locales/es/voice-to-text.ts @@ -1,41 +1,68 @@ const voiceToText = { title: "Voz a Texto", subtitle: "Transcribí audios a documentos de texto editables", - onboarding: { - sectionTitle: "1. Selección de Archivos de Audio", - validFormats: "Formatos válidos: .mp3, .wav, .m4a, .webm", - loadDocuments: "Cargar audio", - dropAreaTitle: "Selecciona los archivos de audio para transcribir", - dropAreaFormats: "Formatos válidos: .mp3, .wav, .m4a, .webm, .ogg, .flac", - description: "Cómo funciona la Transcripción de voz a texto", - steps: { - step1: "Subí uno o más archivos de audio (.mp3, .wav, .m4a, .webm)", - step2: - "El sistema analiza el audio e identifica quién habla en cada momento", - step3: - "Revisá la transcripción, editá el texto y renombrá a los locutores", - step4: "Descargá la transcripción en formato de texto", + stepper: { + step1: "Selección", + step2: "Transcripción", + step3: "Edición", + step4: "Descarga", + }, + howItWorks: { + pageTitle: "¿Cómo funciona?", + modalTitle: "¿Cómo funciona de Voz a Texto?", + gotIt: "Entendido", + helpAria: "Cómo funciona la transcripción de voz a texto", + cards: { + card1: { + title: "Subí el archivo de audio", + subtitle: "Cargá un archivo en formato .mp3, .wav, .m4a o .webm.", + }, + card2: { + title: "La inteligencia artificial analiza el audio", + subtitle: "Extrae la información relevante de cada documento.", + }, + card3: { + title: "Revisión y validación humana", + subtitle: + "Revisá la transcripción, editá el texto y renombrá a los locutores antes de exportar el archivo.", + }, + card4: { + title: "Descargá la transcripción", + subtitle: "El archivo queda listo para exportar en formato de texto.", + }, }, }, + onboarding: { + sectionTitle: "1. Selección de archivo", + loadDocuments: "Cargar archivo", + dropAreaTitle: + "Selecciona el archivo que desea transcribir o arrástralo y suéltalo", + dropAreaFormats: "Formatos válidos: .mp3, .wav, .m4a o .webm", + }, preview: { - sectionTitle: "1. Archivos de audio", - filesLabel: "Archivos seleccionados", - validFormats: "Formatos válidos: .mp3, .wav, .m4a, .webm", + sectionTitle: "1. Selección de archivo", + selectedCount_one: "{{count}} archivo seleccionado", + selectedCount_other: "{{count}} archivos seleccionados", loadMore: "Cargar más audios", continue: "Siguiente", removeAria: "Eliminar {{name}}", + playAria: "Reproducir 10 segundos de {{name}}", + pauseAria: "Pausar {{name}}", + meta: "{{duration}} - {{size}}", }, process: { - sectionTitle: "2. Transcripción de audio", - processingTitle: "AymurAI está transcribiendo los archivos de audio", + sectionTitle: "2. Transcripción de voz a texto", + processingTitle: "AymurAI está transcribiendo el archivo.", processingSubtitle: "Este proceso puede tardar algunos minutos.", - finishText: "Transcripción completada", progressLabel: "{{percent}}%", - completedLabel: "Transcripción completada 100%", - errorLabel: "Error en la transcripción", - nFiles: "{{count}} archivos", + completedLabel: "Carga finalizada 100%", + errorLabel: "Error en la transcripción del archivo. Volvelo a intentar", + stop: "Detener", + replace: "Reemplazar", waitingForWords: "Esperando las primeras palabras…", previewAriaLabel: "Vista previa de la transcripción", + callout: + "Transcribiendo audio. Puede demorar unos segundos. Aparecerá aquí cuando esté listo.", back: "Volver", next: "Siguiente", }, @@ -62,12 +89,17 @@ const voiceToText = { searchPlaceholder: "Buscar", searchAria: "Buscar en la transcripción", editMode: "Modo Edición", + editModeBanner: + "Modo edición activo. Seleccioná el texto para modificarlo.", + editTitleAria: "Editar título de la transcripción", + titleInputAria: "Título de la transcripción", prevResult: "Resultado anterior", nextResult: "Resultado siguiente", addTurn: "+ Agregar turno", addTurnAria: "Agregar turno", removeTurnAria: "Eliminar turno", turnTextAria: "Texto del turno", + finish: "Finalizar", rewind5s: "Retroceder 5 segundos", forward5s: "Adelantar 5 segundos", play: "Reproducir", From 1e56007dfa2f9ca6eb18d1d48b1252baff6173c6 Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 5 Jun 2026 09:54:04 -0300 Subject: [PATCH 193/263] feat(voice-to-text): add renameTranscription reducer action Implements RENAME_TRANSCRIPTION action type, creator, and reducer case following existing patterns; covered by 2 Vitest tests (TDD). Co-Authored-By: Claude Sonnet 4.6 --- .../src/reducers/transcription/actions.ts | 20 ++++++++++ .../src/reducers/transcription/index.test.ts | 38 +++++++++++++++++++ .../src/reducers/transcription/index.ts | 13 +++++++ 3 files changed, 71 insertions(+) create mode 100644 src/renderer/src/reducers/transcription/index.test.ts diff --git a/src/renderer/src/reducers/transcription/actions.ts b/src/renderer/src/reducers/transcription/actions.ts index 0e507ea6..b68bb169 100644 --- a/src/renderer/src/reducers/transcription/actions.ts +++ b/src/renderer/src/reducers/transcription/actions.ts @@ -11,6 +11,7 @@ import type { export enum ActionTypes { ADD_TRANSCRIPTION = "ADD_TRANSCRIPTION", REMOVE_TRANSCRIPTION = "REMOVE_TRANSCRIPTION", + RENAME_TRANSCRIPTION = "RENAME_TRANSCRIPTION", RENAME_SPEAKER_GLOBAL = "RENAME_SPEAKER_GLOBAL", REASSIGN_TURN_SPEAKER = "REASSIGN_TURN_SPEAKER", UPDATE_TURN_TEXT = "UPDATE_TURN_TEXT", @@ -202,6 +203,25 @@ export function addSpeaker( }; } +export type RenameTranscriptionAction = Action< + ActionTypes.RENAME_TRANSCRIPTION, + { transcriptionId: string; title: string } +>; +/** + * Renames a transcription's title + * @param transcriptionId ID of the transcription to rename + * @param title New title + */ +export function renameTranscription( + transcriptionId: string, + title: string, +): RenameTranscriptionAction { + return { + type: ActionTypes.RENAME_TRANSCRIPTION, + payload: { transcriptionId, title }, + }; +} + export type AssignSuggestedSpeakerToTurnAction = Action< ActionTypes.ASSIGN_SUGGESTED_SPEAKER_TO_TURN, { transcriptionId: string; turnId: string; suggested: SuggestedSpeaker } diff --git a/src/renderer/src/reducers/transcription/index.test.ts b/src/renderer/src/reducers/transcription/index.test.ts new file mode 100644 index 00000000..d4ea1c09 --- /dev/null +++ b/src/renderer/src/reducers/transcription/index.test.ts @@ -0,0 +1,38 @@ +import type { Transcription } from "@/types/transcription"; +import { describe, expect, it } from "vitest"; +import { renameTranscription } from "./actions"; +import reducer from "./index"; + +function makeTranscription( + overrides: Partial = {}, +): Transcription { + return { + id: "t1", + title: "Audiencia 10/04/2025", + audioFileName: "a.mp3", + audioDurationMs: 1000, + audioObjectUrl: "blob:x", + speakers: [], + turns: [], + createdAt: "2026-06-04T00:00:00.000Z", + ...overrides, + }; +} + +describe("renameTranscription", () => { + it("renames the matching transcription's title", () => { + const state = [makeTranscription()]; + const next = reducer(state, renameTranscription("t1", "Nuevo título")); + expect(next[0].title).toBe("Nuevo título"); + }); + + it("leaves other transcriptions untouched and does not mutate input", () => { + const state = [ + makeTranscription(), + makeTranscription({ id: "t2", title: "Otro" }), + ]; + const next = reducer(state, renameTranscription("t1", "Cambiado")); + expect(next[1].title).toBe("Otro"); + expect(state[0].title).toBe("Audiencia 10/04/2025"); + }); +}); diff --git a/src/renderer/src/reducers/transcription/index.ts b/src/renderer/src/reducers/transcription/index.ts index 1bb2c4b1..4d621464 100644 --- a/src/renderer/src/reducers/transcription/index.ts +++ b/src/renderer/src/reducers/transcription/index.ts @@ -10,6 +10,7 @@ import { type RemoveTranscriptionAction, type RemoveTurnAction, type RenameSpeakerGlobalAction, + type RenameTranscriptionAction, type UpdateTurnStartMsAction, type UpdateTurnTextAction, } from "./actions"; @@ -19,6 +20,7 @@ type State = Transcription[]; export type TranscriptionAction = | AddTranscriptionAction | RemoveTranscriptionAction + | RenameTranscriptionAction | RenameSpeakerGlobalAction | ReassignTurnSpeakerAction | UpdateTurnTextAction @@ -89,6 +91,17 @@ export default function reducer( return state.filter((t) => t.id !== id); } + // ---------------- + // RENAME TRANSCRIPTION + // ---------------- + case ActionTypes.RENAME_TRANSCRIPTION: { + const { transcriptionId, title } = payload; + return updateTranscription(state, transcriptionId, (t) => ({ + ...t, + title, + })); + } + // ---------------- // RENAME SPEAKER GLOBAL // ---------------- From 7c231c93e7bbb9947825c6862ea74c7e8f973489 Mon Sep 17 00:00:00 2001 From: Lionel Chamorro Date: Fri, 5 Jun 2026 09:56:26 -0300 Subject: [PATCH 194/263] feat(voice-to-text): add audio snippet hook + duration formatter Co-Authored-By: Claude Opus 4.8 (1M context) --- .../voice-to-text/format-duration.test.ts | 17 ++++ .../voice-to-text/use-audio-snippet.ts | 78 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 src/renderer/src/components/voice-to-text/format-duration.test.ts create mode 100644 src/renderer/src/components/voice-to-text/use-audio-snippet.ts diff --git a/src/renderer/src/components/voice-to-text/format-duration.test.ts b/src/renderer/src/components/voice-to-text/format-duration.test.ts new file mode 100644 index 00000000..7bdf7c0d --- /dev/null +++ b/src/renderer/src/components/voice-to-text/format-duration.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, it } from "vitest"; +import { formatDuration } from "./use-audio-snippet"; + +describe("formatDuration", () => { + it("formats minutes and seconds", () => { + expect(formatDuration(46 * 60_000 + 34_000)).toBe("46 min. 34 seg."); + }); + + it("formats sub-minute durations as seconds only", () => { + expect(formatDuration(9_000)).toBe("9 seg."); + }); + + it("treats 0 / NaN as 0 seconds", () => { + expect(formatDuration(0)).toBe("0 seg."); + expect(formatDuration(Number.NaN)).toBe("0 seg."); + }); +}); diff --git a/src/renderer/src/components/voice-to-text/use-audio-snippet.ts b/src/renderer/src/components/voice-to-text/use-audio-snippet.ts new file mode 100644 index 00000000..ae4d6296 --- /dev/null +++ b/src/renderer/src/components/voice-to-text/use-audio-snippet.ts @@ -0,0 +1,78 @@ +import { useCallback, useEffect, useRef, useState } from "react"; + +/** Human-readable duration: "46 min. 34 seg." or "9 seg." */ +export function formatDuration(ms: number): string { + if (!Number.isFinite(ms) || ms <= 0) return "0 seg."; + const totalSeconds = Math.round(ms / 1000); + const minutes = Math.floor(totalSeconds / 60); + const seconds = totalSeconds % 60; + if (minutes === 0) return `${seconds} seg.`; + return `${minutes} min. ${seconds} seg.`; +} + +const SNIPPET_MS = 10_000; + +interface UseAudioSnippet { + durationMs: number; + isPlaying: boolean; + /** Play a 10s snippet from the current position; toggles to pause if playing. */ + toggle: () => void; +} + +/** + * Owns an off-DOM