From e1e7e1b1e5f6552db58dad078329220e8b7b81db Mon Sep 17 00:00:00 2001 From: James nguyen Date: Mon, 19 Jan 2026 19:14:51 +0700 Subject: [PATCH 1/4] Assignment submit --- readme.md | 34 + src/problem1/.keep | 0 src/problem1/index.ts | 33 + src/problem2/.gitignore | 24 + src/problem2/README.md | 167 + src/problem2/eslint.config.js | 23 + src/problem2/index.html | 38 +- src/problem2/package-lock.json | 3898 +++++++++++++++++ src/problem2/package.json | 42 + src/problem2/public/not-found-icon-10.jpg | Bin 0 -> 17482 bytes src/problem2/public/vite.svg | 1 + src/problem2/script.js | 0 src/problem2/src/App.css | 16 + src/problem2/src/App.tsx | 68 + src/problem2/src/api/client.ts | 59 + src/problem2/src/api/hooks/index.ts | 2 + src/problem2/src/api/hooks/prices.hooks.ts | 16 + src/problem2/src/api/hooks/wallet.hooks.ts | 41 + src/problem2/src/api/index.ts | 4 + src/problem2/src/api/provider.tsx | 17 + src/problem2/src/api/services/index.ts | 2 + .../src/api/services/prices.services.ts | 16 + .../src/api/services/wallet.services.ts | 62 + src/problem2/src/atom/error.tsx | 24 + src/problem2/src/atom/form/autocomplete.tsx | 48 + src/problem2/src/atom/form/index.ts | 2 + src/problem2/src/atom/form/text-field.tsx | 21 + src/problem2/src/atom/index.ts | 3 + src/problem2/src/atom/token.tsx | 60 + src/problem2/src/common/configs.ts | 15 + src/problem2/src/common/constants.ts | 35 + src/problem2/src/common/helper.ts | 24 + src/problem2/src/common/index.ts | 3 + src/problem2/src/components/app-header.tsx | 44 + .../exchange-token/exchange-form.tsx | 187 + .../exchange-token/exchange-modal.tsx | 136 + .../src/components/exchange-token/hooks.ts | 230 + .../src/components/exchange-token/index.ts | 1 + src/problem2/src/components/index.ts | 3 + src/problem2/src/components/wallet-card.tsx | 56 + .../exchange-modal/context-definition.ts | 12 + .../src/contexts/exchange-modal/context.tsx | 33 + .../src/contexts/exchange-modal/hook.ts | 13 + .../src/contexts/exchange-modal/index.ts | 3 + src/problem2/src/contexts/index.ts | 2 + .../src/contexts/toast/context-definition.ts | 10 + src/problem2/src/contexts/toast/context.tsx | 54 + src/problem2/src/contexts/toast/hook.ts | 11 + src/problem2/src/contexts/toast/index.ts | 3 + src/problem2/src/main.tsx | 22 + src/problem2/src/theme.ts | 37 + src/problem2/src/types/index.ts | 2 + .../src/types/schemas/exchange-form.schema.ts | 20 + src/problem2/src/types/schemas/index.ts | 1 + src/problem2/src/types/wallet.type.ts | 16 + src/problem2/style.css | 8 - src/problem2/tsconfig.app.json | 44 + src/problem2/tsconfig.json | 7 + src/problem2/tsconfig.node.json | 26 + src/problem2/vite.config.ts | 17 + src/problem3/.keep | 0 src/problem3/messy-file.tsx | 90 + src/problem3/refactor-file.tsx | 110 + src/problem4/.keep | 0 src/problem5/.keep | 0 65 files changed, 5962 insertions(+), 34 deletions(-) delete mode 100644 src/problem1/.keep create mode 100644 src/problem1/index.ts create mode 100644 src/problem2/.gitignore create mode 100644 src/problem2/README.md create mode 100644 src/problem2/eslint.config.js create mode 100644 src/problem2/package-lock.json create mode 100644 src/problem2/package.json create mode 100644 src/problem2/public/not-found-icon-10.jpg create mode 100644 src/problem2/public/vite.svg delete mode 100644 src/problem2/script.js create mode 100644 src/problem2/src/App.css create mode 100644 src/problem2/src/App.tsx create mode 100644 src/problem2/src/api/client.ts create mode 100644 src/problem2/src/api/hooks/index.ts create mode 100644 src/problem2/src/api/hooks/prices.hooks.ts create mode 100644 src/problem2/src/api/hooks/wallet.hooks.ts create mode 100644 src/problem2/src/api/index.ts create mode 100644 src/problem2/src/api/provider.tsx create mode 100644 src/problem2/src/api/services/index.ts create mode 100644 src/problem2/src/api/services/prices.services.ts create mode 100644 src/problem2/src/api/services/wallet.services.ts create mode 100644 src/problem2/src/atom/error.tsx create mode 100644 src/problem2/src/atom/form/autocomplete.tsx create mode 100644 src/problem2/src/atom/form/index.ts create mode 100644 src/problem2/src/atom/form/text-field.tsx create mode 100644 src/problem2/src/atom/index.ts create mode 100644 src/problem2/src/atom/token.tsx create mode 100644 src/problem2/src/common/configs.ts create mode 100644 src/problem2/src/common/constants.ts create mode 100644 src/problem2/src/common/helper.ts create mode 100644 src/problem2/src/common/index.ts create mode 100644 src/problem2/src/components/app-header.tsx create mode 100644 src/problem2/src/components/exchange-token/exchange-form.tsx create mode 100644 src/problem2/src/components/exchange-token/exchange-modal.tsx create mode 100644 src/problem2/src/components/exchange-token/hooks.ts create mode 100644 src/problem2/src/components/exchange-token/index.ts create mode 100644 src/problem2/src/components/index.ts create mode 100644 src/problem2/src/components/wallet-card.tsx create mode 100644 src/problem2/src/contexts/exchange-modal/context-definition.ts create mode 100644 src/problem2/src/contexts/exchange-modal/context.tsx create mode 100644 src/problem2/src/contexts/exchange-modal/hook.ts create mode 100644 src/problem2/src/contexts/exchange-modal/index.ts create mode 100644 src/problem2/src/contexts/index.ts create mode 100644 src/problem2/src/contexts/toast/context-definition.ts create mode 100644 src/problem2/src/contexts/toast/context.tsx create mode 100644 src/problem2/src/contexts/toast/hook.ts create mode 100644 src/problem2/src/contexts/toast/index.ts create mode 100644 src/problem2/src/main.tsx create mode 100644 src/problem2/src/theme.ts create mode 100644 src/problem2/src/types/index.ts create mode 100644 src/problem2/src/types/schemas/exchange-form.schema.ts create mode 100644 src/problem2/src/types/schemas/index.ts create mode 100644 src/problem2/src/types/wallet.type.ts delete mode 100644 src/problem2/style.css create mode 100644 src/problem2/tsconfig.app.json create mode 100644 src/problem2/tsconfig.json create mode 100644 src/problem2/tsconfig.node.json create mode 100644 src/problem2/vite.config.ts delete mode 100644 src/problem3/.keep create mode 100644 src/problem3/messy-file.tsx create mode 100644 src/problem3/refactor-file.tsx delete mode 100644 src/problem4/.keep delete mode 100644 src/problem5/.keep diff --git a/readme.md b/readme.md index 1ff4bc95b..943a69c73 100644 --- a/readme.md +++ b/readme.md @@ -8,3 +8,37 @@ It is important that you minimally attempt the problems, even if you do not arri ## Submission ## You can either provide a link to an online repository, attach the solution in your application, or whichever method you prefer. We're cool as long as we can view your solution without any pain. + +# James Nguyen Submission +Following the code challenge for the **Frontend Developer** position, I completed **Problems 1, 2, and 3** located in the `src` directory. + +## AI Assistance Disclosure + +With the increasing adoption of AI tools in software development and the note from the instruction, I would like to be transparent about how AI assisted me during this challenge. + +### Problem 1 – ~10% AI Assistance +AI was used mainly to generate and refine **code comments**. +I used **GitHub Copilot**, which understood the context well and helped speed up the commenting process. The core logic and implementation were entirely my own. + +### Problem 2 – ~60% AI Assistance +AI played a more significant role in this part, particularly in: +- Suggesting the **basic project structure** +- Generating a **simple responsive layout using MUI** +- Recommending common **API paths, queries**, and general patterns +- Assisting with **helper utilities** such as formatting functions + +However, for more complex aspects—such as **business logic, form handling, and state management**—AI assistance was limited and often resulted in errors that required manual debugging and rework. + +### Problem 3 – ~20% AI Assistance +This was my favorite part of the challenge, as it closely reflects **real-world development scenarios**. +The problem required careful code reading, reasoning about existing behavior, and working through imperfect or messy implementations—something developers face daily. + +Approximately **80% of the ideas and solutions came from my own analysis**, 20% ai help me to validate my thoughts and give me some ideas i missed. + +Overall, I found this problem to be the most realistic and intellectually engaging part of the challenge. + +## Final Note + +I view AI as a productivity tool rather than a replacement for engineering judgment. +Throughout this challenge, my focus was on understanding the problem deeply, making deliberate technical decisions, and using AI selectively to accelerate—not replace—my thinking process. + diff --git a/src/problem1/.keep b/src/problem1/.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/problem1/index.ts b/src/problem1/index.ts new file mode 100644 index 000000000..520f01e59 --- /dev/null +++ b/src/problem1/index.ts @@ -0,0 +1,33 @@ +/** + * first idea in my head was using reduce function, i know the performance it not too good with many loop to generate and calculate, + * but the logic is clear by using the previous value to accumulate the sum. better way can a for loop but i like reduce more. + */ +const sum_to_n_a = function (n: number): number { + return Array.from({ length: n }, (_, i) => i + 1).reduce( + (acc, val) => acc + val, + 0 + ); +}; + +/* + * my second idea was using math, because i love math so i found that if we calculate the sum of an arithmetic sequence, + * we have the last number of the list plus the first number is equal the n-1 number plus the second number, and so on. so we have n/2 pairs of (n+1). + * but then if n is odd number the middle number will be alone without any pair. so we have n/2 -1 pares of (n+1) plus the middle number + * but the special thing is double the middled number is equal to n + 1. then we can convert it back to n/2 pairs of (n+1). + * so finally we have n/2 * (n + 1). + */ +const sum_to_n_b = function (n: number): number { + return n / 2 * (n + 1); +}; + +/* + * actually i have little block with the 3rd idea, originally i want to use while loop to accumulate the sum, but then i think it may not good enough. + * then i try to do a little research and found there are many answers in the internet lol. and i know that recursion can solve the problem. + * then i implement it as the third way to deal with it, hope its still acceptable for the test. + */ +const sum_to_n_c = function (n: number): number { + if (n <= 1) { + return n; + } + return n + sum_to_n_c(n - 1); +}; diff --git a/src/problem2/.gitignore b/src/problem2/.gitignore new file mode 100644 index 000000000..a547bf36d --- /dev/null +++ b/src/problem2/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/src/problem2/README.md b/src/problem2/README.md new file mode 100644 index 000000000..57ab27ad0 --- /dev/null +++ b/src/problem2/README.md @@ -0,0 +1,167 @@ +# Problem 2 - Fancy Form assignment # + +## Project Overview +Create a **currency swap form** based on the template provided in the project folder. +This form allows users to swap assets from one currency to another. + +## Implementation Idea + +The application is designed as a **simple wallet management app** for a single user. + +### Initial State +- The user starts with **1,000,000 USD** in their USD wallet. +- Each currency is represented as a separate wallet. + +### Pricing & Token Data +- Token prices are fetched from the following API: + https://interview.switcheo.com/prices.json +- Conversion rates are applied **in real time**: + - When the user selects/search the target currency + - When the user enters the amount to swap + - Conversion also works in reverse (changing the target amount recalculates the source amount) + +### Validation Rules +The form validates the following cases: +- Empty input fields +- Negative or zero amounts +- Insufficient balance in the source wallet + +### API Simulation +- A small artificial delay is added to simulate a real API call during the swap process + + +## folder structures +``` +problem2/ +├── public/ # Static assets +└── src/ + ├── main.tsx # Contain provider and render app + ├── App.tsx # Simple App component + ├── theme.ts # Configure Material-UI theme + ├── api/ # API layer contain data fetching logic hooks and services + ├── atom/ # Reusable UI components (Atomic Design) + ├── components/ # Feature components containing business UI and logic + ├── contexts/ # React contexts for modal and notification + ├── types/ # TypeScript types & schemas + └── common/ # Utilities & constants +``` + +## Tech Stack + +### Core Framework +- **React 19.2.0** with **TypeScript ~5.9.3** + - Uses React built-in hooks and Context API for state management + - Type-safe development with strict TypeScript configuration + +### Build Tool & Development +- **Vite (Rolldown-Vite 7.2.5)** - Next-gen build tool with HMR + - Path alias mapping (`@components`, `@api`, `@types`, etc.) + +### UI Framework +- **Material-UI v7.3.7** (@mui/material) + - Component library with Material Design + - Responsive Grid system + +### State Management & Data Fetching +- **TanStack React Query v5.90.18** + - Server state management + - Automatic caching, refetching and background updates + +### Form Handling & Validation +- **Zod v4.3.5** - TypeScript-first schema validation + - Runtime type checking + +### HTTP Client +- **Axios v1.13.2** + - Promise-based HTTP client + - Request/response interceptors + +--- + +## Architecture & Best Practices + +### 1. **Layered Architecture** +``` +Presentation Layer (Components) + ↓ +Business Logic Layer (Hooks) + ↓ +Data Access Layer (Services) + ↓ +API Client Layer (Axios) +``` + +#### **Separation of Concerns** +- **Components**: Handle UI rendering and user interaction only +- **Custom Hooks**: Business logic, state management, side effects +- **Services**: API calls, data transformation +- **Contexts**: Cross-cutting concerns (modals, notifications) + +### 2. **Atomic Design Pattern** +``` +src/atom/ # Atomic components (Button, Input, Autocomplete) +src/components/ # Feature components (WalletCard, ExchangeForm) +``` + +- Reusable UI components in `/atom` +- Composition-based component design +- Props typing with generics for reusability + +**Example**: `CommonAutocomplete` - Generic component that works with any data type + +### 3. **Custom Hooks Pattern** + +#### **Data Fetching Hooks** (`useWallets`, `useAllPrices`) +```typescript +// Query keys pattern for cache management +export const walletQueryKeys = { + all: ["wallets"] as const, +}; + +// Shared query config +export const queryConfig = { + staleTime: 5 * 60 * 1000, // 5 minutes + gcTime: 30 * 60 * 1000, // 30 minutes + retry: 2, +}; +``` + +#### **Business Logic Hooks** (`useExchangeForm`) +- Form state management +- Field-level validation +- Real-time conversion calculation +- Bidirectional data sync (from ↔ to amounts) + +### 4. **Performance Optimizations** + +#### **Memoization** +```typescript +// useMemo for expensive calculations +const pricesMap = useMemo(() => getLatestPricesMap(prices), [prices]); + +// useCallback for event handlers +const handleAmountChange = useCallback((field, value) => { + // ... +}, [dependencies]); +``` + +#### **React Query Caching** +- 5 minutes stale time → Reduce unnecessary refetches +- 30 minutes garbage collection → Balance memory usage +- Background refetching on window focus + +#### **Component Optimization** +- Skeleton loading states +- Conditional rendering with early returns +- Grid virtualization with MUI Grid v2 + +## Key Takeaways + +✅ **Type Safety First**: TypeScript strict mode + Zod validation +✅ **Separation of Concerns**: Layered architecture with clear boundaries +✅ **Performance**: React Query caching + memoization +✅ **Developer Experience**: Path aliases + hot reload + ESLint +✅ **User Experience**: Loading states + error handling + real-time validation +✅ **Code Quality**: Consistent patterns + reusable components + documentation +✅ **Scalability**: Modular structure + easy to extend + diff --git a/src/problem2/eslint.config.js b/src/problem2/eslint.config.js new file mode 100644 index 000000000..5e6b472f5 --- /dev/null +++ b/src/problem2/eslint.config.js @@ -0,0 +1,23 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + }, +]) diff --git a/src/problem2/index.html b/src/problem2/index.html index 4058a68bf..1440f4257 100644 --- a/src/problem2/index.html +++ b/src/problem2/index.html @@ -1,27 +1,13 @@ - - - - - Fancy Form - - - - - - - - -
-
Swap
- - - - - - - -
- - - + + + + + + + vite-project + + +
+ + diff --git a/src/problem2/package-lock.json b/src/problem2/package-lock.json new file mode 100644 index 000000000..fd4b1e861 --- /dev/null +++ b/src/problem2/package-lock.json @@ -0,0 +1,3898 @@ +{ + "name": "vite-project", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vite-project", + "version": "0.0.0", + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@hookform/resolvers": "^5.2.2", + "@mui/icons-material": "^7.3.7", + "@mui/material": "^7.3.7", + "@mui/styled-engine-sc": "^7.3.7", + "@tanstack/react-query": "^5.90.18", + "axios": "^1.13.2", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "zod": "^4.3.5" + }, + "devDependencies": { + "@eslint/js": "^9.39.1", + "@types/node": "^24.10.1", + "@types/react": "^19.2.5", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.1", + "eslint": "^9.39.1", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.4.24", + "globals": "^16.5.0", + "typescript": "~5.9.3", + "typescript-eslint": "^8.46.4", + "vite": "npm:rolldown-vite@7.2.5" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", + "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.28.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", + "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", + "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6", + "@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/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 + }, + "node_modules/@babel/generator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", + "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", + "dependencies": { + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6", + "@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, + "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-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "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==", + "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, + "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, + "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==", + "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==", + "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, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "dependencies": { + "@babel/types": "^7.28.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.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, + "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, + "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.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "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==", + "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.28.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", + "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", + "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", + "dev": true, + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", + "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" + }, + "node_modules/@emotion/styled": { + "version": "11.14.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@hookform/resolvers": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.2.2.tgz", + "integrity": "sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==", + "dependencies": { + "@standard-schema/utils": "^0.3.0" + }, + "peerDependencies": { + "react-hook-form": "^7.55.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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==", + "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, + "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==", + "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==" + }, + "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==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.7.tgz", + "integrity": "sha512-8jWwS6FweMkpyRkrJooamUGe1CQfO1yJ+lM43IyUJbrhHW/ObES+6ry4vfGi8EKaldHL3t3BG1bcLcERuJPcjg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.7.tgz", + "integrity": "sha512-3Q+ulAqG+A1+R4ebgoIs7AccaJhIGy+Xi/9OnvX376jQ6wcy+rz4geDGrxQxCGzdjOQr4Z3NgyFSZCz4T999lA==", + "dependencies": { + "@babel/runtime": "^7.28.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^7.3.7", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.7.tgz", + "integrity": "sha512-6bdIxqzeOtBAj2wAsfhWCYyMKPLkRO9u/2o5yexcL0C3APqyy91iGSWgT3H7hg+zR2XgE61+WAu12wXPON8b6A==", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/core-downloads-tracker": "^7.3.7", + "@mui/system": "^7.3.7", + "@mui/types": "^7.4.10", + "@mui/utils": "^7.3.7", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.12", + "clsx": "^2.1.1", + "csstype": "^3.2.3", + "prop-types": "^15.8.1", + "react-is": "^19.2.3", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^7.3.7", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.7.tgz", + "integrity": "sha512-w7r1+CYhG0syCAQUWAuV5zSaU2/67WA9JXUderdb7DzCIJdp/5RmJv6L85wRjgKCMsxFF0Kfn0kPgPbPgw/jdw==", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/utils": "^7.3.7", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.7.tgz", + "integrity": "sha512-y/QkNXv6cF6dZ5APztd/dFWfQ6LHKPx3skyYO38YhQD4+Cxd6sFAL3Z38WMSSC8LQz145Mpp3CcLrSCLKPwYAg==", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "csstype": "^3.2.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine-sc": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/@mui/styled-engine-sc/-/styled-engine-sc-7.3.7.tgz", + "integrity": "sha512-BJ91ujrXXaYW0wXdEw8K1EoUzsqA6e/sJhxxLlwWjqgRWC8spa+MFP+H+5vCUqAHRiB38dAOcvgZxflUG5oeZg==", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@types/hoist-non-react-statics": "^3.3.7", + "csstype": "^3.2.3", + "hoist-non-react-statics": "^3.3.2", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "styled-components": "^6.0.0" + } + }, + "node_modules/@mui/system": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.7.tgz", + "integrity": "sha512-DovL3k+FBRKnhmatzUMyO5bKkhMLlQ9L7Qw5qHrre3m8zCZmE+31NDVBFfqrbrA7sq681qaEIHdkWD5nmiAjyQ==", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/private-theming": "^7.3.7", + "@mui/styled-engine": "^7.3.7", + "@mui/types": "^7.4.10", + "@mui/utils": "^7.3.7", + "clsx": "^2.1.1", + "csstype": "^3.2.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.4.10", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.10.tgz", + "integrity": "sha512-0+4mSjknSu218GW3isRqoxKRTOrTLd/vHi/7UC4+wZcUrOAqD9kRk7UQRL1mcrzqRoe7s3UT6rsRpbLkW5mHpQ==", + "dependencies": { + "@babel/runtime": "^7.28.4" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.7.tgz", + "integrity": "sha512-+YjnjMRnyeTkWnspzoxRdiSOgkrcpTikhNPoxOZW0APXx+urHtUoXJ9lbtCZRCA5a4dg5gSbd19alL1DvRs5fg==", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/types": "^7.4.10", + "@types/prop-types": "^15.7.15", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.2.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", + "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "dev": true, + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@oxc-project/runtime": { + "version": "0.97.0", + "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.97.0.tgz", + "integrity": "sha512-yH0zw7z+jEws4dZ4IUKoix5Lh3yhqIJWF9Dc8PWvhpo7U7O+lJrv7ZZL4BeRO0la8LBQFwcCewtLBnVV7hPe/w==", + "dev": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.97.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.97.0.tgz", + "integrity": "sha512-lxmZK4xFrdvU0yZiDwgVQTCvh2gHWBJCBk5ALsrtsBWhs0uDIi+FTOnXRQeQfs304imdvTdaakT/lqwQ8hkOXQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.50.tgz", + "integrity": "sha512-XlEkrOIHLyGT3avOgzfTFSjG+f+dZMw+/qd+Y3HLN86wlndrB/gSimrJCk4gOhr1XtRtEKfszpadI3Md4Z4/Ag==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.50.tgz", + "integrity": "sha512-+JRqKJhoFlt5r9q+DecAGPLZ5PxeLva+wCMtAuoFMWPoZzgcYrr599KQ+Ix0jwll4B4HGP43avu9My8KtSOR+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.50.tgz", + "integrity": "sha512-fFXDjXnuX7/gQZQm/1FoivVtRcyAzdjSik7Eo+9iwPQ9EgtA5/nB2+jmbzaKtMGG3q+BnZbdKHCtOacmNrkIDA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.50.tgz", + "integrity": "sha512-F1b6vARy49tjmT/hbloplzgJS7GIvwWZqt+tAHEstCh0JIh9sa8FAMVqEmYxDviqKBaAI8iVvUREm/Kh/PD26Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.50.tgz", + "integrity": "sha512-U6cR76N8T8M6lHj7EZrQ3xunLPxSvYYxA8vJsBKZiFZkT8YV4kjgCO3KwMJL0NOjQCPGKyiXO07U+KmJzdPGRw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.50.tgz", + "integrity": "sha512-ONgyjofCrrE3bnh5GZb8EINSFyR/hmwTzZ7oVuyUB170lboza1VMCnb8jgE6MsyyRgHYmN8Lb59i3NKGrxrYjw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.50.tgz", + "integrity": "sha512-L0zRdH2oDPkmB+wvuTl+dJbXCsx62SkqcEqdM+79LOcB+PxbAxxjzHU14BuZIQdXcAVDzfpMfaHWzZuwhhBTcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.50.tgz", + "integrity": "sha512-gyoI8o/TGpQd3OzkJnh1M2kxy1Bisg8qJ5Gci0sXm9yLFzEXIFdtc4EAzepxGvrT2ri99ar5rdsmNG0zP0SbIg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.50.tgz", + "integrity": "sha512-zti8A7M+xFDpKlghpcCAzyOi+e5nfUl3QhU023ce5NCgUxRG5zGP2GR9LTydQ1rnIPwZUVBWd4o7NjZDaQxaXA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.50.tgz", + "integrity": "sha512-eZUssog7qljrrRU9Mi0eqYEPm3Ch0UwB+qlWPMKSUXHNqhm3TvDZarJQdTevGEfu3EHAXJvBIe0YFYr0TPVaMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.50.tgz", + "integrity": "sha512-nmCN0nIdeUnmgeDXiQ+2HU6FT162o+rxnF7WMkBm4M5Ds8qTU7Dzv2Wrf22bo4ftnlrb2hKK6FSwAJSAe2FWLg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.0.7" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.50.tgz", + "integrity": "sha512-7kcNLi7Ua59JTTLvbe1dYb028QEPaJPJQHqkmSZ5q3tJueUeb6yjRtx8mw4uIqgWZcnQHAR3PrLN4XRJxvgIkA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-ia32-msvc": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.50.tgz", + "integrity": "sha512-lL70VTNvSCdSZkDPPVMwWn/M2yQiYvSoXw9hTLgdIWdUfC3g72UaruezusR6ceRuwHCY1Ayu2LtKqXkBO5LIwg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.50.tgz", + "integrity": "sha512-4qU4x5DXWB4JPjyTne/wBNPqkbQU8J45bl21geERBKtEittleonioACBL1R0PsBu0Aq21SwMK5a9zdBkWSlQtQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz", + "integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==", + "dev": true + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==" + }, + "node_modules/@tanstack/query-core": { + "version": "5.90.19", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.19.tgz", + "integrity": "sha512-GLW5sjPVIvH491VV1ufddnfldyVB+teCnpPIvweEfkpRx7CfUmUGhoh9cdcUKBh/KwVxk22aNEDxeTsvmyB/WA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.90.19", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.19.tgz", + "integrity": "sha512-qTZRZ4QyTzQc+M0IzrbKHxSeISUmRB3RPGmao5bT+sI6ayxSRhn0FXEnT5Hg3as8SBFcRosrXXRFB+yAcxVxJQ==", + "dependencies": { + "@tanstack/query-core": "5.90.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "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, + "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, + "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, + "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, + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "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 + }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz", + "integrity": "sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==", + "dependencies": { + "hoist-non-react-statics": "^3.3.0" + }, + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "24.10.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.9.tgz", + "integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==", + "dev": true, + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "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==" + }, + "node_modules/@types/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.8.tgz", + "integrity": "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/stylis": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.7.tgz", + "integrity": "sha512-VgDNokpBoKF+wrdvhAAfS55OMQpL6QRglwTwNC3kIgBrzZxA4WsFj+2eLfEA/uMUDzBcEhYmjSbwQakn/i3ajA==", + "peer": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.0.tgz", + "integrity": "sha512-eEXsVvLPu8Z4PkFibtuFJLJOTAV/nPdgtSjkGoPpddpFk3/ym2oy97jynY6ic2m6+nc5M8SE1e9v/mHKsulcJg==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.53.0", + "@typescript-eslint/type-utils": "8.53.0", + "@typescript-eslint/utils": "8.53.0", + "@typescript-eslint/visitor-keys": "8.53.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.53.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.53.0.tgz", + "integrity": "sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.53.0", + "@typescript-eslint/types": "8.53.0", + "@typescript-eslint/typescript-estree": "8.53.0", + "@typescript-eslint/visitor-keys": "8.53.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.53.0.tgz", + "integrity": "sha512-Bl6Gdr7NqkqIP5yP9z1JU///Nmes4Eose6L1HwpuVHwScgDPPuEWbUVhvlZmb8hy0vX9syLk5EGNL700WcBlbg==", + "dev": true, + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.53.0", + "@typescript-eslint/types": "^8.53.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.53.0.tgz", + "integrity": "sha512-kWNj3l01eOGSdVBnfAF2K1BTh06WS0Yet6JUgb9Cmkqaz3Jlu0fdVUjj9UI8gPidBWSMqDIglmEXifSgDT/D0g==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.53.0", + "@typescript-eslint/visitor-keys": "8.53.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.53.0.tgz", + "integrity": "sha512-K6Sc0R5GIG6dNoPdOooQ+KtvT5KCKAvTcY8h2rIuul19vxH5OTQk7ArKkd4yTzkw66WnNY0kPPzzcmWA+XRmiA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.53.0.tgz", + "integrity": "sha512-BBAUhlx7g4SmcLhn8cnbxoxtmS7hcq39xKCgiutL3oNx1TaIp+cny51s8ewnKMpVUKQUGb41RAUWZ9kxYdovuw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.53.0", + "@typescript-eslint/typescript-estree": "8.53.0", + "@typescript-eslint/utils": "8.53.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.53.0.tgz", + "integrity": "sha512-Bmh9KX31Vlxa13+PqPvt4RzKRN1XORYSLlAE+sO1i28NkisGbTtSLFVB3l7PWdHtR3E0mVMuC7JilWJ99m2HxQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.53.0.tgz", + "integrity": "sha512-pw0c0Gdo7Z4xOG987u3nJ8akL9093yEEKv8QTJ+Bhkghj1xyj8cgPaavlr9rq8h7+s6plUJ4QJYw2gCZodqmGw==", + "dev": true, + "dependencies": { + "@typescript-eslint/project-service": "8.53.0", + "@typescript-eslint/tsconfig-utils": "8.53.0", + "@typescript-eslint/types": "8.53.0", + "@typescript-eslint/visitor-keys": "8.53.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.53.0.tgz", + "integrity": "sha512-XDY4mXTez3Z1iRDI5mbRhH4DFSt46oaIFsLg+Zn97+sYrXACziXSQcSelMybnVZ5pa1P6xYkPr5cMJyunM1ZDA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.53.0", + "@typescript-eslint/types": "8.53.0", + "@typescript-eslint/typescript-estree": "8.53.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.53.0.tgz", + "integrity": "sha512-LZ2NqIHFhvFwxG0qZeLL9DvdNAHPGCY5dIRwBhyYeU+LfLhcStE1ImjsuTG/WaVh3XysGaeLW8Rqq7cGkPCFvw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.53.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.2.tgz", + "integrity": "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.28.5", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.53", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": 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/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, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "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 + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.15", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.15.tgz", + "integrity": "sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg==", + "dev": true, + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "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" + } + ], + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "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==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001765", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001765.tgz", + "integrity": "sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==", + "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" + } + ] + }, + "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, + "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/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "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 + }, + "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==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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 + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "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, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "peer": true, + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, + "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==" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "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==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "dev": true + }, + "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==", + "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==", + "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==", + "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==", + "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==", + "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/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", + "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz", + "integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==", + "dev": true, + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.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 + }, + "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 + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "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, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, + "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, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "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==", + "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/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, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "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==", + "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==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "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==" + }, + "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==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "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==" + }, + "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, + "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==", + "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 + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "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 + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "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, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "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, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", + "dev": true, + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "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" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "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, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "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==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "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==", + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "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==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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==" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/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, + "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, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "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==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "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" + } + ], + "peer": true, + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "peer": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "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, + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.3" + } + }, + "node_modules/react-hook-form": { + "version": "7.71.1", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.71.1.tgz", + "integrity": "sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w==", + "peer": true, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, + "node_modules/react-is": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.3.tgz", + "integrity": "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA==" + }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dependencies": { + "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-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.50.tgz", + "integrity": "sha512-JFULvCNl/anKn99eKjOSEubi0lLmNqQDAjyEMME2T4CwezUDL0i6t1O9xZsu2OMehPnV2caNefWpGF+8TnzB6A==", + "dev": true, + "dependencies": { + "@oxc-project/types": "=0.97.0", + "@rolldown/pluginutils": "1.0.0-beta.50" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-beta.50", + "@rolldown/binding-darwin-arm64": "1.0.0-beta.50", + "@rolldown/binding-darwin-x64": "1.0.0-beta.50", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.50", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.50", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.50", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.50", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.50", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.50", + "@rolldown/binding-openharmony-arm64": "1.0.0-beta.50", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.50", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.50", + "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.50", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.50" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.50.tgz", + "integrity": "sha512-5e76wQiQVeL1ICOZVUg4LSOVYg9jyhGCin+icYozhsUzM+fHE7kddi1bdiE0jwVqTfkjba3jUFbEkoC9WkdvyA==", + "dev": true + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==" + }, + "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, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "peer": true + }, + "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, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/styled-components": { + "version": "6.3.8", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.3.8.tgz", + "integrity": "sha512-Kq/W41AKQloOqKM39zfaMdJ4BcYDw/N5CIq4/GTI0YjU6pKcZ1KKhk6b4du0a+6RA9pIfOP/eu94Ge7cu+PDCA==", + "peer": true, + "dependencies": { + "@emotion/is-prop-valid": "1.4.0", + "@emotion/unitless": "0.10.0", + "@types/stylis": "4.2.7", + "css-to-react-native": "3.2.0", + "csstype": "3.2.3", + "postcss": "8.4.49", + "shallowequal": "1.1.0", + "stylis": "4.3.6", + "tslib": "2.8.1" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/styled-components/node_modules/stylis": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", + "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "peer": true + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, + "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, + "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==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/ts-api-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "dev": true, + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "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==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.53.0.tgz", + "integrity": "sha512-xHURCQNxZ1dsWn0sdOaOfCSQG0HKeqSj9OexIxrz6ypU6wHYOdX2I3D2b8s8wFSsSOYJb+6q283cLiLlkEsBYw==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.53.0", + "@typescript-eslint/parser": "8.53.0", + "@typescript-eslint/typescript-estree": "8.53.0", + "@typescript-eslint/utils": "8.53.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true + }, + "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" + } + ], + "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, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "name": "rolldown-vite", + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.2.5.tgz", + "integrity": "sha512-u09tdk/huMiN8xwoiBbig197jKdCamQTtOruSalOzbqGje3jdHiV0njQlAW0YvzoahkirFePNQ4RYlfnRQpXZA==", + "dev": true, + "dependencies": { + "@oxc-project/runtime": "0.97.0", + "fdir": "^6.5.0", + "lightningcss": "^1.30.2", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rolldown": "1.0.0-beta.50", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "esbuild": "^0.25.0", + "jiti": ">=1.21.0", + "less": "^4.0.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 + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "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/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "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" + } + ], + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "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, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", + "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + } + } +} diff --git a/src/problem2/package.json b/src/problem2/package.json new file mode 100644 index 000000000..d39d55655 --- /dev/null +++ b/src/problem2/package.json @@ -0,0 +1,42 @@ +{ + "name": "vite-project", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@hookform/resolvers": "^5.2.2", + "@mui/icons-material": "^7.3.7", + "@mui/material": "^7.3.7", + "@mui/styled-engine-sc": "^7.3.7", + "@tanstack/react-query": "^5.90.18", + "axios": "^1.13.2", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "zod": "^4.3.5" + }, + "devDependencies": { + "@eslint/js": "^9.39.1", + "@types/node": "^24.10.1", + "@types/react": "^19.2.5", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.1", + "eslint": "^9.39.1", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.4.24", + "globals": "^16.5.0", + "typescript": "~5.9.3", + "typescript-eslint": "^8.46.4", + "vite": "npm:rolldown-vite@7.2.5" + }, + "overrides": { + "vite": "npm:rolldown-vite@7.2.5" + } +} diff --git a/src/problem2/public/not-found-icon-10.jpg b/src/problem2/public/not-found-icon-10.jpg new file mode 100644 index 0000000000000000000000000000000000000000..381489c0b9ef3796aef118e8a1925d5a91100c36 GIT binary patch literal 17482 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 literal 0 HcmV?d00001 diff --git a/src/problem2/public/vite.svg b/src/problem2/public/vite.svg new file mode 100644 index 000000000..e7b8dfb1b --- /dev/null +++ b/src/problem2/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/problem2/script.js b/src/problem2/script.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/problem2/src/App.css b/src/problem2/src/App.css new file mode 100644 index 000000000..735b2cacf --- /dev/null +++ b/src/problem2/src/App.css @@ -0,0 +1,16 @@ +#root { + max-width: 1280px; + margin: 0 auto; + + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} + +/* Ensure border-box for all elements */ +*, +*::before, +*::after { + box-sizing: border-box; +} diff --git a/src/problem2/src/App.tsx b/src/problem2/src/App.tsx new file mode 100644 index 000000000..28822e026 --- /dev/null +++ b/src/problem2/src/App.tsx @@ -0,0 +1,68 @@ +import "./App.css"; +import { Grid, Skeleton } from "@mui/material"; +import { ExchangeModal, WalletCard, AppHeader } from "@components"; +import { useAllPrices, useWallets } from "@api/hooks"; +import { useMemo } from "react"; +import { ErrorBox } from "@atom"; + +function App() { + const { + data: prices, + isError: isPricesError, + refetch: refetchPrices, + error: pricesError, + } = useAllPrices(); + const { + data: wallets, + isLoading, + isError, + isFetching, + error, + refetch, + } = useWallets(); + + const walletBoxes = useMemo(() => { + if (!wallets) return null; + return wallets.map((wallet) => ( + + + + )); + }, [wallets]); + + return ( + <> + {/* header */} + + + {/* body */} + + {(isLoading || isFetching) && + Array.from({ length: 4 }).map((_, index) => ( + + + + ))} + + {(isError || isPricesError) && ( + + {isError && } + {isPricesError && ( + + )} + + )} + + {!isLoading && !isError && !isFetching && walletBoxes} + + + + + ); +} + +export default App; diff --git a/src/problem2/src/api/client.ts b/src/problem2/src/api/client.ts new file mode 100644 index 000000000..b5c642392 --- /dev/null +++ b/src/problem2/src/api/client.ts @@ -0,0 +1,59 @@ +import { QueryClient } from "@tanstack/react-query"; +import type { AxiosError, AxiosInstance } from "axios"; +import axios, { HttpStatusCode } from "axios"; +import { + MAX_RETRIES, + MAX_TIMEOUT, + PRICE_API_URL, + SECOND_TO_MILLISECONDS, +} from "@common"; + +export const priceClient: AxiosInstance = axios.create({ + baseURL: PRICE_API_URL, + timeout: MAX_TIMEOUT, + headers: { + "Content-Type": "application/json", + }, +}); + +/** + * Response Interceptor for Public Client + * Basic error handling + */ +priceClient.interceptors.response.use( + (response) => { + return response; + }, + (error) => { + console.error("Access forbidden"); + + return Promise.reject(error); + }, +); + +export const queryClient = new QueryClient({ + defaultOptions: { + queries: { + // Global retry strategy + retry: (failureCount: number, error: unknown) => { + const axiosError = error as AxiosError; + // Don't retry on 4xx errors + if ( + axiosError?.response?.status && + axiosError.response.status >= HttpStatusCode.BadRequest && + axiosError.response.status < HttpStatusCode.InternalServerError + ) { + return false; + } + // Retry max 2 times for 5xx and network errors + return failureCount < MAX_RETRIES; + }, + // Retry delay + retryDelay: (attemptIndex: number) => + Math.min( + SECOND_TO_MILLISECONDS * MAX_RETRIES ** attemptIndex, + MAX_TIMEOUT, + ), + }, + }, +}); diff --git a/src/problem2/src/api/hooks/index.ts b/src/problem2/src/api/hooks/index.ts new file mode 100644 index 000000000..022b23c31 --- /dev/null +++ b/src/problem2/src/api/hooks/index.ts @@ -0,0 +1,2 @@ +export * from "./prices.hooks"; +export * from "./wallet.hooks"; diff --git a/src/problem2/src/api/hooks/prices.hooks.ts b/src/problem2/src/api/hooks/prices.hooks.ts new file mode 100644 index 000000000..3117008f9 --- /dev/null +++ b/src/problem2/src/api/hooks/prices.hooks.ts @@ -0,0 +1,16 @@ +import { useQuery } from "@tanstack/react-query"; +import { priceService } from "@api"; +import type { TokenPriceType } from "@types"; +import { queryConfig } from "@common"; + +const queryKeys = { + all: ["prices"] as const, +}; + +export const useAllPrices = () => { + return useQuery({ + ...queryConfig, + queryKey: queryKeys.all, + queryFn: () => priceService.getTokenPrice(), + }); +}; diff --git a/src/problem2/src/api/hooks/wallet.hooks.ts b/src/problem2/src/api/hooks/wallet.hooks.ts new file mode 100644 index 000000000..126a9287f --- /dev/null +++ b/src/problem2/src/api/hooks/wallet.hooks.ts @@ -0,0 +1,41 @@ +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { walletService } from "@api"; +import type { WalletType } from "@types"; +import { queryConfig } from "@common"; + +export const walletQueryKeys = { + all: ["wallets"] as const, +}; + +export const useWallets = () => { + return useQuery({ + ...queryConfig, + queryKey: walletQueryKeys.all, + queryFn: () => walletService.getWallets(), + }); +}; + +interface ExchangeWalletParams { + fromCurrency: string; + toCurrency: string; + fromAmount: number; + toAmount: number; +} + +export const useExchangeWallet = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (params: ExchangeWalletParams) => { + await walletService.exchangeWallet( + params.fromCurrency, + params.toCurrency, + params.fromAmount, + params.toAmount, + ); + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: walletQueryKeys.all }); + }, + }); +}; diff --git a/src/problem2/src/api/index.ts b/src/problem2/src/api/index.ts new file mode 100644 index 000000000..06cf368aa --- /dev/null +++ b/src/problem2/src/api/index.ts @@ -0,0 +1,4 @@ +export * from "./client"; +export * from "./provider"; +export * from "./services"; +export * from "./hooks"; \ No newline at end of file diff --git a/src/problem2/src/api/provider.tsx b/src/problem2/src/api/provider.tsx new file mode 100644 index 000000000..f3565c7eb --- /dev/null +++ b/src/problem2/src/api/provider.tsx @@ -0,0 +1,17 @@ +import type { ReactNode } from "react"; +import { QueryClientProvider } from "@tanstack/react-query"; +import { queryClient } from "./client"; + +interface QueryProviderProps { + children: ReactNode; +} + +/** + * React Query Provider Component + * Wrap your app with this component to enable React Query + */ +export const QueryProvider = ({ children }: QueryProviderProps) => { + return ( + {children} + ); +}; diff --git a/src/problem2/src/api/services/index.ts b/src/problem2/src/api/services/index.ts new file mode 100644 index 000000000..47c2eee32 --- /dev/null +++ b/src/problem2/src/api/services/index.ts @@ -0,0 +1,2 @@ +export * from "./prices.services"; +export * from "./wallet.services"; diff --git a/src/problem2/src/api/services/prices.services.ts b/src/problem2/src/api/services/prices.services.ts new file mode 100644 index 000000000..f1b32d7b0 --- /dev/null +++ b/src/problem2/src/api/services/prices.services.ts @@ -0,0 +1,16 @@ +import { priceClient } from "@api/client"; +import { API_ENDPOINTS } from "@common"; +import type { TokenPriceType } from "@types"; + +export const priceService = { + getTokenPrice: async (): Promise => { + // Simulate an API call to fetch token price + try { + const response = await priceClient.get(API_ENDPOINTS.PRICES); + return response.data; + } catch (error) { + console.error("Failed to fetch token prices", error); + throw error; + } + }, +}; diff --git a/src/problem2/src/api/services/wallet.services.ts b/src/problem2/src/api/services/wallet.services.ts new file mode 100644 index 000000000..6d0aa6ef2 --- /dev/null +++ b/src/problem2/src/api/services/wallet.services.ts @@ -0,0 +1,62 @@ +import { WALLET_STORE, SIMULATED_DELAY } from "@common"; +import type { WalletType } from "@types"; + +export const walletService = { + init: () => { + const initData = { USD: 100000000 }; + + const storedData = localStorage.getItem(WALLET_STORE); + if (!storedData) { + localStorage.setItem(WALLET_STORE, JSON.stringify(initData)); + } + return initData; + }, + + getWallets: async (): Promise => { + // Simulate API delay + await new Promise((resolve) => setTimeout(resolve, SIMULATED_DELAY)); + + const storedData = localStorage.getItem(WALLET_STORE); + const walletData: Record = + storedData && storedData.length > 2 + ? (JSON.parse(storedData) as Record) + : walletService.init(); + + return Object.keys(walletData) + .map((key) => ({ + currency: key, + amount: walletData[key], + })) + .filter((wallet) => wallet.amount > 0); + }, + + getBalance: (currency: string): number => { + const storedData = localStorage.getItem(WALLET_STORE); + const walletData: Record = storedData + ? (JSON.parse(storedData) as Record) + : walletService.init(); + return walletData[currency] || 0; + }, + + exchangeWallet: async ( + fromCurrency: string, + toCurrency: string, + fromAmount: number, + toAmount: number, + ) => { + await new Promise((resolve) => setTimeout(resolve, SIMULATED_DELAY)); + + const storedData = localStorage.getItem(WALLET_STORE); + const walletData: Record = storedData + ? (JSON.parse(storedData) as Record) + : walletService.init(); + const currentFromAmount = walletData[fromCurrency] || 0; + if (currentFromAmount < fromAmount) { + throw new Error("Insufficient funds"); + } + walletData[fromCurrency] -= fromAmount; + walletData[toCurrency] = (walletData[toCurrency] || 0) + toAmount; + + localStorage.setItem(WALLET_STORE, JSON.stringify(walletData)); + }, +}; diff --git a/src/problem2/src/atom/error.tsx b/src/problem2/src/atom/error.tsx new file mode 100644 index 000000000..82a69ff99 --- /dev/null +++ b/src/problem2/src/atom/error.tsx @@ -0,0 +1,24 @@ +import { Alert, Box, Button } from "@mui/material"; +import { ERROR_MESSAGES } from "@common"; + +interface ErrorBoxProps { + error?: Error; + refetch: () => void; +} + +export const ErrorBox = ({ error, refetch }: ErrorBoxProps) => { + return ( + + refetch()}> + Retry + + } + > + {ERROR_MESSAGES.FAILED_TO_LOAD}: {error?.message || ERROR_MESSAGES.UNKNOWN_ERROR} + + + ); +}; diff --git a/src/problem2/src/atom/form/autocomplete.tsx b/src/problem2/src/atom/form/autocomplete.tsx new file mode 100644 index 000000000..3e9a04354 --- /dev/null +++ b/src/problem2/src/atom/form/autocomplete.tsx @@ -0,0 +1,48 @@ +import { Autocomplete, TextField } from "@mui/material"; +import type { AutocompleteProps, TextFieldProps } from "@mui/material"; + +type CommonAutocompleteProps = { + name: string; + label?: string; + textFieldProps?: Omit; + onChange?: (value: T | null) => void; + error?: string; +} & Omit, "renderInput" | "onChange">; + +export const CommonAutocomplete = ({ + label, + textFieldProps, + onChange, + error, + ref, + ...props +}: CommonAutocompleteProps) => { + return ( + { + // Call custom onChange if provided + if (onChange) { + onChange(newValue); + } + }} + renderInput={(params) => ( + + )} + /> + ); +}; diff --git a/src/problem2/src/atom/form/index.ts b/src/problem2/src/atom/form/index.ts new file mode 100644 index 000000000..4bfff20ff --- /dev/null +++ b/src/problem2/src/atom/form/index.ts @@ -0,0 +1,2 @@ +export * from "./text-field"; +export * from "./autocomplete"; diff --git a/src/problem2/src/atom/form/text-field.tsx b/src/problem2/src/atom/form/text-field.tsx new file mode 100644 index 000000000..1272d7a29 --- /dev/null +++ b/src/problem2/src/atom/form/text-field.tsx @@ -0,0 +1,21 @@ +import { TextField } from "@mui/material"; +import type { TextFieldProps } from "@mui/material"; + +export const CommonNumberInput = (props: TextFieldProps) => { + return ( + + ); +}; diff --git a/src/problem2/src/atom/index.ts b/src/problem2/src/atom/index.ts new file mode 100644 index 000000000..be632a192 --- /dev/null +++ b/src/problem2/src/atom/index.ts @@ -0,0 +1,3 @@ +export * from "./form"; +export * from "./token"; +export * from "./error"; diff --git a/src/problem2/src/atom/token.tsx b/src/problem2/src/atom/token.tsx new file mode 100644 index 000000000..ed57257fc --- /dev/null +++ b/src/problem2/src/atom/token.tsx @@ -0,0 +1,60 @@ +import { getTokenIcon, TOKEN_ICON_FALLBACK } from "@common"; +import { styled } from "@mui/material"; +import React from "react"; + +interface TokenAvatarProps { + token: string; + size?: number; +} + +export const TokenAvatar = React.memo( + ({ token, size = 24 }: TokenAvatarProps) => { + if (!token) return null; + return ( + + {token} { + const target = e.target as HTMLImageElement; + target.style.display = "none"; + }} + /> + + ); + }, +); + +const TokenAvatarStyled = styled("div")<{ size: number }>(({ size }) => ({ + width: size, + height: size, + borderRadius: "50%", + backgroundSize: "cover", + backgroundPosition: "center", + backgroundImage: `url(${TOKEN_ICON_FALLBACK})`, + position: "relative", + "& img": { + borderRadius: "50%", + objectFit: "cover", + display: "block", + width: size, + height: size, + }, +})); + +interface TokenOptionProps extends React.HTMLAttributes { + option: string; +} +export const TokenOption = React.memo( + ({ option, ...props }: TokenOptionProps) => ( +
  • + + {option} +
  • + ), +); diff --git a/src/problem2/src/common/configs.ts b/src/problem2/src/common/configs.ts new file mode 100644 index 000000000..a639d0a20 --- /dev/null +++ b/src/problem2/src/common/configs.ts @@ -0,0 +1,15 @@ +export const SIMULATED_DELAY = 500; // ms + +export const MAX_TIMEOUT = 30000; // ms + +export const MAX_RETRIES = 2; + +export const SECOND_TO_MILLISECONDS = 1000; + +export const queryConfig = { + staleTime: SECOND_TO_MILLISECONDS * 60 * 5, // 5 minutes + gcTime: SECOND_TO_MILLISECONDS * 60 * 30, // 30 minutes + retry: MAX_RETRIES, + retryDelay: (attemptIndex: number) => + Math.min(SECOND_TO_MILLISECONDS * MAX_RETRIES ** attemptIndex, MAX_TIMEOUT), +}; diff --git a/src/problem2/src/common/constants.ts b/src/problem2/src/common/constants.ts new file mode 100644 index 000000000..1c50703f1 --- /dev/null +++ b/src/problem2/src/common/constants.ts @@ -0,0 +1,35 @@ +// Base URL for token icons from GitHub +export const TOKEN_ICON_BASE_URL = + "https://raw.githubusercontent.com/Switcheo/token-icons/main/tokens"; + +export const TOKEN_ICON_FALLBACK = "/not-found-icon-10.jpg"; + +export const PRICE_API_URL = "https://interview.switcheo.com/"; + +export const WALLET_STORE = "wallets"; + +export const API_ENDPOINTS = { + PRICES: "prices.json", +}; + +export const ERROR_MESSAGES = { + FETCH_PRICES: "Failed to fetch token prices.", + FETCH_WALLETS: "Failed to fetch wallet data.", + FAILED_TO_LOAD: "Failed to load data", + UNKNOWN_ERROR: "Unknown error", + VALIDATE: { + MISSING_TOKEN: "Please select a token", + AMOUNT_MUST_BE_NUMBER: "Amount must be a number", + AMOUNT_MUST_BE_POSITIVE: "Amount must be greater than 0", + CANNOT_SWAP_SAME_TOKEN: "Cannot swap the same token", + INSUFFICIENT_BALANCE: "Insufficient balance", + }, + SWAP: { + SUCCESS: "Swap successful!", + FAILED: "Swap failed!", + }, + CONTEXT: { + TOAST_PROVIDER_REQUIRED: "useToast must be used within ToastProvider", + EXCHANGE_MODAL_PROVIDER_REQUIRED: "useExchangeModal must be used within ExchangeModalProvider", + }, +}; diff --git a/src/problem2/src/common/helper.ts b/src/problem2/src/common/helper.ts new file mode 100644 index 000000000..52dd00fe7 --- /dev/null +++ b/src/problem2/src/common/helper.ts @@ -0,0 +1,24 @@ +import type { TokenPriceType } from "@types"; +import { TOKEN_ICON_BASE_URL } from "./constants"; + +// Helper function to get token icon URL +export const getTokenIcon = (symbol: string) => + `${TOKEN_ICON_BASE_URL}/${symbol}.svg`; + +export const getLatestPricesMap = ( + prices: TokenPriceType[], +): Record => { + const priceMap: Record = {}; + + prices.forEach((price) => { + const existing = priceMap[price.currency]; + if ( + !existing || + new Date(price.date).getTime() > new Date(existing.date).getTime() + ) { + priceMap[price.currency] = price; + } + }); + + return priceMap; +}; diff --git a/src/problem2/src/common/index.ts b/src/problem2/src/common/index.ts new file mode 100644 index 000000000..ba51124a1 --- /dev/null +++ b/src/problem2/src/common/index.ts @@ -0,0 +1,3 @@ +export * from "./constants"; +export * from "./helper"; +export * from "./configs"; diff --git a/src/problem2/src/components/app-header.tsx b/src/problem2/src/components/app-header.tsx new file mode 100644 index 000000000..cbc6bee18 --- /dev/null +++ b/src/problem2/src/components/app-header.tsx @@ -0,0 +1,44 @@ +import { Typography, Grid, Box, Button, styled } from "@mui/material"; +import { useExchangeModal } from "@contexts"; +import { useWallets } from "@api"; + +export const AppHeader = () => { + const { openModal } = useExchangeModal(); + + const { data: wallets } = useWallets(); + + return ( + + + + + My Wallet + + + ({wallets ? wallets.length : 0} currencies) + + + + + + + + ); +}; + +const AppHeaderStyled = styled(Box)(({ theme }) => ({ + position: "sticky", + top: 0, + zIndex: 1000, + padding: theme.spacing(2), + marginBottom: theme.spacing(3), + boxShadow: "0 2px 4px rgba(0,0,0,0.1)", + backgroundColor: theme.palette.background.paper, +})); diff --git a/src/problem2/src/components/exchange-token/exchange-form.tsx b/src/problem2/src/components/exchange-token/exchange-form.tsx new file mode 100644 index 000000000..0f28ec670 --- /dev/null +++ b/src/problem2/src/components/exchange-token/exchange-form.tsx @@ -0,0 +1,187 @@ +import { getLatestPricesMap } from "@common"; +import type { TokenPriceType } from "@types"; +import { useCallback, useEffect, useMemo } from "react"; +import type { useExchangeForm } from "./hooks"; +import { useExchangeModal } from "@contexts"; +import { + CommonAutocomplete, + CommonNumberInput, + TokenAvatar, + TokenOption, +} from "@atom"; +import SwapHorizIcon from "@mui/icons-material/SwapHoriz"; +import { + Box, + Button, + Chip, + Grid, + IconButton, + Stack, + Typography, +} from "@mui/material"; + +interface ExchangeFormProps { + prices: TokenPriceType[]; + formData: ReturnType; +} + +export const ExchangeForm = ({ prices, formData }: ExchangeFormProps) => { + const pricesMap = useMemo(() => getLatestPricesMap(prices), [prices]); + + const { isOpen, selectedCurrency } = useExchangeModal(); + + const { + fromToken, + toToken, + fromAmount, + toAmount, + formError, + handleAmountChange, + handleSubmit, + swapTokens, + handleAllToken, + handleTokenChange, + } = formData; + + const tokenOptions = Object.keys(pricesMap); + + const renderTokenOption = useCallback( + ( + props: React.HTMLAttributes & { key: string }, + option: string, + ) => { + const { key, ...rest } = props; + return ; + }, + [], + ); + + useEffect(() => { + // Set fromToken when modal opens with selectedCurrency + if (isOpen && selectedCurrency) { + handleTokenChange("fromToken", selectedCurrency); + } + // handleToken changed after fromToken is set, not in dependency array cause bug set from token wrongly + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isOpen, selectedCurrency]); + return ( + + + {/* From Section */} + + + + From{" "} + {fromToken && ( + + )} + + tkn !== toToken)} + renderOption={renderTokenOption} + onChange={(value) => handleTokenChange("fromToken", value)} + value={fromToken} + error={formError?.fromToken} + textFieldProps={{ + InputProps: { + startAdornment: fromToken && ( + + ), + }, + }} + /> + { + handleAmountChange("fromAmount", e.target.value ?? 0); + }} + error={!!formError?.fromAmount} + helperText={formError?.fromAmount} + value={fromAmount ?? ""} + slotProps={{ + htmlInput: { min: 0 }, + }} + /> + + + + {/* Swap Icon - Visual indicator only */} + + + + + + + {/* To Section */} + + + + To + + tkn !== fromToken)} + onChange={(value) => handleTokenChange("toToken", value)} + renderOption={renderTokenOption} + value={toToken} + error={formError?.toToken} + textFieldProps={{ + InputProps: { + startAdornment: toToken && , + }, + }} + /> + { + handleAmountChange("toAmount", e.target.value ?? 0); + }} + slotProps={{ + htmlInput: { min: 0 }, + }} + /> + + + + + + + ); +}; diff --git a/src/problem2/src/components/exchange-token/exchange-modal.tsx b/src/problem2/src/components/exchange-token/exchange-modal.tsx new file mode 100644 index 000000000..655d44fd4 --- /dev/null +++ b/src/problem2/src/components/exchange-token/exchange-modal.tsx @@ -0,0 +1,136 @@ +import { + Box, + styled, + Typography, + IconButton, + Modal, + CircularProgress, +} from "@mui/material"; +import CloseIcon from "@mui/icons-material/Close"; +import { type TokenPriceType } from "@types"; +import { useMemo, useEffect } from "react"; +import { getLatestPricesMap } from "@common"; +import { useExchangeForm } from "./hooks"; +import { useExchangeModal } from "@contexts"; +import { ExchangeForm } from "./exchange-form"; + +interface ExchangeModalProps { + prices: TokenPriceType[]; +} + +export const ExchangeModal = ({ prices }: ExchangeModalProps) => { + const pricesMap = useMemo(() => getLatestPricesMap(prices), [prices]); + const { isOpen, closeModal } = useExchangeModal(); + + const formSubmitCallback = () => { + closeModal(); + }; + + const exchangeForm = useExchangeForm(pricesMap, formSubmitCallback); + const { fromToken, isPending, resetForm, ballance } = exchangeForm; + + useEffect(() => { + // Reset form when modal is closed + if (!isOpen) { + resetForm(); + } + }, [isOpen, resetForm]); + + return ( + + + {isPending && ( + + + + )} + + + + + + + + Swap Tokens + + + {fromToken && + `Current ${fromToken} balance: ${ballance.toLocaleString( + undefined, + { + maximumFractionDigits: 6, + }, + )}`} + + + + + + ); +}; + +const ExchangeStyled = styled(Box)(({ theme }) => ({ + position: "absolute", + top: "50%", + left: "50%", + transform: "translate(-50%, -50%)", + width: "100%", + maxWidth: "800px", + maxHeight: "90vh", + backgroundColor: theme.palette.background.paper, + boxShadow: theme.shadows[24], + padding: theme.spacing(4), + borderRadius: theme.spacing(1), + display: "flex", + flexDirection: "column", + [theme.breakpoints.down("md")]: { + width: "100vw", + height: "100vh", + maxWidth: "none", + maxHeight: "none", + top: 0, + left: 0, + transform: "none", + borderRadius: 0, + padding: theme.spacing(4), + overflow: "auto", + }, +})); + +const CloseIconButton = styled(IconButton)(({ theme }) => ({ + position: "absolute", + right: theme.spacing(1), + top: theme.spacing(1), + color: theme.palette.grey[500], + zIndex: 1, + display: "flex", + [theme.breakpoints.up("md")]: { + display: "none", + }, +})); + +const ModalContainer = styled(Box)({ + display: "flex", + flexDirection: "column", + justifyContent: "center", + flex: 1, +}); + +const LoadingOverlay = styled(Box)(({ theme }) => ({ + position: "absolute", + inset: 0, + backgroundColor: "rgba(0, 0, 0, 0.5)", + zIndex: 10, + display: "flex", + alignItems: "center", + justifyContent: "center", + borderRadius: theme.spacing(1), + [theme.breakpoints.down("md")]: { + borderRadius: 0, + }, +})); diff --git a/src/problem2/src/components/exchange-token/hooks.ts b/src/problem2/src/components/exchange-token/hooks.ts new file mode 100644 index 000000000..ced010fb5 --- /dev/null +++ b/src/problem2/src/components/exchange-token/hooks.ts @@ -0,0 +1,230 @@ +import { walletService, useExchangeWallet } from "@api"; +import { useToast } from "@contexts"; +import { + exchangeSchema, + type ExchangeFormData, + type TokenPriceType, +} from "@types"; +import { ERROR_MESSAGES } from "@common"; +import { useCallback, useState } from "react"; + +type TokenForm = Partial>; +type AmountForm = { + fromAmount: string | number; + toAmount: string | number; +}; + +type FormError = Partial>; + +const tokenFormDefaultValue: TokenForm = { + fromToken: "", + toToken: "", +}; + +const amountFormDefaultValue: AmountForm = { + fromAmount: "", + toAmount: "", +}; + +const keyAmountExchange: Record = { + fromAmount: "toAmount", + toAmount: "fromAmount", +}; + +const keyTokenExchange: Record = { + fromToken: "toToken", + toToken: "fromToken", +}; +const errorsDefaultValue: FormError = {} as FormError; + +export const useExchangeForm = ( + prices: Record, + formCallback?: () => void, +) => { + const { mutate: exchangeWallet, isPending } = useExchangeWallet(); + const { showSuccess, showError } = useToast(); + + const [tokenForm, setTokenForm] = useState(tokenFormDefaultValue); + const [amountForm, setAmountForm] = useState( + amountFormDefaultValue, + ); + const [formError, setFormError] = useState( + errorsDefaultValue, + ); + + const { fromToken, toToken } = tokenForm; + const { fromAmount, toAmount } = amountForm; + const ballance = walletService.getBalance(tokenForm.fromToken || ""); + + const calculateAmount = useCallback( + (from: number, fromTkn: string, toTkn: string): number => { + const fromPrice = prices[fromTkn]; + const toPrice = prices[toTkn]; + if (!fromPrice || !toPrice || toPrice.price === 0 || from <= 0) return 0; + const priceRate = (fromPrice.price / toPrice.price) * 10e6; + return parseFloat(((from * Number(priceRate)) / 10e6).toFixed(6)); + }, + [prices], + ); + + const validateField = useCallback( + (field: keyof ExchangeFormData, value: string | number) => { + // Validate single field using field-level schema + const fieldSchema = exchangeSchema.shape[field]; + const result = fieldSchema.safeParse(value); + + const message = !result.success + ? result.error.issues[0].message + : undefined; + + // Clear error if valid + setFormError((prev) => ({ + ...prev, + [field]: message, + })); + return result.success; + }, + [], + ); + + const handleAmountChange = useCallback( + (field: keyof AmountForm, value: number | string) => { + const hasTokens = fromToken && toToken; + + validateField(field, Number(value)); + setAmountForm((prev) => { + if (!hasTokens) return { ...prev, [field]: value }; + const newAmount = calculateAmount(Number(value), fromToken, toToken); + validateField(keyAmountExchange[field], newAmount); + return { + ...prev, + [field]: value, + [keyAmountExchange[field]]: newAmount, + }; + }); + }, + [calculateAmount, fromToken, toToken, validateField], + ); + + const handleTokenChange = useCallback( + (field: keyof TokenForm, token?: string | null) => { + validateField(field, token ?? ""); + setTokenForm((prev: TokenForm) => { + const otherToken = prev[keyTokenExchange[field]]; + const fromToken = field === "fromToken" ? token : otherToken; + const toToken = field === "toToken" ? token : otherToken; + const newData = { + ...prev, + [field]: token ?? "", + }; + + setAmountForm((amtPrev) => { + const formNum = Number(amtPrev.fromAmount); + const willRecalculate = + fromToken && toToken && amtPrev.fromAmount && formNum > 0; + + if (!token) { + return { ...amtPrev, toAmount: 0 }; + } else if (willRecalculate) { + const newToAmount = calculateAmount(formNum, fromToken, toToken); + validateField("toAmount", newToAmount); + return { ...amtPrev, toAmount: newToAmount }; + } + return amtPrev; + }); + return newData; + }); + }, + [calculateAmount, validateField], + ); + + const swapTokens = useCallback(() => { + setTokenForm((prev) => ({ + fromToken: prev.toToken, + toToken: prev.fromToken, + })); + setAmountForm((prev) => ({ + fromAmount: prev.toAmount, + toAmount: prev.fromAmount, + })); + setFormError((prev) => ({ + fromToken: prev?.toToken, + toToken: prev?.fromToken, + fromAmount: prev?.toAmount, + toAmount: prev?.fromAmount, + })); + }, []); + + const handleAllToken = useCallback(() => { + handleAmountChange("fromAmount", ballance); + }, [ballance, handleAmountChange]); + + const resetForm = useCallback(() => { + setTokenForm(tokenFormDefaultValue); + setAmountForm(amountFormDefaultValue); + setFormError(undefined); + }, []); + + const validateForm = useCallback( + (data: Partial) => { + setFormError(undefined); + const result = exchangeSchema.safeParse(data); + if (!result.success) { + const errors: FormError = {} as FormError; + result.error.issues.forEach((issue) => { + const field = issue.path[0] as keyof ExchangeFormData; + errors[field] = issue.message; + }); + setFormError(errors); + return false; + } else if (Number(data.fromAmount) > ballance) { + const errors: FormError = {} as FormError; + errors.fromAmount = ERROR_MESSAGES.VALIDATE.INSUFFICIENT_BALANCE; + setFormError(errors); + return false; + } + return true; + }, + [ballance], + ); + + const handleSubmit = (data: Partial) => { + const result = validateForm(data); + if (!result) { + return; + } + exchangeWallet( + { + fromCurrency: data.fromToken || "", + toCurrency: data.toToken || "", + fromAmount: Number(data.fromAmount) || 0, + toAmount: Number(data.toAmount) || 0, + }, + { + onSuccess: () => { + showSuccess(ERROR_MESSAGES.SWAP.SUCCESS); + formCallback?.(); + }, + onError: (error: Error) => { + showError(error.message || ERROR_MESSAGES.SWAP.FAILED); + }, + }, + ); + }; + + return { + fromAmount, + toAmount, + fromToken, + toToken, + ballance, + isPending, + handleTokenChange, + resetForm, + handleSubmit, + formError, + swapTokens, + handleAllToken, + handleAmountChange, + }; +}; diff --git a/src/problem2/src/components/exchange-token/index.ts b/src/problem2/src/components/exchange-token/index.ts new file mode 100644 index 000000000..b8ec4972e --- /dev/null +++ b/src/problem2/src/components/exchange-token/index.ts @@ -0,0 +1 @@ +export * from "./exchange-modal"; \ No newline at end of file diff --git a/src/problem2/src/components/index.ts b/src/problem2/src/components/index.ts new file mode 100644 index 000000000..86caedab5 --- /dev/null +++ b/src/problem2/src/components/index.ts @@ -0,0 +1,3 @@ +export * from "./wallet-card"; +export * from "./exchange-token"; +export * from "./app-header"; diff --git a/src/problem2/src/components/wallet-card.tsx b/src/problem2/src/components/wallet-card.tsx new file mode 100644 index 000000000..311a83208 --- /dev/null +++ b/src/problem2/src/components/wallet-card.tsx @@ -0,0 +1,56 @@ +import { TokenAvatar } from "@atom"; +import { useExchangeModal } from "@contexts"; +import { + Box, + Button, + Card, + CardActions, + CardContent, + Typography, +} from "@mui/material"; +import React, { useMemo } from "react"; + +interface WalletCardProps { + currency: string; + amount: number; +} + +export const WalletCard = React.memo( + ({ currency, amount }: WalletCardProps) => { + const { openModal } = useExchangeModal(); + + const handleExchangeClick = () => { + openModal(currency); + }; + + const formattedAmount = useMemo( + () => + amount.toLocaleString(undefined, { + maximumFractionDigits: 6, + }), + [amount], + ); + + return ( + + + +   + {currency} + + + {`Your current balance in the wallet `} + + + {formattedAmount} {currency} + + + + + + + ); + }, +); diff --git a/src/problem2/src/contexts/exchange-modal/context-definition.ts b/src/problem2/src/contexts/exchange-modal/context-definition.ts new file mode 100644 index 000000000..605bf0e2a --- /dev/null +++ b/src/problem2/src/contexts/exchange-modal/context-definition.ts @@ -0,0 +1,12 @@ +import { createContext } from "react"; + +export interface ExchangeModalContextType { + isOpen: boolean; + selectedCurrency: string | null; + openModal: (currency?: string) => void; + closeModal: () => void; +} + +export const ExchangeModalContext = createContext< + ExchangeModalContextType | undefined +>(undefined); diff --git a/src/problem2/src/contexts/exchange-modal/context.tsx b/src/problem2/src/contexts/exchange-modal/context.tsx new file mode 100644 index 000000000..359466b1f --- /dev/null +++ b/src/problem2/src/contexts/exchange-modal/context.tsx @@ -0,0 +1,33 @@ +import React, { useState, useCallback } from "react"; +import { ExchangeModalContext } from "./context-definition"; + +interface ExchangeModalProviderProps { + children: React.ReactNode; +} + +export const ExchangeModalProvider = ({ + children, +}: ExchangeModalProviderProps) => { + const [isOpen, setIsOpen] = useState(false); + const [selectedCurrency, setSelectedCurrency] = useState(null); + + const openModal = useCallback((currency?: string) => { + setSelectedCurrency(currency || null); + setIsOpen(true); + }, []); + + const closeModal = useCallback(() => { + setIsOpen(false); + }, []); + + const value = React.useMemo( + () => ({ isOpen, selectedCurrency, openModal, closeModal }), + [isOpen, selectedCurrency, openModal, closeModal] + ); + + return ( + + {children} + + ); +}; diff --git a/src/problem2/src/contexts/exchange-modal/hook.ts b/src/problem2/src/contexts/exchange-modal/hook.ts new file mode 100644 index 000000000..910b60d66 --- /dev/null +++ b/src/problem2/src/contexts/exchange-modal/hook.ts @@ -0,0 +1,13 @@ +import { useContext } from "react"; +import { ExchangeModalContext } from "./context-definition"; +import { ERROR_MESSAGES } from "@common"; + +export const useExchangeModal = () => { + const context = useContext(ExchangeModalContext); + if (!context) { + throw new Error( + ERROR_MESSAGES.CONTEXT.EXCHANGE_MODAL_PROVIDER_REQUIRED, + ); + } + return context; +}; \ No newline at end of file diff --git a/src/problem2/src/contexts/exchange-modal/index.ts b/src/problem2/src/contexts/exchange-modal/index.ts new file mode 100644 index 000000000..6ef5c8e6e --- /dev/null +++ b/src/problem2/src/contexts/exchange-modal/index.ts @@ -0,0 +1,3 @@ +export * from "./context-definition"; +export * from "./context"; +export * from "./hook"; \ No newline at end of file diff --git a/src/problem2/src/contexts/index.ts b/src/problem2/src/contexts/index.ts new file mode 100644 index 000000000..360385cb5 --- /dev/null +++ b/src/problem2/src/contexts/index.ts @@ -0,0 +1,2 @@ +export * from "./exchange-modal"; +export * from "./toast"; diff --git a/src/problem2/src/contexts/toast/context-definition.ts b/src/problem2/src/contexts/toast/context-definition.ts new file mode 100644 index 000000000..1457bdbea --- /dev/null +++ b/src/problem2/src/contexts/toast/context-definition.ts @@ -0,0 +1,10 @@ +import { createContext } from "react"; + +export interface ToastContextType { + showSuccess: (message: string) => void; + showError: (message: string) => void; +} + +export const ToastContext = createContext( + undefined +); diff --git a/src/problem2/src/contexts/toast/context.tsx b/src/problem2/src/contexts/toast/context.tsx new file mode 100644 index 000000000..506774e98 --- /dev/null +++ b/src/problem2/src/contexts/toast/context.tsx @@ -0,0 +1,54 @@ +import { useState, type ReactNode } from "react"; +import { Snackbar, Alert, type AlertColor } from "@mui/material"; +import { ToastContext } from "./context-definition"; + +interface ToastProviderProps { + children: ReactNode; +} + +interface ToastState { + open: boolean; + message: string; + severity: AlertColor; +} + +export const ToastProvider = ({ children }: ToastProviderProps) => { + const [toast, setToast] = useState({ + open: false, + message: "", + severity: "success", + }); + + const showSuccess = (message: string) => { + setToast({ open: true, message, severity: "success" }); + }; + + const showError = (message: string) => { + setToast({ open: true, message, severity: "error" }); + }; + + const handleClose = () => { + setToast((prev) => ({ ...prev, open: false })); + }; + + return ( + + {children} + + + {toast.message} + + + + ); +}; diff --git a/src/problem2/src/contexts/toast/hook.ts b/src/problem2/src/contexts/toast/hook.ts new file mode 100644 index 000000000..032c79890 --- /dev/null +++ b/src/problem2/src/contexts/toast/hook.ts @@ -0,0 +1,11 @@ +import { useContext } from "react"; +import { ToastContext } from "./context-definition"; +import { ERROR_MESSAGES } from "@common"; + +export const useToast = () => { + const context = useContext(ToastContext); + if (!context) { + throw new Error(ERROR_MESSAGES.CONTEXT.TOAST_PROVIDER_REQUIRED); + } + return context; +}; diff --git a/src/problem2/src/contexts/toast/index.ts b/src/problem2/src/contexts/toast/index.ts new file mode 100644 index 000000000..543623633 --- /dev/null +++ b/src/problem2/src/contexts/toast/index.ts @@ -0,0 +1,3 @@ +export * from "./context-definition"; +export * from "./context"; +export * from "./hook"; diff --git a/src/problem2/src/main.tsx b/src/problem2/src/main.tsx new file mode 100644 index 000000000..a043f063f --- /dev/null +++ b/src/problem2/src/main.tsx @@ -0,0 +1,22 @@ +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import { ThemeProvider, CssBaseline } from "@mui/material"; +import App from "./App.tsx"; +import { QueryProvider } from "@api"; +import { theme } from "./theme"; +import { ExchangeModalProvider, ToastProvider } from "@contexts"; + +createRoot(document.getElementById("root")!).render( + + + + + + + + + + + + , +); diff --git a/src/problem2/src/theme.ts b/src/problem2/src/theme.ts new file mode 100644 index 000000000..03ad1730d --- /dev/null +++ b/src/problem2/src/theme.ts @@ -0,0 +1,37 @@ +import { createTheme } from "@mui/material/styles"; + +export const theme = createTheme({ + components: { + MuiCssBaseline: { + styleOverrides: { + "*": { + boxSizing: "border-box", + }, + "*::before": { + boxSizing: "border-box", + }, + "*::after": { + boxSizing: "border-box", + }, + }, + }, + MuiButton: { + styleOverrides: { + root: { + "&:focus": { + outline: "none", + }, + }, + }, + }, + MuiIconButton: { + styleOverrides: { + root: { + "&:focus": { + outline: "none", + }, + }, + }, + }, + }, +}); diff --git a/src/problem2/src/types/index.ts b/src/problem2/src/types/index.ts new file mode 100644 index 000000000..8c98bfce2 --- /dev/null +++ b/src/problem2/src/types/index.ts @@ -0,0 +1,2 @@ +export * from "./wallet.type"; +export * from "./schemas"; diff --git a/src/problem2/src/types/schemas/exchange-form.schema.ts b/src/problem2/src/types/schemas/exchange-form.schema.ts new file mode 100644 index 000000000..1530e706d --- /dev/null +++ b/src/problem2/src/types/schemas/exchange-form.schema.ts @@ -0,0 +1,20 @@ +import { z } from "zod"; +import { ERROR_MESSAGES } from "@common"; + +export const exchangeSchema = z + .object({ + fromToken: z.string().min(1, ERROR_MESSAGES.VALIDATE.MISSING_TOKEN), + fromAmount: z + .number({ message: ERROR_MESSAGES.VALIDATE.AMOUNT_MUST_BE_NUMBER }) + .positive(ERROR_MESSAGES.VALIDATE.AMOUNT_MUST_BE_POSITIVE), + toToken: z.string().min(1, ERROR_MESSAGES.VALIDATE.MISSING_TOKEN), + toAmount: z + .number({ message: ERROR_MESSAGES.VALIDATE.AMOUNT_MUST_BE_NUMBER }) + .positive(ERROR_MESSAGES.VALIDATE.AMOUNT_MUST_BE_POSITIVE), + }) + .refine((data) => !(!!data.toToken && data.fromToken === data.toToken), { + message: ERROR_MESSAGES.VALIDATE.CANNOT_SWAP_SAME_TOKEN, + path: ["toToken"], + }); + +export type ExchangeFormData = z.infer; diff --git a/src/problem2/src/types/schemas/index.ts b/src/problem2/src/types/schemas/index.ts new file mode 100644 index 000000000..6d13e90b9 --- /dev/null +++ b/src/problem2/src/types/schemas/index.ts @@ -0,0 +1 @@ +export * from "./exchange-form.schema"; diff --git a/src/problem2/src/types/wallet.type.ts b/src/problem2/src/types/wallet.type.ts new file mode 100644 index 000000000..690cae338 --- /dev/null +++ b/src/problem2/src/types/wallet.type.ts @@ -0,0 +1,16 @@ +export type TokenType = { + symbol: string; + name: string; +}; + +export type TokenPriceType = { + currency: string; + price: number; + date: string; +}; + + +export type WalletType = { + currency: string; + amount: number; +} \ No newline at end of file diff --git a/src/problem2/style.css b/src/problem2/style.css deleted file mode 100644 index 915af91c7..000000000 --- a/src/problem2/style.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - min-width: 360px; - font-family: Arial, Helvetica, sans-serif; -} diff --git a/src/problem2/tsconfig.app.json b/src/problem2/tsconfig.app.json new file mode 100644 index 000000000..dd3df10e1 --- /dev/null +++ b/src/problem2/tsconfig.app.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + /* Path Alias */ + "baseUrl": ".", + "paths": { + "@components": ["./src/components"], + "@components/*": ["./src/components/*"], + "@types": ["./src/types"], + "@types/*": ["./src/types/*"], + "@common": ["./src/common"], + "@common/*": ["./src/common/*"], + "@api": ["./src/api"], + "@api/*": ["./src/api/*"], + "@atom": ["./src/atom"], + "@atom/*": ["./src/atom/*"], + "@contexts": ["./src/contexts"], + "@contexts/*": ["./src/contexts/*"] + } + }, + "include": ["src"] +} diff --git a/src/problem2/tsconfig.json b/src/problem2/tsconfig.json new file mode 100644 index 000000000..1ffef600d --- /dev/null +++ b/src/problem2/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/src/problem2/tsconfig.node.json b/src/problem2/tsconfig.node.json new file mode 100644 index 000000000..8a67f62f4 --- /dev/null +++ b/src/problem2/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/src/problem2/vite.config.ts b/src/problem2/vite.config.ts new file mode 100644 index 000000000..08c44ecfb --- /dev/null +++ b/src/problem2/vite.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], + resolve: { + alias: { + "@components": "/src/components", + "@api": "/src/api", + "@types": "/src/types", + "@common": "/src/common", + "@atom": "/src/atom", + "@contexts": "/src/contexts", + }, + }, +}); diff --git a/src/problem3/.keep b/src/problem3/.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/problem3/messy-file.tsx b/src/problem3/messy-file.tsx new file mode 100644 index 000000000..cc735a951 --- /dev/null +++ b/src/problem3/messy-file.tsx @@ -0,0 +1,90 @@ +interface WalletBalance { + currency: string; + amount: number; +} +interface FormattedWalletBalance { + // Extends WalletBalance + currency: string; + amount: number; + formatted: string; +} + +interface Props extends BoxProps {} // extend without adding new property +const WalletPage: React.FC = (props: Props) => {// component never export + const { children, ...rest } = props; //missing classes destructure + const balances = useWalletBalances(); // assuming a hook to get wallet balances but should mapped with the interface - handle error + const prices = usePrices(); // assuming a hook to get prices - handel error + + const getPriority = (blockchain: any): number => { // use useCallback while using in another useMemo function or write outside component to avoid re create + // should not use any type in typescript, + switch ( + blockchain // return list of value can use object map (contain defined) + ) { + case "Osmosis": // define element as enum or constant + return 100; + case "Ethereum": + return 50; + case "Arbitrum": + return 30; + case "Zilliqa": + return 20; // same value can merge case + case "Neo": + return 20; + default: + return -99; + } + }; + + const sortedBalances = useMemo(() => { + // can simplify the filter and sort logic and produce hook to reuse + return balances + .filter((balance: WalletBalance) => { + const balancePriority = getPriority(balance.blockchain);// define but never use, type blockchain not in WalletBalance + if (lhsPriority > -99) {// wrong variable + // can contain in one if use and condition then return to sorten code + if (balance.amount <= 0) { // maybe wrong caclulation condition, negative amount is weird + return true; + } + } + return false; + }) + .sort((lhs: WalletBalance, rhs: WalletBalance) => { // can contain sort direction to change the order + // + const leftPriority = getPriority(lhs.blockchain);// missing the type definition of blockchain in WalletBalance + const rightPriority = getPriority(rhs.blockchain);//use many time for the get priority function + if (leftPriority > rightPriority) { + // can use return rightPriority - leftPriority to sort number directly + return -1; + } else if (rightPriority > leftPriority) { + return 1; + } + }); // missing return 0; + }, [balances, prices]); //get priority shouled be in dependency array, waite prices dependency + + const formattedBalances = sortedBalances.map((balance: WalletBalance) => {//can produce map at the same process with sortand filter, + // function never use + return { + ...balance, + formatted: balance.amount.toFixed(), //tofixed without parameter will return string with 0 decimal, should define the decimal point + }; + }); + + const rows = sortedBalances.map( // not cache and cause re render, if it contain many logic can create other component + // use wrong list should use formattedBalances + (balance: FormattedWalletBalance, index: number) => { + //wrong type with the sortedBalances + const usdValue = prices[balance.currency] * balance.amount; // can produce in map function and cache using use Memo - prices can be undefined risk + return ( + + ); + } + ); + + return
    {rows}
    ;// - empty state - +}; diff --git a/src/problem3/refactor-file.tsx b/src/problem3/refactor-file.tsx new file mode 100644 index 000000000..fdf5204eb --- /dev/null +++ b/src/problem3/refactor-file.tsx @@ -0,0 +1,110 @@ +import React, { useMemo } from "react"; +import { BoxProps, ClassesType } from "@types"; // assumption types folder +import { + WalletRow, + LoadingState, + ErrorState, + Box, + EmptyState, +} from "@components"; +import { useWalletBalances, usePrices } from "@apis"; + +const INVALID_PRIORITY = -99; + +enum BlockchainEnum { + OSMOSIS = "Osmosis", + ETHEREUM = "Ethereum", + ARBITRUM = "Arbitrum", + ZILLIQA = "Zilliqa", + NEO = "Neo", +} + +interface WalletBalance { + currency: string; + amount: number; + blockchain: BlockchainEnum; // define blockchain type +} + +interface WalletWithPriority extends WalletBalance { + priority: number; +} + +const blockchainPriorityMap: Record = { + [BlockchainEnum.OSMOSIS]: 100, + [BlockchainEnum.ETHEREUM]: 50, + [BlockchainEnum.ARBITRUM]: 30, + [BlockchainEnum.ZILLIQA]: 20, + [BlockchainEnum.NEO]: 20, +}; + +const getPriority = (blockchain: BlockchainEnum): number => { + //write outside component to avoid re create + return blockchainPriorityMap[blockchain] ?? INVALID_PRIORITY; +}; + +// Custom hook to filter and sort wallet balances +const useSortedWalletBalances = ( + balances: WalletBalance[] +): WalletWithPriority[] => { + // Map priority once, then filter/sort on the mapped value to avoid repeated lookup + return useMemo(() => { + return balances + .map((balance) => ({ + ...balance, + priority: getPriority(balance.blockchain), + })) + .filter( + (balance) => balance.priority > INVALID_PRIORITY && balance.amount > 0 + ) + .sort((lhs, rhs) => rhs.priority - lhs.priority); + }, [balances]); +}; + +interface Props extends BoxProps { + classes?: ClassesType; +} +export const WalletPage: React.FC = (props: Props) => { + const { classes, children: _children, ...rest } = props; + const { data: balances, loading, error } = useWalletBalances(); + const { + data: prices, + loading: pricesLoading, + error: pricesError, + } = usePrices(); + + // Handle loading state + if (loading || pricesLoading) return ; + + // Handle error state + if (error || pricesError || !prices || !balances) { + const errorMessage = + error?.message || pricesError?.message || "Data unavailable"; + return ; + } + + if (balances.length === 0) { + return ; + } + + const sortedBalances = useSortedWalletBalances(balances); + const rows = useMemo( + () => + sortedBalances.map((balance) => { + const usdValue = (prices[balance.currency] ?? 0) * balance.amount; + const formatted = balance.amount.toFixed(2); + return ( + + ); + }), + [sortedBalances, prices, classes?.row] + ); + + return {rows}; +}; + diff --git a/src/problem4/.keep b/src/problem4/.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/problem5/.keep b/src/problem5/.keep deleted file mode 100644 index e69de29bb..000000000 From 600d72309e36c69c091cf6ddfed21810d0f7ce76 Mon Sep 17 00:00:00 2001 From: James nguyen Date: Mon, 19 Jan 2026 22:39:12 +0700 Subject: [PATCH 2/4] update readme --- readme.md | 9 +++++---- src/problem2/src/components/app-header.tsx | 4 +++- src/problem3/messy-file.tsx | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index 943a69c73..b9202a722 100644 --- a/readme.md +++ b/readme.md @@ -16,11 +16,12 @@ Following the code challenge for the **Frontend Developer** position, I complete With the increasing adoption of AI tools in software development and the note from the instruction, I would like to be transparent about how AI assisted me during this challenge. -### Problem 1 – ~10% AI Assistance +### Problem 1 **[View problem solved](src/problem1/index.ts)** – ~10% AI Assistance AI was used mainly to generate and refine **code comments**. I used **GitHub Copilot**, which understood the context well and helped speed up the commenting process. The core logic and implementation were entirely my own. -### Problem 2 – ~60% AI Assistance +### Problem 2 **[View Problem Documentation](src/problem2/README.md)** – ~60% AI Assistance + AI played a more significant role in this part, particularly in: - Suggesting the **basic project structure** - Generating a **simple responsive layout using MUI** @@ -29,8 +30,8 @@ AI played a more significant role in this part, particularly in: However, for more complex aspects—such as **business logic, form handling, and state management**—AI assistance was limited and often resulted in errors that required manual debugging and rework. -### Problem 3 – ~20% AI Assistance -This was my favorite part of the challenge, as it closely reflects **real-world development scenarios**. +### Problem 3 **[View problem comment](src/problem3/messy-file.tsx)** – ~20% AI Assistance +This was my favorite part of the challenge, as it closely reflects **real-world development scenarios**. I jump on it right after finish the first problem. The problem required careful code reading, reasoning about existing behavior, and working through imperfect or messy implementations—something developers face daily. Approximately **80% of the ideas and solutions came from my own analysis**, 20% ai help me to validate my thoughts and give me some ideas i missed. diff --git a/src/problem2/src/components/app-header.tsx b/src/problem2/src/components/app-header.tsx index cbc6bee18..c964da265 100644 --- a/src/problem2/src/components/app-header.tsx +++ b/src/problem2/src/components/app-header.tsx @@ -20,7 +20,9 @@ export const AppHeader = () => { My Wallet - ({wallets ? wallets.length : 0} currencies) + {wallets && + wallets.length > 0 && + `(${wallets.length} ${wallets.length > 1 ? "currencies" : "currency"})`} diff --git a/src/problem3/messy-file.tsx b/src/problem3/messy-file.tsx index cc735a951..d044fd819 100644 --- a/src/problem3/messy-file.tsx +++ b/src/problem3/messy-file.tsx @@ -3,7 +3,7 @@ interface WalletBalance { amount: number; } interface FormattedWalletBalance { - // Extends WalletBalance + // can Extends WalletBalance currency: string; amount: number; formatted: string; From f6f806b7a19a2a66ee51fcd845891dc891482f17 Mon Sep 17 00:00:00 2001 From: jamesdev41-ui Date: Tue, 20 Jan 2026 10:56:25 +0700 Subject: [PATCH 3/4] Update readme.md --- readme.md | 39 +++++++-------------------------------- 1 file changed, 7 insertions(+), 32 deletions(-) diff --git a/readme.md b/readme.md index b9202a722..8c3926bc6 100644 --- a/readme.md +++ b/readme.md @@ -1,45 +1,20 @@ -# 99Tech Code Challenge #1 # - -Note that if you fork this repository, your responses may be publicly linked to this repo. -Please submit your application along with the solutions attached or linked. - -It is important that you minimally attempt the problems, even if you do not arrive at a working solution. - -## Submission ## -You can either provide a link to an online repository, attach the solution in your application, or whichever method you prefer. -We're cool as long as we can view your solution without any pain. - # James Nguyen Submission Following the code challenge for the **Frontend Developer** position, I completed **Problems 1, 2, and 3** located in the `src` directory. -## AI Assistance Disclosure - -With the increasing adoption of AI tools in software development and the note from the instruction, I would like to be transparent about how AI assisted me during this challenge. - -### Problem 1 **[View problem solved](src/problem1/index.ts)** – ~10% AI Assistance -AI was used mainly to generate and refine **code comments**. -I used **GitHub Copilot**, which understood the context well and helped speed up the commenting process. The core logic and implementation were entirely my own. - -### Problem 2 **[View Problem Documentation](src/problem2/README.md)** – ~60% AI Assistance - -AI played a more significant role in this part, particularly in: -- Suggesting the **basic project structure** -- Generating a **simple responsive layout using MUI** -- Recommending common **API paths, queries**, and general patterns -- Assisting with **helper utilities** such as formatting functions +### Problem 1 **[View problem solved](src/problem1/index.ts)** -However, for more complex aspects—such as **business logic, form handling, and state management**—AI assistance was limited and often resulted in errors that required manual debugging and rework. +### Problem 2 **[View Problem Documentation](src/problem2/README.md)** -### Problem 3 **[View problem comment](src/problem3/messy-file.tsx)** – ~20% AI Assistance -This was my favorite part of the challenge, as it closely reflects **real-world development scenarios**. I jump on it right after finish the first problem. +### Problem 3 **[View problem comment](src/problem3/messy-file.tsx)** +This was my favorite part of the challenge, as it closely reflects **real-world development scenarios**. I jump on it right after finishing the first problem. The problem required careful code reading, reasoning about existing behavior, and working through imperfect or messy implementations—something developers face daily. -Approximately **80% of the ideas and solutions came from my own analysis**, 20% ai help me to validate my thoughts and give me some ideas i missed. - Overall, I found this problem to be the most realistic and intellectually engaging part of the challenge. -## Final Note +## Final Note AI Assistance Disclosure + +With the increasing adoption of AI tools in software development and the note from the instruction, I would like to be transparent about how AI assisted me during this challenge. I view AI as a productivity tool rather than a replacement for engineering judgment. Throughout this challenge, my focus was on understanding the problem deeply, making deliberate technical decisions, and using AI selectively to accelerate—not replace—my thinking process. From 385d0aa90b4500d757da76de9b57f892373a93db Mon Sep 17 00:00:00 2001 From: jamesdev41-ui Date: Tue, 20 Jan 2026 11:03:33 +0700 Subject: [PATCH 4/4] Update readme.md --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 8c3926bc6..ab2ac5113 100644 --- a/readme.md +++ b/readme.md @@ -11,10 +11,10 @@ The problem required careful code reading, reasoning about existing behavior, an Overall, I found this problem to be the most realistic and intellectually engaging part of the challenge. - ## Final Note AI Assistance Disclosure -With the increasing adoption of AI tools in software development and the note from the instruction, I would like to be transparent about how AI assisted me during this challenge. +With the increasing adoption of AI tools in software development and based on the instruction, I would like to be transparent about how AI assisted me during this challenge. How I simply used AI in this project was that I first coded the initial part by myself, then used AI to help complete the line. However, if the generated code did not fit my idea or logic, I would not accept it and would adjust or rewrite it. + I view AI as a productivity tool rather than a replacement for engineering judgment. -Throughout this challenge, my focus was on understanding the problem deeply, making deliberate technical decisions, and using AI selectively to accelerate—not replace—my thinking process. +Throughout this challenge, my focus was on understanding the problem deeply, making technical decisions on my own, and using AI selectively to accelerate — not replace — my thinking process.